복습

첨부파일 업로드 위치

- 실제 업로드 되는 폴더 위치가 따로 있다

- 이클립스에 폴더를 만들어둬야 이 위치에 폴더가 생긴다

 

첨부파일 업로드 폼

- form 태그 안에 enctype="multipart/form-data" 속성이 있어야만 한다

- action 으로 지정된 페이지에서 실제 업로드를 진행한다

 

첨부파일 업로드

- MultipartRequest 객체를 생성하면 자동으로 업로드가 수행된다

- 객체를 생성하며 생성자에서 인코딩을 수행하므로 post 로 전달된 값이 있더라도 인코딩 할 필요 없다

- DefaultFileRenamePolicy 객체가 파일명뒤에 번호를 붙이며 중복문제를 해결해 준다

 

+ 첨부파일과 DB

- 직접 첨부파일을 저장할 수 있는 컬럼이 있다

- 일반적으로는 서버측의 폴더에 첨부파일이 저장되고 테이블에는 첨부파일명만 저장됨

 

+ 첨부파일과 스프링

- 스프링에서는 cos 외에 다른 라이브러리를 사용해서 첨부파일을 업로드할것


자료실 게시판 : 파일별 기능 및 구조 설명

- writeForm.jsp 에 첨부파일을 선택하는 양식이 포함되어있다

- writeForm.jsp는 자료실 기능을 가진 게시판 폼

 

자료실 게시판 : 글 작성 & 첨부파일 업로드

- 첨부파일을 업로드 가능한 글 작성 폼인 writeForm.jsp 파일 부터 작성하자

- writeForm.jsp

<%@ page contentType="text/html; charset=utf-8" %>
<%@ include file="color.jsp"%>

<html>
<head>
	<title>게시판</title>
	<link href="style.css" rel="stylesheet" type="text/css">
	<script src="http://code.jquery.com/jquery-latest.js"></script>
	<script src="check.js"></script>
</head>   

<body bgcolor="<%=bodyback_c%>">  
<center><b>글쓰기</b>
<br>
<form method="post" name="writeform" action="writePro.jsp" enctype="multipart/form-data">

<table width="430" border="1" cellspacing="0" cellpadding="0"  bgcolor="<%=bodyback_c%>" align="center">
   <tr>
    <td align="right" colspan="2" bgcolor="<%=value_c%>">
	    <a href="list.jsp"> 글목록</a> 
   </td>
   </tr>
   <tr>
    <td  width="100"  bgcolor="<%=value_c%>" align="center">이 름</td>
    <td  width="330">
       <input autofocus type="text" size="10" maxlength="10" id="writer" name="writer"></td>
  </tr>
  <tr>
    <td  width="100"  bgcolor="<%=value_c%>" align="center" >제 목</td>
    <td  width="330">    
       <input type="text" size="40" maxlength="50" id="subject" name="subject"></td>	
  </tr>
  <tr>
    <td  width="100"  bgcolor="<%=value_c%>" align="center">Email</td>
    <td  width="330">
       <input type="text" size="40" maxlength="30" id="email" name="email" ></td>
  </tr>
  <tr>
    <td  width="70"  bgcolor="<%=value_c%>" align="center">파일첨부</td>
    <td  width="330">
       <input type="file" size="40"  name="upload" ></td>
  </tr>
  <tr>
    <td  width="100"  bgcolor="<%=value_c%>" align="center" >내 용</td>
    <td  width="330" >
     <textarea id="content" name="content" rows="13" cols="40"></textarea> </td>
  </tr>
  <tr>
    <td  width="100"  bgcolor="<%=value_c%>" align="center" >비밀번호</td>
    <td  width="330" >
     <input type="password" size="8" maxlength="12" id="passwd" name="passwd"> 
	 </td>
  </tr>
<tr>      
 <td colspan=2 bgcolor="<%=value_c%>" align="center"> 
  <input type="submit" value="글쓰기" >  
  <input type="reset" value="다시작성">
  <input type="button" value="목록보기" OnClick="location.href='list.jsp'">
</td></tr></table>    
   
</form>      
</body>
</html>

- 폼을 통해 writePro.jsp 파일로 값들을 전달하고 있다

- 양식의 name 값들은 DTO 클래스의 프로퍼티명과 같고, 테이블 안 컬럼명과도 같다

 

첨부파일 양식 (writeForm.jsp 부분)

- 첨부파일은 input type = "file" 로 만들어야하고, name 값을 자세히 봐야 한다

 

폼을통해 첨부파일 전송 시 주의사항 (writeForm.jsp 부분)

1. method 가 post 방식이어야 한다

2. form 태그 안에 enctype="multipart/form-data" 가 있어야한다

 

 

- 다음은 action tag 로 지정된, 실제로 서버에 글을 작성하고 첨부파일을 업로드 하는 writePro.jsp 파일을 생성 및 작성하자

- writePro.jsp

<%@page import="upload.BoardDBBean"%>
<%@page import="upload.BoardDataBean"%>
<%@page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy"%>
<%@page import="com.oreilly.servlet.MultipartRequest"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	// 업로드할 디렉토리 위치 구하기
	String path = request.getRealPath("upload");
	System.out.println("path:" + path);
	
	// 첨부파일의 크기 설정(단위 : Byte) : 1MB
	int size = 1024 * 1024;
	
	// 첨부파일은 MultipartRequest 클래스로 객체를 생성하면서 업로드가 수행된다.
	MultipartRequest multi = 
		new MultipartRequest(request,
				path,	// 업로드 디렉토리 위치
				size,	// 첨부파일의 크기 : 1MB
				"utf-8",	// 인코딩 타입 설정
				new DefaultFileRenamePolicy());	// 중복 문제 해결
				
	String writer = multi.getParameter("writer");
	String subject = multi.getParameter("subject");
	String email = multi.getParameter("email");
	String content = multi.getParameter("content");
	String passwd = multi.getParameter("passwd");
	
	// 오리지널 파일명 : 클라이언트가 업로드한 파일명
	String upload0 = multi.getOriginalFileName("upload");
	
	// 실제 서버에 저장된 파일명
	String upload = multi.getFilesystemName("upload");
	
	BoardDataBean board = new BoardDataBean();
	board.setWriter(writer);
	board.setEmail(email);
	board.setSubject(subject);
	board.setContent(content);
	board.setPasswd(passwd);
	board.setIp(request.getRemoteAddr());	// 클라이언트의 IP 주소
	board.setUpload(upload);	// 첨부 파일명
	
	BoardDBBean dao = BoardDBBean.getInstance();
	int result = dao.insert(board);	// insert SQL문 실행
	
	if(result == 1) {
%>
		<script>
			alert("글 작성 성공");
			location.href = "list.jsp";
		</script>
<%	} else {%>
		<script>
			alert("글 작성 실패");
			history.go(-1);
		</script>
<%	}%>

- 첨부파일이 전송되면, 지금까지 쓰던 action tag 들로 쉽게 처리 불가

- MultipartRequest 객체를 생성하고, 그 객체로 getParameter() 메소드를 사용해서 나머지 값들을 받아야함

 

- 순서 잘 보기

1. 업로드할 디렉토리 위치 구하기 (writePro.jsp 부분)

	// 업로드할 디렉토리 위치 구하기
	String path = request.getRealPath("upload");
	System.out.println("path:" + path);

- 폴더명을 적어서 그 업로드될 디렉토리의 진짜 경로를 getRealPath() 로 구한다

- 업로드를 수행하게 되면 path 값이 콘솔창에 출력된다, 그 폴더로 들어가면 파일들이 있음

 

2. 첨부파일의 크기(단위: Byte) 설정 (writePro.jsp 부분)

	// 첨부파일의 크기 설정(단위 : Byte) : 1MB
	int size = 1024 * 1024;

- 1024 로 하면 1KB 가 되고 1024 * 1024 로 하면 1MB 가 됨, 현재는 1MB로 설정

- 이 범위 벗어나면 업로드 되지 않음

 

3. 첨부파일은 MultipartRequest 클래스로 객체를 생성하면서 업로드가 수행됨 (writePro.jsp 부분)

	// 첨부파일은 MultipartRequest 클래스로 객체를 생성하면서 업로드가 수행된다.
	MultipartRequest multi = 
		new MultipartRequest(request,
				path,	// 업로드 디렉토리 위치
				size,	// 첨부파일의 크기 : 1MB
				"utf-8",	// 인코딩 타입 설정
				new DefaultFileRenamePolicy());	// 중복 문제 해결

- 첫번째 매개변수는 request, 두번째 매개변수는 path, 세번째 매개변수는 size, 네번째 매개변수는 인코딩 타입

- 다섯번째 매개변수는 중복문제를 해결할 DefaultFileRenamePolicy 객체

- cos 라이브러리는 따로 첨부파일을 전송하는 코드는 없고, MultipartRequest 객체를 만들면 자동 업로드됨

- 여기서 인코딩을 처리하므로 이 파일 wirtePro.jsp 에서는 따로 인코딩 시켜주는 코드가 필요없다

 

+ import 정보 (writePro.jsp 부분)

<%@page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy"%>
<%@page import="com.oreilly.servlet.MultipartRequest"%>

 

4. 전달된 값 받기 (writePro.jsp 부분)

	String writer = multi.getParameter("writer");
	String subject = multi.getParameter("subject");
	String email = multi.getParameter("email");
	String content = multi.getParameter("content");
	String passwd = multi.getParameter("passwd");

- 이름, 제목, 내용 등을 받기 위해 기존에는 request.getParameter() 나 useBean, setProperty action tag 를 사용했다

- 첨부파일 전송이 포함되어있을때는 첨부파일 외의 값을 받을때 이 메소드나 액션태그들을 사용 불가

- MultipartRequest 클래스에 있는 메소드들은 MutlipartRequest 객체 메소드를 사용해야한다

ex) getParameter(), getFilesystemName(), getFileNames()

- MultipartRequest 클래스에 없는 메소드여야 request 객체의 메소드를 사용가능하다

ex) getRemoteAddr()

 

5. 두가지 파일명 구하기 (writePro.jsp 부분)

	// 오리지널 파일명 : 클라이언트가 업로드한 파일명
	String upload0 = multi.getOriginalFileName("upload");
	
	// 실제 서버에 저장된 파일명
	String upload = multi.getFilesystemName("upload");

- 실제 서버에 저장된 파일명과 사용자가 업로드한 오리지널 파일명이 다를 수 있다

- 중복이 발생된 경우에 두 파일명이 다르다, 두 파일명을 구해야함

- 매개변수에 작성하는 "upload" 는 첨부파일 업로드 양식의 name 값이다

 

6. DTO 객체 생성 및 값 설정 (writePro.jsp 부분)

	BoardDataBean board = new BoardDataBean();
	board.setWriter(writer);
	board.setEmail(email);
	board.setSubject(subject);
	board.setContent(content);
	board.setPasswd(passwd);
	board.setIp(request.getRemoteAddr());	// 클라이언트의 IP 주소
	board.setUpload(upload);	// 첨부 파일명

- 앞에서 모든 값들을 변수에 저장시켜뒀으니 DTO 객체 board를 생성해서 값을 넣어야한다

- useBean action tag, setProperty action tag 가 사용불가하므로, 직접 객체를 생성 후 setter 메소드로 값 설정

- ip 주소는 폼에서 넘어오지 않으므로 따로 구해서 저장한다

- 두가지 파일명이 있는데 파일명을 저장할 컬럼은 upload 하나의 컬럼이고, DTO 프로퍼티도 하나이다

- 두가지 파일명 중 하나를 선택해서 저장해야함

- 우리는 실제 서버에 저장된 파일명을 테이블의 upload 컬럼에 저장할것

 

7. DAO 객체 생성 후 DAO 의 메소드 사용 (writePro.jsp 부분)

	BoardDBBean dao = BoardDBBean.getInstance();
	int result = dao.insert(board);	// insert SQL문 실행

- DAO의 insert() 메소드를 사용한다

- 매개변수를 통해 insert 할 DTO 객체 board를 전달

 

8. insert 성공, 실패 처리 (writePro.jsp 부분)

	if(result == 1) {
%>
		<script>
			alert("글 작성 성공");
			location.href = "list.jsp";
		</script>
<%	} else {%>
		<script>
			alert("글 작성 실패");
			history.go(-1);
		</script>
<%	}%>

 

- 이제 DAO 클래스에서 insert() 메소드를 작성하자

 

DAO 클래스 글 작성 메소드 작성

- 전체 코드는 가장 마지막에 한번만

- DAO 클래스 BoardDBBean.java 에서 추가한 insert() 부분 코드만

	// 글 작성
	public int insert(BoardDataBean board) {
		int result = 0;
		
		Connection con = null;
		PreparedStatement pstmt = null;
		
		try {
			con = getConnection();
			
			String sql = "insert into upload values(upload_seq.nextval,?,?,?,?,";
			sql += "sysdate,?,?,?,?)";
			
			pstmt = con.prepareStatement(sql);
			
			pstmt.setString(1, board.getWriter());
			pstmt.setString(2, board.getEmail());
			pstmt.setString(3, board.getSubject());
			pstmt.setString(4, board.getPasswd());
			pstmt.setInt(5, board.getReadcount());	// readcount : 조회수
			pstmt.setString(6, board.getContent());
			pstmt.setString(7, board.getIp());
			pstmt.setString(8, board.getUpload());
			
			result = pstmt.executeUpdate();	// SQL문 실행

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(pstmt != null) try { pstmt.close(); } catch (Exception e) {}
			if(con != null) try { con.close(); } catch (Exception e) {}
		}
		return result;
	}

- 매개변수에 객체를 넘겨줌으로서 주솟값을 넘겨서 호출 Call By Reference

- JSP 파일에서 DAO 에 접근하기 위해서는 다른 패키지에 있으므로 클래스와 메소드가 public 이어야 가능

- 삽입 성공 데이터 개수를 돌려줄 것이므로 리턴자료형 int, 일반적으로 삽입은 1번만 가능하므로 1 반환

+ 기본자료형은 num 과 readcount 는 폼에서 넘어오지 않더라도 초기값이 0 으로 설정됨,

+ getReadCount() 로 0 을 불러오게됨, 직접 0 으로 설정해줘도 된다

 

- writeForm.jsp 에서 작성 및 첨부파일 업로드 하고 작성 시도

 

데이터 insert 확인

- sql 파일에서 확인해보면

- 데이터가 잘 insert 되었다

 

첨부파일 업로드 확인

- 콘솔창 확인해보면 path 값이 찍혀있다, 이 경로로 가보기

path:C:\Users\admin\eclipse-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\upload\upload

+ 앞의 upload 는 프로젝트명, 뒤의 upload 는 폴더명

- 탐색기에서 확인하면 첨부파일이 잘 업로드 되었음을 확인 가능하다

 

- 다음으로 list.jsp 를 구현해야함

 

자료실 게시판 : 목록 페이지 / 게시판 페이지

- list.jsp

<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.List"%>
<%@page import="upload.BoardDataBean"%>
<%@page import="upload.BoardDBBean"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%
	// 1. 한 화면에 출력할 데이터 갯수
	int page_size = 10;

	String pageNum = request.getParameter("page");
	if(pageNum == null){
		pageNum = "1";		// 1 page : 최근글이 보이는 페이지
	}
	
	// 2. 현재 페이지 번호
	int currentPage = Integer.parseInt(pageNum);
	
	// startRow : 각 page 데이터를 추출할 시작번호
	// endRow : 각 page 데이터를 추출할 끝번호
	// 1 page : startRow=1,  endRow=10
	// 2 page : startRow=11, endRow=20
	// 3 page : startRow=21, endRow=30
	int startRow = (currentPage - 1) * page_size + 1;
	int endRow = currentPage * page_size;
	
	// 3. 총 데이터 갯수
	int count = 0;
	
	BoardDBBean dao = BoardDBBean.getInstance();
	count = dao.getCount();
	System.out.println("count:"+count);
	
	List<BoardDataBean> list = null;
	if(count > 0){
		list = dao.getList(startRow, endRow);
	}
	System.out.println("list:"+list);
%>      
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<%
	if(count == 0){
%>
		작성된 글이 없습니다.
<%	}else{ %>
	
		<a href="writeForm.jsp">글작성</a> 글갯수 : <%=count %>
		<table border=1 width=700 align=center>
			<caption>게시판 목록</caption>
			<tr>
				<th>번호</th>
				<th>제목</th>
				<th>작성자</th>
				<th>작성일</th>
				<th>조회수</th>
				<th>IP주소</th>
			</tr>
<%
			// number : 각 페이지에 출력될 시작 번호
			int number = count - (currentPage-1) * page_size;

			SimpleDateFormat sd = 
					new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			
			for(int i=0; i<list.size(); i++){
				BoardDataBean board = list.get(i);
%>				
			<tr>
				<td><%=number-- %></td>
				<td>
				
<a href="content.jsp?num=<%=board.getNum()%>&page=<%=currentPage%>">				
				<%=board.getSubject() %>
</a>	
			
				</td>
				<td><%=board.getWriter() %></td>
				<td><%=sd.format(board.getReg_date()) %></td>
				<td><%=board.getReadcount() %></td>
				<td><%=board.getIp() %></td>
			</tr>			
				
<%			} // for end
%>
			
		</table>	
		
<%	} // else end
%>

<!-- 페이지 링크 설정 -->
<center>
<%
if(count > 0){
	
	// pageCount : 총페이지 수
	int pageCount=count/page_size + ((count%page_size==0) ? 0:1);
	System.out.println("pageCount:"+pageCount);
	
	// srartPage : 각 블럭의 시작 페이지 번호    1, 11, 21...
	// endPage : 각 블럭의 끝 페이지 번호         10, 20, 30...
	int startPage = ((currentPage-1)/10) * 10 + 1;
	int block = 10;	// 1개의 블럭의 크기 : 10개의 페이지로 구성
	int endPage = startPage + block - 1;
	
	// 가장 마지막 블럭에는 endPage값을 pageCount로 설정
	if(endPage > pageCount){
		endPage = pageCount;
	}
%>	
	<!-- 1페이지로 이동 -->
	<a href="list.jsp?page=1" style="text-decoration:none"> << </a>

<%
	// 이전 블럭으로 이동
	if(startPage > 10){
%>	
		<a href="list.jsp?page=<%=startPage-10%>">[이전]</a>	
<%	}	

	//각 블럭당 10개의 페이지 출력
	for(int i=startPage; i<=endPage; i++){
		if(i==currentPage){ 	// 현재 페이지	 %>
				[<%=i%>]
<% 		}else{ %>
				<a href="list.jsp?page=<%=i%>">[<%=i%>]</a>
<% 		}	
	} // for end

	// 다음 블럭으로 이동하는 부분
	if(endPage < pageCount){ %>
			<a href="list.jsp?page=<%=startPage+10%>">[다음]</a>		
<%	}  %>
	
	<!-- 마지막 페이지로 이동 -->
		<a href="list.jsp?page=<%=pageCount%>"
			style="text-decoration:none"> >> </a>			
<%	
}
%>
</center>

</body>
</html>

- 페이징 처리를 하고 있다, 페이징 처리 자세한 내용은 예전에 했다

https://laker99.tistory.com/116

https://laker99.tistory.com/117

 

- DAO 클래스에서 총 데이터 개수를 구해주는 메소드 getCount() 와 목록을 구해주는 메소드 getList() 를 구현해야함

 

DAO 클래스 총 데이터 개수 구하는 메소드 작성

- 전체 코드는 가장 마지막에 한번만

- DAO 클래스 BoardDBBean.java 에서 추가한 getCount() 부분 코드만

	// 총 데이터 갯수 구하기
	public int getCount() {
		int result = 0;
		
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			con = getConnection();
			
			String sql = "select count(*) from upload";
			
			pstmt = con.prepareStatement(sql);
			rs = pstmt.executeQuery();
			
			if(rs.next()) {
//				result = rs.getInt(1); 아래와 같음
				result = rs.getInt("count(*)");
			}
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			if(rs != null) try { rs.close(); } catch (Exception e) {}
			if(pstmt != null) try { pstmt.close(); } catch (Exception e) {}
			if(con != null) try { con.close(); } catch (Exception e) {}
		}
		return result;
	}

- 총 데이터 개수를 숫자로 돌려주므로 리턴자료형 int

- DB의 전체 데이터개수를 구해주는 메소드이므로 매개변수는 필요없다

- select sql 문을 사용해야하므로 결과를 돌려줄 ResultSet 객체 rs 가 필요

- 데이터가 1개이므로 if 문을 사용하고, rs.getInt(1) 또는 rs.getInt("count(*)") 로 데이터를 가져옴

 

DAO 클래스 목록을 자르고 목록을 구해주는 메소드 작성

- 전체 코드는 가장 마지막에 한번만

- DAO 클래스 BoardDBBean.java 에서 추가한 getList() 부분 코드만

	// 게시판 목록 : 데이터 10개 추출
	public List<BoardDataBean> getList(int start, int end) {
		List<BoardDataBean> list = new ArrayList<BoardDataBean>();
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			con = getConnection();
			
			String sql = "select * from (select rownum rnum, upload.* from *";
			sql += " (select * from upload order by num desc) upload)";
			sql += " where rnum >= ? and rnum <= ?";
			
			pstmt = con.prepareStatement(sql);
			pstmt.setInt(1, start);
			pstmt.setInt(2, end);
			
			rs = pstmt.executeQuery();	// SQL문 실행
			
			while(rs.next()) {
				BoardDataBean board = new BoardDataBean();
				
				board.setNum(rs.getInt("num"));
				board.setWriter(rs.getString("writer"));
				board.setEmail(rs.getString("email"));
				board.setSubject(rs.getString("subject"));
				board.setPasswd(rs.getString("passwd"));
				board.setReg_date(rs.getTimestamp("reg_date"));
				board.setReadcount(rs.getInt("readcount"));
				board.setContent(rs.getString("content"));
				board.setIp(rs.getString("ip"));
				board.setUpload(rs.getString("upload"));
				
				list.add(board);
			}
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			if(rs != null) try { rs.close(); } catch (Exception e) {}
			if(pstmt != null) try { pstmt.close(); } catch (Exception e) {}
			if(con != null) try { con.close(); } catch (Exception e) {}
		}
		return list;
	}

- 사용자가 1페이지 선택시 1 과 10 이 매개변수로 넘어온다, 매개변수는 int 두개

- 2개이상의 데이터를 검색하는 메소드의 리턴 자료형은 List

- List 객체를 생성하고 그 객체에 글들(데이터들)을 저장하고 그 List 를 반환할 것

- select sql 문을 사용해야하므로 결과를 돌려줄 ResultSet 객체 rs 가 필요

- 데이터를 여러개 검색하므로 while 문 안에서 rs.next() 로 컬럼별로 잘라서 데이터를 가져오게한다

- 하나의 데이터를 저장하기 위한 DTO 객체를 생성하고, setter 메소드로 rs 에서 가져온 값을 세팅한 후 그 DTO 객체를 list 안에 저장

<SQL문>

- 서브쿼리가 2개이다

- 두번째 서브 쿼리에서 최근글이 위로가도록 내림차순 정렬하고, 두번째 서브쿼리의 별칭을 upload 로 지정

- 첫번째 서브쿼리에 upload.* 를 사용해서 두번째 서브쿼리의 모든 컬럼을 사용

- 첫번째 서브쿼리에서 rownum 컬럼의 별칭을 rnum 으로 지정

- 바깥쪽 쿼리에서 rnum 의 범위를 지정

 

- list.jsp 를 실행해서 목록 페이지가 잘 구현되었는지 확인해보자

+ 화면에 출력되는 번호값은 num 컬럼과 관련 없다, 이 번호값은 파생된 변수

+ 나중에 갤러리 게시판 처럼 화면에 사진을 출력할 수도 있다

 

- 콘솔창 확인

- 총 데이터 개수를 의미하는 count 는 1

- list 안에 있는 DTO 객체, 즉 데이터의 주솟값이 출력되고있다

- 총 페이지수를 의미하는 pageCount 는 1

 

자료실 게시판 : 상세 페이지

- list.jsp 에서 상세페이지로 넘어가는 부분 코드

- 글 번호와 페이지 번호가 content.jsp 로 넘어간다

 

- 다음은 제목 링크를 클릭시 넘어가는 상세페이지 content.jsp 를 생성 및 작성하자

- content.jsp

<%@page import="java.text.SimpleDateFormat"%>
<%@page import="upload.BoardDataBean"%>
<%@page import="upload.BoardDBBean"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%
	int num = Integer.parseInt(request.getParameter("num"));
	String nowpage = request.getParameter("page");
	
	BoardDBBean dao = BoardDBBean.getInstance();
	
	// 조회수 1 증가 + 상세 정보 구하기
	BoardDataBean board = dao.updateContent(num);
	
	SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	String content = board.getContent().replace("\n","<br>");

%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상세 페이지</title>
</head>
<body>
<table border=1 width=500 align=center>
	<caption>상세 페이지</caption>
	<tr>
		<td>번호</td>
		<td><%=board.getNum() %></td>
		<td>조회수</td>
		<td><%=board.getReadcount() %></td>
	</tr>
	<tr>
		<td>작성자명</td>
		<td><%=board.getWriter() %></td>
		<td>작성일</td>
		<td><%=sd.format(board.getReg_date()) %></td>
	</tr>
	<tr>
		<td>제목</td>
		<td colspan=3><%=board.getSubject() %></td>
	</tr>
	<tr>
		<td>내용</td>
		<td colspan=3>
			<pre><%=board.getContent() %></pre>
			<%=content %>
		</td>
	</tr>
	<tr>
		<td>첨부파일<td>
		<td colspan=3>
			<!-- 첨부 파일이 있으면 -->
			<% if(board.getUpload() != null) {	%>
				<a href="file_down.jsp?file_name=<%=board.getUpload() %>">
					<%=board.getUpload() %>
				</a>	
			<% } %>
		</td>
	</tr>
	<tr>
		<td colspan=4 align=center>
			<input type="button" value="글수정"
			onClick="location.href='updateForm.jsp?num=<%=num%>&page=<%=nowpage%>'">
			<input type="button" value="글삭제"
			onClick="location.href='deleteForm.jsp?num=<%=num%>&page=<%=nowpage%>'">
			<input type="button" value="글목록"
			onClick="location.href='list.jsp?page=<%=nowpage%>'">
		</td>
	</tr>
</table>
</body>
</html>

- 일단 넘어온 글 번호 num 값과 페이지 번호 page 값을 받아야한다

- 글 번호 num 은 상세 정보를 구해올때 select sql 문에서 사용되어야하므로 바로 int 형으로 형변환한다

- 상세페이지에서 해야하는 일 : 조회수 1 증가 + 상세정보 구하기

- 조회수 1 증가 & 상세 정보 구하는 메소드 updateContent() 호출, 매개변수로 글번호 num 전달하고 1개 데이터 상세정보를 저장한 DTO 객체를 리턴받기

- 돌려받은 객체를 뿌려주고 있다

- SimpleDateFormat 객체, replace() 메소드 등 사용

- 마지막 버튼 3가지 중 '글수정' 과 '글삭제' 버튼에는 글번호 num 값과 페이지번호 page 값을 전달하고 있다

 

첨부파일 다운 (content.jsp 부분)

- 조건식을 써서 첨부파일이 있는 경우만 첨부파일명을 출력

- 첨부파일명을 클릭시 file_down.jsp 로 링크를 걸어서 이동하면서 파일명을 전달함

- 첨부파일명 좌우에 file_down.jsp 로의 링크를 걸어서 해당 첨부파일을 다운로드 가능하게함

 

DAO 클래스 조회수 1 증가 & 상세 정보 구하기 메소드 작성

- 전체 코드는 가장 마지막에 한번만

- DAO 클래스 BoardDBBean.java 에서 추가한 updateContent() 메소드 부분 코드만

	// 조회수 1 증가 + 상세 정보 구하기
	public BoardDataBean updateContent(int num) {
		BoardDataBean board = new BoardDataBean();
		
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			con = getConnection();
			
			String sql = "update upload set readcount = readcount + 1 ";
			sql += "where num = ?";
			pstmt = con.prepareStatement(sql);
			pstmt.setInt(1, num);
			pstmt.executeUpdate();
			
			sql = "select * from upload where num = ?";
			pstmt = con.prepareStatement(sql);
			pstmt.setInt(1, num);
			rs = pstmt.executeQuery();
			
			if(rs.next()) {
				board.setNum(rs.getInt("num"));
				board.setWriter(rs.getString("writer"));
				board.setEmail(rs.getString("email"));
				board.setSubject(rs.getString("subject"));
				board.setPasswd(rs.getString("passwd"));
				board.setReg_date(rs.getTimestamp("reg_date"));
				board.setReadcount(rs.getInt("readcount"));
				board.setContent(rs.getString("content"));
				board.setIp(rs.getString("ip"));
				board.setUpload(rs.getString("upload"));
			}
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			if(rs != null) try { rs.close(); } catch (Exception e) {}
			if(pstmt != null) try { pstmt.close(); } catch (Exception e) {}
			if(con != null) try { con.close(); } catch (Exception e) {}
		}
		return board;
	}

- 1개 데이터의 상세정보를 리턴하므로 리턴자료형은 DTO

- 글 번호 num 을 넘겨받아야하므로 매개변수 자료형은 int

- 조회수 1 증가시에는 update 문, 상세 정보 구하기 에는 select 문 사용

 

- 확인하기 위해 목록페이지 list.jsp 로 가서 글 제목을 클릭해서 상세페이지 content.jsp 로 가보자

- 파일명 링크 클릭시 다운로드가 진행됨

- 글수정을 누르면 updateForm.jsp 파일로, 글삭제는 deleteForm.jsp 파일로, 글목록은 list.jsp 파일로 이동

 

자료실 게시판 : 글 수정

- 다음은 글 수정을 하는 수정 폼 updateForm.jsp 를 생성 및 작성하자

- updateForm.jsp

<%@page import="upload.BoardDataBean"%>
<%@page import="upload.BoardDBBean"%>
<%@ page contentType="text/html; charset=utf-8" %>
<%@ include file="color.jsp"%>

<%
	int num = Integer.parseInt(request.getParameter("num"));
	String nowpage = request.getParameter("page");
	
	BoardDBBean dao = BoardDBBean.getInstance();
	
	// 상세 정보 구하기
	BoardDataBean board = dao.getContent(num);
%>

<html>
<head>
	<title>게시판</title>
	<link href="style.css" rel="stylesheet" type="text/css">
	<script src="http://code.jquery.com/jquery-latest.js"></script>
	<script src="check.js"></script>
</head>   

<body bgcolor="<%=bodyback_c%>">  
<center><b>글수정</b>
<br>
<form method="post" name="writeform" action="updatePro.jsp" enctype="multipart/form-data">
<input type="hidden" name="num" value="<%=num %>">
<input type="hidden" name="page" value="<%=nowpage %>">
<table width="430" border="1" cellspacing="0" cellpadding="0"  bgcolor="<%=bodyback_c%>" align="center">
   <tr>
    <td align="right" colspan="2" bgcolor="<%=value_c%>">
	    <a href="list.jsp?page=<%=nowpage%>"> 글목록</a> 
   </td>
   </tr>
   <tr>
    <td  width="100"  bgcolor="<%=value_c%>" align="center">이 름</td>
    <td  width="330">
       <input autofocus type="text" size="10" maxlength="10" 
       id="writer" name="writer" value="<%=board.getWriter()%>"></td>
  </tr>
  <tr>
    <td  width="100"  bgcolor="<%=value_c%>" align="center" >제 목</td>
    <td  width="330">    
       <input type="text" size="40" maxlength="50" 
       id="subject" name="subject" value="<%=board.getSubject()%>"></td>	
  </tr>
  <tr>
    <td  width="100"  bgcolor="<%=value_c%>" align="center">Email</td>
    <td  width="330">
       <input type="text" size="40" maxlength="30" 
       id="email" name="email" value="<%=board.getEmail()%>"></td>
  </tr>
  <tr>
    <td  width="70"  bgcolor="<%=value_c%>" align="center">파일첨부</td>
    <td  width="330">
       <input type="file" size="40"  name="upload" >
       <%=board.getUpload() %>
     </td>
  </tr>
  <tr>
    <td  width="100"  bgcolor="<%=value_c%>" align="center" >내 용</td>
    <td  width="330" >
     <textarea id="content" name="content" rows="13" cols="40"><%=board.getContent() %></textarea> 
     </td>
  </tr>
  <tr>
    <td  width="100"  bgcolor="<%=value_c%>" align="center" >비밀번호</td>
    <td  width="330" >
     <input type="password" size="8" maxlength="12" id="passwd" name="passwd"> 
	 </td>
  </tr>
<tr>      
	<td colspan=2 bgcolor="<%=value_c%>" align="center"> 
  		<input type="submit" value="글수정" >  
  		<input type="reset" value="다시작성">
  		<input type="button" value="목록보기" OnClick="location.href='list.jsp?page=<%=nowpage%>'">
	</td>
</tr>
</table>    
</form>      
</body>
</html>

- writeForm.jsp 내용을 복붙하고 수정

- 앞에서 get 방식으로 넘어온 num 과 page 값을 받아서 변수에 저장

- 수정폼에 정보를 뿌려줘야하므로 DB 연동을 위해 DAO 객체 생성

- 상세정보를 구해오는 역할만을 하는 getContent() 메소드 호출

+ 조회수 1 증가 + 상세 정보 구하기 메소드는 updateContent() 였다

- 구해온 상세정보를 value 속성 등으로 뿌려주고 있다, 첨부파일은 첨부파일 내용을 옆에 출력하고 있음

- list.jsp 로 이동하는 경우에는 ?page=<%=nowpage%> 를 붙이므로서 원래 페이지로 돌아가도록 함

- 첨부파일도 수정할 수 있도록하기위해 enctype="multipart/form-data" 가 form 태그 안에 있어야한다

- 위에서 받은 name 과 page 를 form 태그에서 hidden 객체로 updatePro.jsp 로 전달한다

- num 과 page 는 list.jsp -> content.jsp -> updateForm.jsp -> updatePro.jsp 로 3번 넘어가고 있다

 

- DAO 클래스에서 getContent() 메소드 작성

 

첨부파일 수정시  주의

- 사용자가 첨부파일을 수정할 수도, 수정하지 않을 수도 있다

- 수정을 하면 update 문을 수행할때 첨부파일명이 변경된다

- 수정을 하지 않으면 null 값이 들어가면서 테이블의 upload 컬럼에 있는 기존의 첨부파일명이 지워진다

- 이 문제를 첨부파일을 수정하는 경우, 수정하지 않는경우로 updatePro.jsp 에서 나중에 처리해야한다

 

DAO 클래스 상세 정보 구하기 메소드 작성

- 전체 코드는 가장 마지막에 한번만

- DAO 클래스 BoardDBBean.java 에서 추가한 getContent() 메소드 부분 코드만

	// 수정폼 : 상세 정보 구하기
	public BoardDataBean getContent(int num) {
		
		BoardDataBean board = new BoardDataBean();
		
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			con = getConnection();
			
			String sql = "select * from upload where num = ?";
			
			pstmt = con.prepareStatement(sql);
			pstmt.setInt(1, num);
			rs = pstmt.executeQuery();	// SQL문 실행
			
			if(rs.next()) {
				board.setNum(rs.getInt("num"));
				board.setWriter(rs.getString("writer"));
				board.setEmail(rs.getString("email"));
				board.setSubject(rs.getString("subject"));
				board.setPasswd(rs.getString("passwd"));
				board.setReg_date(rs.getTimestamp("reg_date"));
				board.setReadcount(rs.getInt("readcount"));
				board.setContent(rs.getString("content"));
				board.setIp(rs.getString("ip"));
				board.setUpload(rs.getString("upload"));
			}
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			if(rs != null) try { rs.close(); } catch (Exception e) {}
			if(pstmt != null) try { pstmt.close(); } catch (Exception e) {}
			if(con != null) try { con.close(); } catch (Exception e) {}
		}
		return board;
	}

- 1개 데이터 상세정보를 구해오므로 리턴 자료형은 DTO, 매개변수는 글번호를 받아야하므로 자료형이 int

- updateContent() 메소드를 복붙해서 조회수 증가 부분만 지우기

 

- 목록페이지에서 글을 선택해서 상세페이지로 오고 거기서 '글수정' 을 눌렀을때 나오는 수정폼 확인

 

- '글수정' 을 누르면 updatePro.jsp 에서 사용자가 입력한 비밀번호가 맞는 비밀번호인지 확인 후 수정을 실행한다

- updatePro.jsp 파일을 생성 및 작성하자

- updatePro.jsp

<%@page import="upload.BoardDBBean"%>
<%@page import="upload.BoardDataBean"%>
<%@page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy"%>
<%@page import="com.oreilly.servlet.MultipartRequest"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	// 업로드할 디렉토리 위치 구하기
	String path = request.getRealPath("upload");
	System.out.println("path:" + path);
	
	// 첨부파일의 크기 설정(단위 : Byte) : 1MB
	int size = 1024 * 1024;
	
	// 첨부파일은 MultipartRequest 클래스로 객체를 생성하면서 업로드가 수행된다.
	MultipartRequest multi = 
		new MultipartRequest(request,
				path,	// 업로드 디렉토리 위치
				size,	// 첨부파일의 크기 : 1MB
				"utf-8",	// 인코딩 타입 설정
				new DefaultFileRenamePolicy());	// 중복 문제 해결
	
	int num = Integer.parseInt(multi.getParameter("num"));
	String nowpage = multi.getParameter("page");
				
	String writer = multi.getParameter("writer");
	String subject = multi.getParameter("subject");
	String email = multi.getParameter("email");
	String content = multi.getParameter("content");
	String passwd = multi.getParameter("passwd");
	
	// 오리지널 파일명 : 클라이언트가 업로드한 파일명
	String upload0 = multi.getOriginalFileName("upload");
	
	// 실제 서버에 저장된 파일명
	String upload = multi.getFilesystemName("upload");
	
	BoardDataBean board = new BoardDataBean();
	board.setNum(num);
	board.setWriter(writer);
	board.setEmail(email);
	board.setSubject(subject);
	board.setContent(content);
	board.setPasswd(passwd);
	board.setIp(request.getRemoteAddr());	// 클라이언트의 IP 주소
//	board.setUpload(upload);	// 첨부파일을 수정하지 않으면 null값이 저장된다.
	
	BoardDBBean dao = BoardDBBean.getInstance();
	BoardDataBean old = dao.getContent(num); // DB에서 상세정보 가져옴
	
	if(upload != null) {	// 첨부 파일을 수정한 경우
		board.setUpload(upload);
	} else {	// 첨부 파일을 수정하지 않은 경우
		board.setUpload(old.getUpload());
	}

	// 비번 비교
	if(old.getPasswd().equals(passwd)){	// 비번 일치시
		int result = dao.update(board);	// update SQL문 실행
		
		if(result == 1) {
%>
		<script>
			alert("글 수정 성공");
			location.href="list.jsp?page=<%=nowpage%>";
		</script>
<%		}
	} else {%>
		<script>
			alert("비번이 일치하지 않습니다.");
			history.go(-1);
		</script>
<%	}%>

- writePro.jsp 의 내용을 복붙 후 수정

- writeForm.jsp 에서 hidden 으로 넘어온 글 번호 num 과 페이지 번호 page 값을 multi.getParamter() 받아서 변수에 저장

- hidden 으로 넘어온 이 값들도 request 객체가 아닌 MultipartRequest 객체 multi.getParameter() 로 값을 전달받아야한다

- useBean action tag 가 사용불가능하므로 DTO 객체를 직접 만들어서 setter 메소드로 값을 설정함

- 그리고 hidden 으로 넘어온 num 을 DTO 객체 board 에 세팅

- 수정폼에서 넘어온 비밀번호와 DB에서 가져온 비밀번호가 일치해야한다

- 비번 일치시 DAO 의 update() 를 호출하여 update sql 을 실행함

+ 페이지번호를 3번째 가져왔으므로 수정 성공시 list.jsp 로 돌아갈때 원래 페이지로 돌아갈 수 있다

 

첨부파일 수정 처리 (updatePro.jsp 부분)

	BoardDataBean old = dao.getContent(num); // DB에서 상세정보 가져옴
	
	if(upload != null) {	// 첨부 파일을 수정한 경우
		board.setUpload(upload);
	} else {	// 첨부 파일을 수정하지 않은 경우
		board.setUpload(old.getUpload());
	}

- 두 경우를 나눠서 처리해야함

- updateForm.jsp 에서 넘어온 upload 가 null 이면 첨부파일을 선택하지 않은 경우이다

1. 첨부파일을 선택한 경우

- 수정폼에서 첨부파일을 선택하면 문제 없이 setUpload(upload) 되어 수정됨

2. 첨부파일을 선택하지 않은 경우

- 수정폼에서 첨부파일을 선택하지 않으면 upload 가 null 이 되어 setUpload(upload) 시 null 값이 들어감

- 수정폼에서 첨부파일을 선택하지 않으면 원래 파일명 그대로 들어가도록 해야함

- DB 에서 가져온 상세정보인 DTO 객체 old 에서 old.getUpload() 해서 원래의 파일명을 가져와서 객체 board 에 세팅

 

- DAO 클래스에서 실제로 수정을 해주는 update() 메소드를 작성하자

 

DAO 클래스 글 수정 + 첨부파일 수정 메소드 작성

- 전체 코드는 가장 마지막에 한번만

- DAO 클래스 BoardDBBean.java 에서 추가한 update() 부분 코드만

	// 글 수정
	public int update(BoardDataBean board) {
		
		int result = 0;
		Connection con = null;
		PreparedStatement pstmt = null;
		
		try {
			con = getConnection();
			
			String sql = "update upload set writer=?,email=?,subject=?,";
			sql += "content=?,ip=?,upload=? where num=?";
			
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, board.getWriter());
			pstmt.setString(2, board.getEmail());
			pstmt.setString(3, board.getSubject());
			pstmt.setString(4, board.getContent());
			pstmt.setString(5, board.getIp());
			pstmt.setString(6, board.getUpload());
			pstmt.setInt(7, board.getNum());
			
			result = pstmt.executeUpdate();	// SQL문 실행
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			if(pstmt != null) try { pstmt.close(); } catch (Exception e) {}
			if(con != null) try { con.close(); } catch (Exception e) {}
		}
		return result;
	}

- updatePro.jsp 에서 첨부파일이 없는경우 기존 첨부파일명을 board 객체에 넣었으므로 여기선 자유롭게 board.getUpload() 로 값을 세팅하면 된다

- ip 주소는 수정할 필요 없지만 updatePro.jsp 에서 ip 주소도 새로 구해서 board 객체에 넣었으므로 새로 세팅

 

- 수정 기능을 확인하기 위해 목록페이지->상세페이지->수정폼에서 수정해보자

- 첨부파일을 수정하지 않았을때

- 첨부파일을 수정하지 않으면 기존 파일이 그대로 나옴

 

 첨부파일을 수정했을때

- 첨부파일이 수정되었다

 

- 다음은 삭제 기능을 구현하자

 

자료실 게시판 : 글 삭제 & 첨부파일 삭제

- 상세 페이지인 content.jsp 파일에서 '글삭제' 버튼 클릭시 deleteForm.jsp 파일로 넘어간다

- 글번호인 num 과 페이지번호인 page 값이 전달된다

- list.jsp -> content.jsp -> deleteForm.jsp 로 넘어온 값들이다

 

- 먼저 삭제폼 deleteForm.jsp 파일 생성 후 작성

-deleteForm.jsp

<%@page import="upload.BoardDataBean"%>
<%@page import="upload.BoardDBBean"%>
<%@ page contentType="text/html; charset=utf-8" %>
<%@ include file="color.jsp"%>

<%
	int num = Integer.parseInt(request.getParameter("num"));
	String nowpage = request.getParameter("page");
%>

<html>
<head>
	<title>게시판</title>
	<link href="style.css" rel="stylesheet" type="text/css">
	<script src="http://code.jquery.com/jquery-latest.js"></script>
	<script src="check.js"></script>
</head>   

<body bgcolor="<%=bodyback_c%>">  
<center><b>글삭제</b>
<br>
<form method="post" name="writeform" action="deletePro.jsp">
<input type="hidden" name="num" value="<%=num %>">
<input type="hidden" name="page" value="<%=nowpage %>">
<table width="430" border="1" cellspacing="0" cellpadding="0"  bgcolor="<%=bodyback_c%>" align="center">
   <tr>
    <td align="right" colspan="2" bgcolor="<%=value_c%>">
	    <a href="list.jsp?page=<%=nowpage%>"> 글목록</a> 
   </td>
   </tr>
  <tr>
    <td  width="100"  bgcolor="<%=value_c%>" align="center" >비밀번호</td>
    <td  width="330" >
     <input type="password" size="8" maxlength="12" id="passwd" name="passwd"> 
	 </td>
  </tr>
<tr>      
	<td colspan=2 bgcolor="<%=value_c%>" align="center"> 
  		<input type="submit" value="글삭제" >  
  		<input type="reset" value="다시작성">
  		<input type="button" value="목록보기" OnClick="location.href='list.jsp?page=<%=nowpage%>'">
	</td>
</tr>
</table>    
</form>      
</body>
</html>

- updateForm.jsp 파일 내용 복붙 후 수정, 비밀번호 입력양식 외 입력양식 삭제

- deleteForm.jsp 에서는 DB 연동이 필요없으므로 updateForm.jsp의 DB 연동 코드 삭제

- 삭제폼에서는 첨부파일이 전달되지 않기때문에 enctype="multipart/form-data" 를 지워야한다!

- 지우지 않으면 다른 값들 전달에 문제가 생기므로 반드시 지워야함

- num 과 page 값은 3번째 deletePro.jsp 로 또다시 넘어간다

- 폼을 통해서 num, page 가 hidden 으로 넘어가고, 사용자가 입력한 비번 passwd 가 deletePro.jsp로 넘어간다, 총 3개가 넘어감

 

- 다음으로는 deletePro.jsp 파일을 생성 및 작성

- deletePro.jsp

<%@page import="upload.BoardDataBean"%>
<%@page import="upload.BoardDBBean"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	request.setCharacterEncoding("utf-8");
%>

<jsp:useBean id="board" class="upload.BoardDataBean"/>
<jsp:setProperty property="*" name ="board"/>

<%
	String nowpage = request.getParameter("page");

	String path = request.getRealPath("upload");
	System.out.println("path:" + path);
	
	BoardDBBean dao = BoardDBBean.getInstance();
	BoardDataBean old = dao.getContent(board.getNum());
	
	// 비번 비교
	if(old.getPasswd().equals(board.getPasswd())) {	// 비번 일치시
		int result = dao.delete(old, path);	// 글 삭제, 첨부파일 삭제
%>
		<script>
			alert("글 삭제 성공");
			location.href="list.jsp?page<%=nowpage%>";
		</script>
		
<%	} else {	// 비번 불일치시 %>
		<script>
			alert("비번이 일치하지 않습니다");
			history.go(-1);
		</script>
<%	}%>

- 한글값이 post 로 넘어올 수 있으므로 한글값 인코딩

- 현재는 첨부파일이 넘어오지 않으므로 useBean action tag, setProperty action tag, request.getParameter() 사용 가능

- 넘어온 값 3개 중에 page 는 DTO 프로퍼티에 없으므로 따로 변수를 만들어서 값을 저장

- 글을 삭제하면 첨부파일도 같이 지워야한다, 지우지 않으면 서버측에 계속 저장되어 공간 차지

- 비번을 비교하기 위해 이전에 구현한 DAO의 getContent() 메소드 호출해서 상세정보를 DTO 객체 old 에 저장

- 해당 글의 상세정보를 저장하는 객체 old를 delete() 메소드의 첫번째 매개변수로 넘긴다

- 글번호만 필요하다면 board 객체를 전달해도 되지만 첨부파일명 또한 구해야할 일이 있으므로 객체 old 를 넘김

 

첨부파일 지우기

- JAVA의 File 클래스 관련 내용을 써야함

- 디렉토리 'upload' 의 절대 경로값을 request.getRealPath() 로 구해서 path 변수에 저장한다

-  path 변수를 DAO의 delete() 메소드의 두번째 매개변수로 넘긴다

 

- 이제 DAO 클래스에서 글 삭제 와 첨부파일 삭제 메소드인 delete() 메소드를 작성하자

 

DAO 클래스 글 삭제 & 첨부파일 삭제 메소드 작성

- 전체 코드는 가장 마지막에 한번만

- DAO 클래스 BoardDBBean.java 에서 추가한 delete() 부분 코드만

	// 글 삭제
	public int delete(BoardDataBean board, String path) {
		
		int result = 0;
		Connection con = null;
		PreparedStatement pstmt = null;
		
		try {
			con = getConnection();
			
			String sql = "delete from upload where num=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setInt(1, board.getNum());
			result = pstmt.executeUpdate();
			
			if(board.getUpload() != null) {	// 첨부 파일이 있으면
				File file = new File(path);
				
				// upload 디렉토리의 모든 파일을 읽어온다.
				File[] f = file.listFiles();
				
				for(int i=0; i<f.length; i++) {
					
					// upload 디렉토리에 저장된 파일 중에서 db에 저장된 파일을 삭제한다.
					if(f[i].getName().equals(board.getUpload())) {
						f[i].delete();	// 첨부 파일 삭제
					}
				}
			}
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			if(pstmt != null) try { pstmt.close(); } catch (Exception e) {}
			if(con != null) try { con.close(); } catch (Exception e) {}
		}
		return result;
	}

- 매개변수가 2개이다, 첫번째로는 삭제할 글의 정보인 DTO 객체 board, 두번째로는 첨부파일 저장되는 실제 경로인 path

- 삭제폼에서 hidden 으로 넘어온 num 값을 board.getNum() 으로 가져와서 해당 글을 삭제

- 글 삭제 후 첨부파일을 삭제해야 한다.

 

첨부파일 삭제 (BoardDBBean.java 의 delete() 중 부분)

			if(board.getUpload() != null) {	// 첨부 파일이 있으면
				File file = new File(path);
				
				// upload 디렉토리의 모든 파일을 읽어온다.
				File[] f = file.listFiles();
				
				for(int i=0; i<f.length; i++) {
					
					// upload 디렉토리에 저장된 파일 중에서 db에 저장된 파일을 삭제한다.
					if(f[i].getName().equals(board.getUpload())) {
						f[i].delete();	// 첨부 파일 삭제
					}
				}
* 관련 내용 수업 : https://laker99.tistory.com/48
* 관련 내용 과제 : https://laker99.tistory.com/39 (검색어 : 1. 디렉토리 삭제)
- 비어있는 폴더는 잘 지워졌지만 비어있지 않은 폴더는 지워지지 않았음
- 그 폴더안의 파일을 File 배열로 받아서, 반복문을 통해 모든 파일을 일일히 지운 후 폴더를 지웠다

- 여기서도 마찬가지로 해당 파일을 지우기 위해 upload 폴더의 모든 파일명을 File 배열로 가져오고, 반복문으로 돌리면서 그 중 DB의 파일명과 일치한다면 파일을 삭제

- upload 디렉토리까지의 경로로 File 객체 file 을 생성함

- 그 디렉토리 안의 모든 파일명을 가져와야한다

- 그러므로 File 객체 file 로 file.listFiles() 메소드를 통해 upload 디렉토리의 모든 파일을 읽어온다

- deletePro.jsp 에서 DB에서 검색한 상세정보를 저장한 객체 old 를 매개변수로 전달하므로 old 객체로부터 DB에 저장된 파일명을 구할 수 있다

- upload 디렉토리의 파일명 중 DB에 저장된 파일명과 일치한다면 해당 파일삭제

 

- 삭제 기능이 잘 구현되었는지 확인하기 위해 목록페이지->상세페이지->삭제폼 에서 비밀번호를 입력해서 삭제 해보자

- 기존에 있던 첨부파일

- 글이 삭제되었음을 알 수 있다

 

- 콘솔창 확인시

- deletePro.jsp 에서 첨부파일이 저장되는 upload 디렉토리의 실제 경로 구하고 출력한다

- 그 경로로 탐색기에서 확인하면

- 첨부파일 (해파리 사진) 또한 삭제되었음을 알 수 있다

 

첨부파일 수정 이전 파일 문제점

- 첨부파일을 코알라 사진에서 해파리 사진으로 수정하였다

- 해파리 사진은 글을 삭제할때 같이 삭제되었지만 수정 이전 첨부파일인 코알라 사진은 그대로 upload 폴더에 남아있음

- 이전 첨부파일을 지워주는 코드가 없기때문이다.

- 코알라 사진 또한 지우려면 코알라 사진에서 해파리 사진으로 수정할때 코알라 사진을 삭제해야한다

 

자료실 게시판 : 초기 페이지

- index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<script>
	location.href = "upload1/list.jsp";
</script>
</body>
</html>

- index.jsp 파일에서 목록페이지 list.jsp 로 바로 가도록 설정

- index.jsp 파일 기준에서 list.jsp 파일은 upload1 폴더 하위에 있으므로 upload1/list.jsp 로 경로 설정


앞으로 학습할 것들

- 이제 Model 1 으로 만들 수 있는 프로그램 끝났다

 

Model 2 로 넘어가기 전에 3가지를 공부

1. Java Servlet

- 흐름을 제어하는 Controller 클래스를 만들때, Java Servlet 클래스로 만드므로 Java Servlet 클래스 만드는법 배우기

2. 표현언어(EL)

- View 페이지에 결과를 출력할때, 기존 표현식 태그 대신 표현언어를 사용하므로 표현언어(EL) 배우기

3. JSTL

- 사용자 정의 표준인 JSTL 배우기

 

Model 2 구조

- 70% 정도가 Java 코드로 만들어진다

- Model, View, Controller 로 분리되어 개발된다

- Cotroller 클래스 :모든 Class 의 진입점 역할, Java Servlet 클래스로 만들어짐

- Service 클래스 : 실제 요청 처리, 상속 관련

- View 페이지 : EL 이나 JSTL 로 출력

- DAO 클래스에서 sql 문 실행, DAO 클래스는 Model 1과 같다

+ Recent posts