소개
업로드 할 파일을 찾아서 선택하려면 <input type="file">
양식 의 HTML 필드 가 필요합니다 . HTML 사양에 명시된대로 POST
메서드 를 사용해야 enctype
하고 양식 의 속성을로 설정해야 "multipart/form-data"
합니다.
<form action="upload" method="post" enctype="multipart/form-data">
<input type="text" name="description" />
<input type="file" name="file" />
<input type="submit" />
</form>
이러한 양식을 제출하면 요청 본문에서 설정되지 않은 경우와 다른 형식으로 이진 다중 파트 양식 데이터를 사용할 수 있습니다 enctype
.
Servlet 3.0 이전에는 Servlet API가 기본적으로를 지원하지 않았습니다 multipart/form-data
. 기본 형식 enctype 만 지원합니다 application/x-www-form-urlencoded
. request.getParameter()
및 배우자들 모두 반환 null
멀티 폼 데이터를 사용하는 경우. 여기에서 잘 알려진 Apache Commons FileUpload 가 등장했습니다.
수동으로 구문 분석하지 마십시오!
이론적으로 요청 본문을 기반으로 직접 구문 분석 할 수 있습니다 ServletRequest#getInputStream()
. 그러나 이것은 RFC2388에 대한 정확한 지식이 필요한 정확하고 지루한 작업입니다 . 이 작업을 직접 수행하거나 인터넷의 다른 곳에서 찾은 자체 라이브러리가없는 코드를 복사하여 붙여 넣어서는 안됩니다. roseindia.net과 같은 많은 온라인 소스가 이에 실패했습니다. pdf 파일 업로드 도 참조하십시오 . 몇 년 동안 수백만 명의 사용자가 사용하고 암시 적으로 테스트 한 실제 라이브러리를 사용해야합니다. 이러한 라이브러리는 견고성이 입증되었습니다.
이미 Servlet 3.0 이상을 사용중인 경우 기본 API를 사용하십시오.
최소한 Servlet 3.0 (Tomcat 7, Jetty 9, JBoss AS 6, GlassFish 3 등)을 사용 HttpServletRequest#getPart()
하는 경우 제공된 표준 API를 사용 하여 개별 멀티 파트 양식 데이터 항목을 수집 할 수 있습니다 (대부분의 Servlet 3.0 구현은 실제로 Apache를 사용합니다) 이것에 대한 커버 아래의 Commons FileUpload!). 또한 일반적인 양식 필드는 getParameter()
일반적인 방법으로 사용할 수 있습니다 .
먼저 서블릿에 주석을 달아 요청을 @MultipartConfig
인식하고 지원 하여 작동하게하십시오.multipart/form-data
getPart()
@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
// ...
}
그런 doPost()
다음 다음과 같이 구현하십시오 .
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String description = request.getParameter("description"); // Retrieves <input type="text" name="description">
Part filePart = request.getPart("file"); // Retrieves <input type="file" name="file">
String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
InputStream fileContent = filePart.getInputStream();
// ... (do your job here)
}
를 참고하십시오 Path#getFileName()
. 파일 이름을 얻는 방법에 대한 MSIE 수정 프로그램입니다. 이 브라우저는 파일 이름 대신 이름을 따라 전체 파일 경로를 잘못 보냅니다.
경우에 당신은이 <input type="file" name="file" multiple="true" />
멀티 파일 업로드 아래로 수집 (불행하게도 그런 방법으로는 없다 request.getParts("file")
)
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ...
List<Part> fileParts = request.getParts().stream().filter(part -> "file".equals(part.getName()) && part.getSize() > 0).collect(Collectors.toList()); // Retrieves <input type="file" name="file" multiple="true">
for (Part filePart : fileParts) {
String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
InputStream fileContent = filePart.getInputStream();
// ... (do your job here)
}
}
아직 Servlet 3.1이 아닌 경우 수동으로 제출 된 파일 이름을 얻습니다.
주 Part#getSubmittedFileName()
서블릿 3.1 (톰캣 8 부두 9 제이보스 8 글래스 피쉬 4 등)에 도입 하였다. 아직 Servlet 3.1을 사용하지 않는 경우 제출 된 파일 이름을 얻으려면 추가 유틸리티 방법이 필요합니다.
private static String getSubmittedFileName(Part part) {
for (String cd : part.getHeader("content-disposition").split(";")) {
if (cd.trim().startsWith("filename")) {
String fileName = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
return fileName.substring(fileName.lastIndexOf('/') + 1).substring(fileName.lastIndexOf('\\') + 1); // MSIE fix.
}
}
return null;
}
String fileName = getSubmittedFileName(filePart);
파일 이름을 얻는 방법에 대한 MSIE 수정 사항을 참고하십시오. 이 브라우저는 파일 이름 대신 이름을 따라 전체 파일 경로를 잘못 보냅니다.
아직 Servlet 3.0을 사용하지 않는 경우 Apache Commons FileUpload를 사용하십시오.
아직 Servlet 3.0을 사용하고 있지 않은 경우 (업그레이드 할 시점이 아닙니까?) 일반적인 방법은 Apache Commons FileUpload 를 사용 하여 여러 형식의 데이터 요청을 구문 분석하는 것입니다. 훌륭한 사용 설명서 와 FAQ가 있습니다 (둘 다주의해서 살펴보십시오). O'Reilly ( " cos ") MultipartRequest
도 있지만 약간의 버그가 있으며 몇 년 동안 더 이상 활발하게 유지되지 않습니다. 나는 그것을 사용하지 않는 것이 좋습니다. Apache Commons FileUpload는 여전히 활발하게 유지되고 있으며 현재는 매우 성숙합니다.
Apache Commons FileUpload를 사용하려면 webapp에 최소한 다음 파일이 있어야합니다 /WEB-INF/lib
.
커먼즈 IO를 잊었 기 때문에 초기 시도가 실패했을 가능성이 높습니다.
여기에 어떻게 킥오프 예입니다 doPost()
당신의이 UploadServlet
아파치 코 몬즈는 FileUpload를 사용할 때처럼 보일 수는 :
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
for (FileItem item : items) {
if (item.isFormField()) {
// Process regular form field (input type="text|radio|checkbox|etc", select, etc).
String fieldName = item.getFieldName();
String fieldValue = item.getString();
// ... (do your job here)
} else {
// Process form file field (input type="file").
String fieldName = item.getFieldName();
String fileName = FilenameUtils.getName(item.getName());
InputStream fileContent = item.getInputStream();
// ... (do your job here)
}
}
} catch (FileUploadException e) {
throw new ServletException("Cannot parse multipart request.", e);
}
// ...
}
그것은 당신이 전화를하지 않는 것이 매우 중요합니다 getParameter()
, getParameterMap()
, getParameterValues()
, getInputStream()
, getReader()
사전에 동일한 요청에 등. 그렇지 않으면 서블릿 컨테이너는 요청 본문을 읽고 구문 분석하므로 Apache Commons FileUpload는 빈 요청 본문을 가져옵니다. ao ServletFileUpload # parseRequest (request)도 빈 목록을 반환합니다 .
를 참고하십시오 FilenameUtils#getName()
. 파일 이름을 얻는 방법에 대한 MSIE 수정 프로그램입니다. 이 브라우저는 파일 이름 대신 이름을 따라 전체 파일 경로를 잘못 보냅니다.
또는이 모든 Filter
것을 자동으로 구문 분석 request.getParameter()
하고 일반적인 방법으로 계속 사용 하여 업로드 된 파일을 검색 할 수 있도록 요청을 매개 변수 맵에 다시 넣을 수도 있습니다 request.getAttribute()
. 이 블로그 기사에서 예제를 찾을 수 있습니다 .
getParameter()
여전히 반환 되는 GlassFish3 버그에 대한 해결 방법null
3.1.2 이전의 Glassfish 버전 은 여전히을 반환 하는 버그 가있었습니다 . 이러한 컨테이너를 대상으로하고 업그레이드 할 수없는 경우이 유틸리티 방법 을 사용하여 값을 추출해야합니다 .getParameter()
null
getPart()
private static String getValue(Part part) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(part.getInputStream(), "UTF-8"));
StringBuilder value = new StringBuilder();
char[] buffer = new char[1024];
for (int length = 0; (length = reader.read(buffer)) > 0;) {
value.append(buffer, 0, length);
}
return value.toString();
}
String description = getValue(request.getPart("description")); // Retrieves <input type="text" name="description">
업로드 된 파일을 저장하면 (사용하지 getRealPath()
않고 part.write()
!)
얻은 InputStream
( fileContent
위의 코드 스 니펫에 표시된 변수)을 디스크 또는 데이터베이스 에 올바르게 저장하는 방법에 대한 자세한 내용은 다음 답변으로 이동하십시오 .
업로드 된 파일 제공
저장된 파일을 디스크 또는 데이터베이스에서 클라이언트로 올바르게 제공하는 방법에 대한 자세한 내용은 다음 답변을 참조하십시오.
양식 아약시
다음 답변으로 Ajax (및 jQuery)를 사용하여 업로드하는 방법을 알아보십시오. 양식 데이터를 수집하기위한 서블릿 코드는이를 위해 변경할 필요가 없습니다. 응답 방식 만 변경 될 수 있지만 이는 다소 사소합니다 (예 : JSP로 전달하는 대신 Ajax 호출을 담당하는 스크립트에 따라 JSON 또는 XML 또는 일반 텍스트 만 인쇄).
이 모든 것이 도움이되기를 바랍니다 :)