복습
첨부파일 업로드 위치
- 실제 업로드 되는 폴더 위치가 따로 있다
- 이클립스에 폴더를 만들어둬야 이 위치에 폴더가 생긴다
첨부파일 업로드 폼
- 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과 같다