2022년 7월 23일 토요일

JSP 10강 - 파일 업로드 및 다운로드

 파일 첨부가 가능한 자료실 형 게시판을 만들기 위해서는 파일을 업로드, 다운로드 기능을 구현해야 한다. 

1. 라이브러리 추가하기

http://servlets.com/cos/

에서 cos 를 다운 받고, WebContent/WEB-INF/lib에 추가 한다.

2. 화면(폼) 작성

enctype 속성은 서버로 전송할 때 인코딩 방식을 지정하는 속성으로 3가지가 있다.

appliction/x-www-form-urlencoded : 모든 문자를 서버로 전송하기 전에 인코딩 한다. 기본값

multipart/form-data : 모든 문자를 인코딩하지 않는다.<form>태그를 통해 파일을 서버로 전송할 때 주로 사용

text/plain : 공백 문자만 + 기호로 변환하고, 나머지는 인코딩하지 않는다.


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>

<head><title>FileUpload</title></head>

<script>

//입력값 검증용 자바스크립트

    function validateForm(form) { 

        if (form.name.value == "") {

            alert("작성자를 입력하세요.");

            form.name.focus();

            return false;

        }

        if (form.title.value == "") {

            alert("제목을 입력하세요.");

            form.title.focus();

            return false;

        }

        if (form.attachedFile.value == "") {

            alert("첨부파일은 필수 입력입니다.");

            return false;

        }

    }

</script>

<body>

    <h3>파일 업로드</h3>

    <span style="color: red;">${errorMessage }</span>

//method 속성은 post로, enctype 속성은 multipart/form-data로 지정해야 한다.

    <form name="fileForm" method="post" enctype="multipart/form-data"

          action="UploadProcess.jsp" onsubmit="return validateForm(this);">

        작성자 : <input type="text" name="name" value="머스트해브" /><br />

        제목 : <input type="text" name="title" /><br /> 

        카테고리(선택사항) : 

            <input type="checkbox" name="cate" value="사진" checked />사진 

            <input type="checkbox" name="cate" value="과제" />과제 

            <input type="checkbox" name="cate" value="워드" />워드 

            <input type="checkbox" name="cate" value="음원" />음원 <br /> 

//<input> 태그의 type 속성은 file로 지정한다.

        첨부파일 : <input type="file" name="attachedFile" /> <br />

        <input type="submit" value="전송하기" />

    </form>

</body>

</html>

3. 파일 업로드 및 폼값 처리

폼값을 받을 때는 확장 라이브러리에서 제공하는 MultipartRequest 클래스를 사용한다.

//import 생략

String saveDirectory = application.getRealPath("/Uploads");  // 저장할 디렉터리

int maxPostSize = 1024 * 1000;  // 파일 최대 크기(1MB)

String encoding = "UTF-8";  // 인코딩 방식

try {

    // 1. MultipartRequest 객체 생성

    MultipartRequest mr = new MultipartRequest(request, saveDirectory, maxPostSize, encoding);


    // 2. 새로운 파일명 생성

    String fileName = mr.getFilesystemName("attachedFile");  // 현재 파일 이름

    String ext = fileName.substring(fileName.lastIndexOf("."));  // 파일 확장자

    String now = new SimpleDateFormat("yyyyMMdd_HmsS").format(new Date());

    String newFileName = now + ext;  // 새로운 파일 이름("업로드일시.확장자")


    // 3. 파일명 변경(서버의 운영체제에 따라 경로 표현이 다르기에 이렇게 설정)

    File oldFile = new File(saveDirectory + File.separator + fileName); 

    File newFile = new File(saveDirectory + File.separator + newFileName);

    oldFile.renameTo(newFile);


    // 4. 다른 폼값 받기

    String name = mr.getParameter("name");

    String title = mr.getParameter("title");

    String[] cateArray = mr.getParameterValues("cate");

    StringBuffer cateBuf = new StringBuffer();

    if (cateArray == null) {

        cateBuf.append("선택 없음");

    }

    else {

        for (String s : cateArray) {

            cateBuf.append(s + ", ");

        }

    }


    // 5. DTO 생성

    MyfileDTO dto = new MyfileDTO();

    dto.setName(name);

    dto.setTitle(title);

    dto.setCate(cateBuf.toString());

    dto.setOfile(fileName);

    dto.setSfile(newFileName);


    // 6. DAO를 통해 데이터베이스에 반영

    MyfileDAO dao = new MyfileDAO();

    dao.insertFile(dto);

    dao.close();


    // 7. 파일 목록 JSP로 리디렉션

    response.sendRedirect("FileList.jsp");

}

catch (Exception e) {

    e.printStackTrace();

    request.setAttribute("errorMessage", "파일 업로드 오류");

    request.getRequestDispatcher("FileUploadMain.jsp").forward(request, response);

}

%>

4. 파일 다운로드
//import 생략
String saveDirectory = application.getRealPath("/Uploads"); //다운로드 파일 위치
String saveFilename = request.getParameter("sName"); //저장된 파일명
String originalFilename = request.getParameter("oName"); //원본 파일명

try {
    // 파일을 찾아 입력 스트림 생성
    File file = new File(saveDirectory, saveFilename);  
    InputStream inStream = new FileInputStream(file);
    
    // 한글 파일명 깨짐 방지
    String client = request.getHeader("User-Agent");
    if (client.indexOf("WOW64") == -1) {
        originalFilename = new String(originalFilename.getBytes("UTF-8"), "ISO-8859-1");
    }
    else {
        originalFilename = new String(originalFilename.getBytes("KSC5601"), "ISO-8859-1");
    }
   
// 파일 다운로드용 응답 헤더 설정 
    response.reset(); 
//다운로드 창을 위한 콘텐츠 타입 지정 (octet-stream 은 8비트 단위의 바이너리 데이터)
    response.setContentType("application/octet-stream"); 
//파일 다운로드 창이 뜰 때 원본 파일명이 기본으로 입력 되도록 설정
    response.setHeader("Content-Disposition", "attachment; filename=\"" +originalFilename + "\""); 
    response.setHeader("Content-Length", "" + file.length() );
    
    // 출력 스트림 초기화
    out.clear();  //출력 스트림 중복을 막기 위해 현재 것을 초기화
    
    // response 내장 객체로부터 새로운 출력 스트림 생성
    OutputStream outStream = response.getOutputStream();   

    // 출력 스트림에 파일 내용 출력
    byte b[] = new byte[(int)file.length()];
    int readBuffer = 0;    
    while ( (readBuffer = inStream.read(b)) > 0 ) {
        outStream.write(b, 0, readBuffer);
    }

    // 입/출력 스트림 닫음
    inStream.close(); 
    outStream.close();
}
catch (FileNotFoundException e) {
    JSFunction.alertBack("파일을 찾을 수 없습니다.", out);
}
catch (Exception e) {
    JSFunction.alertBack("예외가 발생하였습니다.", out);
}
%>

댓글 없음:

댓글 쓰기