파일 업로드 라이브러리 설치

  • JSP에서 파일 업로드 기능을 구현하기 위해서 오픈 라이브러리를 사용하면 쉽게 구현할 수 있다.
  • 파일 업로드 라이브러리에는 대표적으로 cos.jar와 commons-fileupload.jar가 있다.
  • 여기서는 cos.jar를 사용하도록 하겠다.
cos.jar 다운로드 사이트

Servlets.com | com.oreilly.servlet

 

Servlets.com | com.oreilly.servlet

 

www.servlets.com

  1. cos-22.05.zip파일을 다운로드 받아서 압축 풀기
  2. cos-22.05 안에 cos.jar 파일을 복사하기
  3. "컨텍스트(MyMVC)/webapp/WEB-INF/lib" 안에 붙여넣기

 


 

파일 업로드시 주의사항
  1. form태그의 method를 post로 지정
  2. form태그의 enctype을 multipart/form-data로 지정
    ※ 디폴트값인 application/x-www-form-urlencoded로 지정하면 파일명만 전송된다.

 

[View] input.jsp 수정 (게시판 글쓰기 페이지)

[경로: src/main/webapp/board/input.jsp]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
 
<div class="container">
    <h1>MVC Board</h1>
    <br><br>
    <form name="bbsF" method="post" action="insert.do" enctype="multipart/form-data">
        <table border="1">
            ...
            <tr>
                <th>첨부파일</th>
                <td>
                    <input type="file" name="fileName" id="fileName">
                </td>
            </tr>
        </table>
    </form>
</div>
cs

 

[Controller] BoardInsertAction 수정

[경로: src/main/java/board.controller/BoardInsertAction.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class BoardInsertAction extends AbstractAction {
 
    @Override
    public void execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
        //0. 파일 업로드 처리
        //<1> 업로드할 디렉토리의 절대경로 얻기 (src/main/webapp/upload 파일)
        ServletContext application = req.getServletContext();
        System.out.println("application: " + application);
        //업로드된 파일의 실제 절대경로 구하기
        String upDir = application.getRealPath("/upload");
        System.out.println("upDir: " + upDir);
        
        //<2> cos.jar의 MultipartRequest 객체 생성 ==> 업로드 처리를 해줌
        MultipartRequest mreq = null;
        try {
            DefaultFileRenamePolicy df = new DefaultFileRenamePolicy();
            //FileRenamePolicy: 동일한 파일명의 파일이 올라왔을 때 덮어쓰지 않게 방지함 (파일명에 인덱스 번호를 붙인다.)
            mreq = new MultipartRequest(req, upDir, 1024*1024*100"utf-8", df);
        //(HttpServletRequest request, 저장할 경로, 업로드 최대용량(100MB), 인코딩 방식(한글처리), policy);
        }catch (IOException e) {//용량 초과시 IOException 발생
            System.out.println("파일 업로드 실패: " + e);
            return;
        }
        //1. 사용자가 입력한 값 받기(MultipartRequest를 이용해 파라미터값 추출)
        String title = mreq.getParameter("title");
        String name = mreq.getParameter("name");
        String content = mreq.getParameter("content");
        String passwd = mreq.getParameter("passwd");
        
        //첨부파일명 받기
        String fileName = mreq.getFilesystemName("fileName");
        //첨부파일명: getParameter(X) => getFileSystemName("파라미터명)
        
        //파일크기 받기
        File file = mreq.getFile("fileName");
        long fileSize = 0;
        if(file!=null) {
            fileSize = file.length(); //파일크기
        }
        
        //2. 유효성 체크
        if(title==null || name==null || passwd==null || title.trim().isBlank()
                || name.trim().isBlank() || passwd.trim().isBlank()) {
            this.setRedirect(true); //redirect이동
            this.setViewName("input.do");//input.do로 redirect이동
            return;
        }
        //3. 1번에서 받은 값 BoardVO객체에 담기
        BoardVO vo = new BoardVO(0, name, passwd, title, content, null0, fileName, fileSize);
        //4. BoardDAO 생성 후 insertBoard() 호출
        BoardDAO dao = new BoardDAO();
        int n = dao.insertBoard(vo);
        //5. 그 결과 메시지, 이동경로 설정해서 req에 저장하기
        String msg = (n>0)? "글 등록 완료":"글 등록 실패";
        String loc = (n>0)? "list.do":"javascript:history.back()";
        
        //request에 msg와 loc 저장 => message.jsp에서 꺼내야 함
        req.setAttribute("msg", msg);
        req.setAttribute("loc", loc);
        
        //뷰페이지 지정
        this.setViewName("/board/message.jsp");
        //이동방식 지정
        this.setRedirect(false); //forward이동
    }
 
}
cs

파일 업로드하여 글 작성시 콘솔

  • pageContext 내장 객체의 메서드
    • ServletContext getServletContext(): 페이지에 대한 서블릿 실행 환경 정보를 담고 있는 application 내장 객체를 리턴한다.
  • 이클립스에서 upload 파일 경로: src/main/webapp/upload
    • getRealPath("/"): src/main/webapp까지를 의미
    • getReatPath("/upload"): src/main/webapp/upload를 의미
    • getRealPath: upload 파일의 실제 위치는 훨씬 깊숙한 곳에 있는데, 그 절대 경로를 알아내는 메서드
    • 실제 위치(upDir): C:\multicampus\Java-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\MyMVC\upload

  • MultipartRequest mreq = new MultipartRequest(HttpServletRequest request, 저장할 경로, 업로드 최대용량, 인코딩 방식, policy)
  • FileRenamePolicy: 동일한 파일명의 파일이 올라오면 디폴트로는 새로운 파일이 예전 파일을 덮어쓰면서 예전 파일이 사라진다. 이를 방지하기 위해 FileRenamePolicy를 이용하면 동일한 파일명의 파일이 올라왔을 때 덮어쓰지 않게 방지한다.

 

[View] view.jsp 수정 (코드 추가)

1
2
3
4
5
6
7
8
9
10
11
12
13
<tr>
    <td width="20%" class="m1"><b>첨부파일</b></td>
    <td colspan="3" class="text-left">&nbsp; 
    <!-- 첨부파일이 있다면 --> 
<c:if test="${vo.fileName ne null}">
    <a href="${pageContext.request.contextPath}/upload/${vo.fileName}" download>${vo.fileName}</a> 
    <%-- request.getContextPath()와 동일 
    ${pageContext.request.contextPath}: 내 현재 위치 -> MyMVC 반환
    --%>
    [${vo.fileSize}]bytes
</c:if>
    </td>
</tr>
cs

실행 결과

 


게시판 글목록 수정

첨부파일이 있는 글에 첨부파일 아이콘이 보이게 설정해보자.

 

아이콘 다운로드

[경로: src/main/webapp/images/attach.png]

attach.png

 

[View] list.jsp 수정 (코드 추가)

1
2
3
4
5
6
<td>
    <a href="view.do?num=${board.num}">${board.title}</a>
    <c:if test="${board.fileName ne null}">
        <img src="../images/attach.png" style="width:0.8em">
    </c:if>
</td>
cs

실행 결과

 


글삭제 수정

첨부파일이 있는 글을 삭제하면 첨부파일도 같이 삭제되도록 설정

[Controller] BoardDeleteAction 수정 (코드 추가)

1
2
3
4
5
6
7
8
9
10
11
12
//5. 서버에 업로드했던 파일이 있다면 서버에서 삭제 처리
String fileName = tmp.getFileName();//첨부파일명
if(fileName!=null) {
    //절대경로(업로드 디렉토리)
    String upDir = req.getServletContext().getRealPath("/upload");
    File delFile = new File(upDir, fileName); //(상위 디렉터리, 파일명)
    if(delFile.exists()) {
        boolean b = delFile.delete();
        System.out.println("파일 삭제 여부: " + b);
    }
}
 
cs

C:\multicampus\Java-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\MyMVC\upload에 들어가서 확인해보면 첨부파일이 삭제된 것을 확인할 수 있다.

 


글수정 수정

첨부파일도 수정할 수 있도록 설정

 

[View] edit.jsp 수정 (코드 추가)

[경로: src/main/webapp/board/edit.jsp]

1
2
3
4
5
6
7
8
9
10
11
12
13
<tr>
    <th>첨부파일</th>
        <td>
        <c:if test="${board.fileName ne null}">
        ${board.fileName} [${board.fileSize} bytes]
        <br>
        </c:if>
        <!-- 옛 첨부파일을 hidden으로 넘기자 ------------------- -->
        <input type="hidden" name="old_fileName" value="${board.fileName}">
        <!-- -------------------------------------------- -->
        <input type="file" name="fileName" id="fileName">
    </td>
</tr>
cs

 

[Controller] BoardUpdateAction 수정

[경로: src/main/java/board.controller/BoardUpdateAction.java]

주석 0번, 4-2번 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class BoardUpdateAction extends AbstractAction {
 
    @Override
    public void execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
        //0. 파일 업로드 처리
        String upDir = req.getServletContext().getRealPath("/upload");
        System.out.println("upDir확인: " + upDir);
        
        MultipartRequest mreq = new MultipartRequest(req, upDir, 100*1024*1024
                "utf-8"new DefaultFileRenamePolicy());
        
        //1. 글번호, 제목, 작성자, 내용, 비밀번호, 첨부파일 받기
        String numStr = mreq.getParameter("num");
        String title = mreq.getParameter("title");
        String name = mreq.getParameter("name");
        String content = mreq.getParameter("content");
        String passwd = mreq.getParameter("passwd");
        String old_fileName = mreq.getParameter("old_fileName"); //예전 첨부파일명
        //첨부파일
        String fileName = mreq.getFilesystemName("fileName"); //새로 첨부하는 파일명
        long fileSize = 0;
        File file = mreq.getFile("fileName");
        if(file!=null) {
            fileSize = file.length();
        }
        
        //2. 유효성 체크
        if(numStr==null|| title==null || name==null || passwd==null || numStr.trim().isBlank()
            || title.trim().isBlank() || name.trim().isBlank() || passwd.trim().isBlank()) {
            this.setRedirect(true); //redirect이동
            this.setViewName("update.do"); //update.do로 redirect이동
            return;
        }
        int num = Integer.parseInt(numStr.trim());
        //3. 1번에서 받은 값을 BoardVO에 담기
        BoardVO vo = new BoardVO(num, name, passwd, title, content, null0, fileName, fileSize);
        //4. BoardDAO의 updateBoard(vo) 호출
        BoardDAO dao = new BoardDAO();
        int n = dao.updateBoard(vo);
        
        //4_2. 새로운 파일을 업로드했다면 예전에 업로드했던 파일은 서버에서 지우자
        if(fileName!=null && old_fileName!=null) {
            File delFile = new File(upDir, old_fileName);
            if(delFile.exists()) {
                boolean b = delFile.delete();
                System.out.println("옛파일 삭제 여부: " + b);
            }
        }
        
        //5. 그 결과 메시지, 이동경로 처리
        String msg = (n>0)? "글수정 성공":"글수정 실패";
        String loc = (n>0)? "list.do":"javascript:history.back()";
        req.setAttribute("msg", msg);
        req.setAttribute("loc", loc);
        
        this.setViewName("/board/message.jsp");
        this.setRedirect(false);
    }
 
}
cs

글수정 클릭
첨부파일 다른 걸로 올리기 => 수정 완료
실행 결과 콘솔

 

+ Recent posts