🍁파일 업로드 / 다운로드
브라우저와 웹 서버 간에 파일을 복사하는 작업을 의미한다.
클라이언트의 자원을 서버 쪽으로 복사하면 파일 업로드, 서버 쪽에서 클라이언트의 자원을 복사하면 파일 다운로드라고 한다.
파일 업로드 라이브러리
cos library
cos-22.05.zip 파일을 저장한다.
- C:\Class\code\server\JSPTest\src\main\webapp\WEB-INF\lib
다운로드한 cos.jar 파일을 프로젝트의 WEB-INF폴더의 lib폴더에 저장한다. 이렇게 하면 톰캣이 대신 참조를 해 준다.
그리고 업로드한 파일을 저장할 전용 폴더를 미리 만들어둔다. webapp(루트 폴더)에 files 폴더를 생성했다.
단일 파일 업로드
파일 업로드 설정
<form method="POST" action="ex16_ok.jsp" enctype="multipart/form-data">
1. <input type="file">
통상적으로 파일 첨부에는 file type의 input 태그를 사용한다.
2. <form method="POST">
method가 POST여야 한다. GET 방식은 데이터가 너무 길면 잘릴 수 있다.
GET 방식으로 잘리는 게 1MB도 안 된다. 약 8KB 이상이면 잘리기 때문에 POST 방식을 사용한다.
3. <form enctype="">
a. application/x-www-form-urlencoded: 폼태그에서 전송하는 데이터가 문자열이다. (기본값)
b. multipart/form-data: 서버로 전송할 때 문자열과 비문자열을 동시에 전송한다.
마지막으로 인코딩 타입을 설정해 준다.
multipart/form-data을 안 하면 첨부 파일이 안 넘어가므로 필수로 설정한다.
인코딩 타입 변환의 문제점
<%@ 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>
<link rel="stylesheet" href="http://pinnpublic.dothome.co.kr/cdn/example-min.css">
</head>
<body>
<h1>파일 업로드</h1>
<form method="POST" action="ex16_ok.jsp" enctype="multipart/form-data">
<table class="vertical">
<tr>
<th>이름</th>
<td><input type="text" name="name"></td>
</tr>
<tr>
<th>나이</th>
<td><input type="number" name="age" min="1" max="100"></td>
</tr>
<tr>
<th>파일</th>
<td><input type="file" name="attach"></td>
</tr>
</table>
<div>
<input type="submit" value="등록하기">
</div>
</form>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="http://pinnpublic.dothome.co.kr/cdn/example-min.js"></script>
</body>
</html>
form 태그의 enctype 인코딩 타입을 multipart/form-data로 바꾸면 다음의 문제가 발생한다.
1. request.getParameter() 동작 불능
2. request.getParameterValues() 동작 불능
<%
String name = request.getParameter("name"); //동작(X)
String age = request.getParameter("age"); //동작(X)
%>
cos.jar 안에는 MultipartRequest 클래스가 있는데, 이 객체가 request의 수신 기능을 대신한다.
업로드된 파일 로컬 경로 지정
- C:\Class\code\server\JSPTest\src\main\webapp\files
- C:\Class\code\server\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\JSPTest\files
처음에 업로드된 파일을 어디에 저장할지 경로(webapp폴더 내 files 폴더)를 정해 주었다.
이에 대한 로컬 경로를 지정해 주어야 한다.
'/'는 webapp 폴더를 의미한다. 그래서 /files 폴더는 업로드된 파일을 저장할 폴더를 의미한다. getRealPath 메서드는 절대 경로(상대 경로)를 로컬 경로로 변환해주는 역할을 한다.
wtpwebapps 안에 실제 실행 폴더를 만들어 두었다.
이를 실행 폴더라고 하는데, 실행 폴더 내에 카피본을 만들어서 관리하고 실행한다.
이곳이 실제 운영중인 작업 위치이므로, 실제로 파일을 업로드하면 저장도 이곳의 files 폴더에 업로드된다.
<%@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"%>
<%
request.setCharacterEncoding("UTF-8");
//String name = request.getParameter("name");
//String age = request.getParameter("age");
//파일 저장 경로
//C:\Class\code\server\JSPTest\src\main\webapp\files
//C:\Class\code\server\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\JSPTest\files
//System.out.println(path);
String path = application.getRealPath("/files");
//업로드 파일의 최대 크기 지정
//- 바이트 단위
int size = 1024 * 1024 * 100; //100MB
//변수 선언
String name = ""; //이름
String age = ""; //나이
String filename = ""; //첨부파일명
String orgfilename = ""; //첨부파일명
//request > MultipartRequest 객체 생성
try {
MultipartRequest multi = new MultipartRequest(
request, //원래 request
path, //파일 업로드 위치
size, //최대 크기
"UTF-8", //인코딩
new DefaultFileRenamePolicy() //파일명 관리(중복 시 넘버링)
);
//데이터 수신
name = multi.getParameter("name");
age = multi.getParameter("age");
//업로드 파일 정보 (파일명)
//<input type="file" name="attach">
filename = multi.getFilesystemName("attach"); //파일명
orgfilename = multi.getOriginalFileName("attach"); //파일명
} catch (Exception e) {
e.printStackTrace();
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="http://pinnpublic.dothome.co.kr/cdn/example-min.css">
</head>
<body>
<h1>결과</h1>
<div>
이름: <%= name %>
</div>
<div>
나이: <%= age %>
</div>
<div>
파일명: <%= filename %>
</div>
<div>
파일명: <%= orgfilename %>
</div>
<h2>파일 다운로드</h2>
<div>
<a href="/jsp/files/<%= filename %>"><%= orgfilename %></a>
</div>
<h2>파일 다운로드</h2>
<div>
<a href="/jsp/files/<%= filename %>" download><%= orgfilename %></a>
</div>
<h2>파일 다운로드</h2>
<div>
<a href="download.jsp?filename=<%= filename %>&orgfilename=<%= orgfilename %>"><%=orgfilename %></a>
</div>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="http://pinnpublic.dothome.co.kr/cdn/example-min.js"></script>
</body>
</html>
MultipartRequest 객체를 만드는 순간 이미 첨부파일은 files에 복사가 완료된다.
getFilesystemName는 파일이 저장된 실제 이름이고, getOriginalFileName는 사용자가 올렸던 원본 이름이다.
파일 다운로드
<h2>파일 다운로드</h2>
<div>
<a href="/jsp/files/<%= filename %>"><%= orgfilename %></a>
</div>
- 장점: 간단하다.
- 단점: 파일 확장자에 따라 달라진다.
위 방법은 간단하지만 파일 확장자에 따라 다운로드 하는 방법이 달라지므로 적절하지 않다.
download
<h2>파일 다운로드</h2>
<div>
<a href="/jsp/files/<%= filename %>" download><%= orgfilename %></a>
</div>
- 장점: 간단하다.
- 단점: 파일명이 다운로드 할 때마다 바뀔 수 있다. (넘버링된다.)
download는 모든 파일을 무조건 다운로드 시키는 옵션이다.
속성 하나만 붙이는 것만으로도 다운로드가 되기 때문에 생산성이 높다.
download.jsp 모듈
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.net.URLEncoder"%>
<%@ page import="java.io.File"%>
<%@ page import="java.io.*"%>
<%
String fileName = request.getParameter("filename");
String orgfileName = request.getParameter("orgfilename");
String savePath = "files"; //첨부파일 폴더의 경로: webapp > files
ServletContext context = getServletContext();
String sDownloadPath = context.getRealPath(savePath);
String sFilePath = sDownloadPath + "/" + fileName;
byte b[] = new byte[4096];
FileInputStream in = new FileInputStream(sFilePath);
String sMimeType = getServletContext().getMimeType(sFilePath);
System.out.println("sMimeType>>>" + sMimeType);
if (sMimeType == null)
sMimeType = "application/octet-stream";//MIME. 브라우저에게 해석할 수 없는 데이터라고 타입을 속여서 보내는 작업 중 하나
response.setContentType(sMimeType);
String agent = request.getHeader("User-Agent");
boolean ieBrowser = (agent.indexOf("MSIE") > -1) || (agent.indexOf("Trident") > -1);
if (ieBrowser) {
orgfileName = URLEncoder.encode(orgfileName, "UTF-8").replaceAll("/+", "%20");
} else {
orgfileName = new String(orgfileName.getBytes("UTF-8"), "iso-8859-1");
}
response.setHeader("Content-Disposition", "attachment; filename= " + orgfileName);
ServletOutputStream out2 = response.getOutputStream();
int numRead;
while ((numRead = in.read(b, 0, b.length)) != -1) {
out2.write(b, 0, numRead);
}
out2.flush();
out2.close();
in.close();
%>
<h2>파일 다운로드</h2>
<div>
<a href="downLoad.jsp?filename=<%= filename %>&orgfilename=<%= orgfilename %>"><%= orgfilename %></a>
</div>
- 장점: 무조건 다운로드 처리하며, 원본 파일명으로 다운로드한다.
- 단점: 비용이 높다.(download.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>
<link rel="stylesheet" href="http://pinnpublic.dothome.co.kr/cdn/example-min.css">
</head>
<body>
<form method="POST" action="ex17_ok.jsp" enctype="multipart/form-data">
<table class="vertical">
<tr>
<th>파일1</th>
<td><input type="file" name="attach1"></td>
</tr>
<tr>
<th>파일2</th>
<td><input type="file" name="attach2"></td>
</tr>
<tr>
<th>파일3</th>
<td><input type="file" name="attach3"></td>
</tr>
</table>
<div>
<input type="submit" value="업로드">
</div>
</form>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="http://pinnpublic.dothome.co.kr/cdn/example-min.js"></script>
</body>
</html>
<%@page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy"%>
<%@page import="com.oreilly.servlet.MultipartRequest"%>
<%@page import="java.util.ArrayList"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String path = application.getRealPath("/files");
int size = 1024 * 1024 * 100;
ArrayList<String> filename = new ArrayList<String>();
ArrayList<String> orgfilename = new ArrayList<String>();
try {
MultipartRequest multi = new MultipartRequest(
request,
path,
size,
"UTF-8",
new DefaultFileRenamePolicy()
);
//다중 파일명 > 컬렉션
filename.add(multi.getFilesystemName("attach1"));
filename.add(multi.getFilesystemName("attach2"));
filename.add(multi.getFilesystemName("attach3"));
orgfilename.add(multi.getOriginalFileName("attach1"));
orgfilename.add(multi.getOriginalFileName("attach2"));
orgfilename.add(multi.getOriginalFileName("attach3"));
} catch (Exception e) {
e.printStackTrace();
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="http://pinnpublic.dothome.co.kr/cdn/example-min.css">
</head>
<body>
<h1>결과</h1>
<% for (int i=0; i<3; i++) { %>
<div>
<a href="download.jsp?filename=<%= filename.get(i) %>&orgfilename=<%= orgfilename.get(i) %>"><%=orgfilename.get(i) %></a>
</div>
<% } %>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="http://pinnpublic.dothome.co.kr/cdn/example-min.js"></script>
</body>
</html>