Spring MVCファイルのアップロード例
SpringはMultipartResolver
インターフェースを使用して、実装の2つであるWebアプリケーションでのファイルアップロードを処理します。
-
StandardServletMultipartResolver
–サーブレット3.0マルチパートリクエストの解析。 -
CommonsMultipartResolver
–クラシックコモンズ-fileupload.jar
この記事で使用されるツール:
-
Spring 4.3.5.RELEASE
-
メーベン3
-
Tomcat 7または8、Jetty 9またはServlet 3.0コンテナー
一言で言えば、この記事では、Spring MVC Webアプリケーションでファイルのアップロードを処理する方法と、一般的な最大サイズを超えるファイルサイズの例外を処理する方法を示します。
Note
この記事では、サーブレット3.0マルチパートリクエストの解析に焦点を当てます。
P.S Article is updated from Spring 2.5.x to Spring 4.3.x
1. プロジェクト構造
標準のMavenプロジェクト構造。
2. プロジェクトの依存関係
標準のSpring依存関係。ファイルのアップロードに追加のライブラリは不要です。
pom.xml
4.0.0 com.example spring-mvc-file-upload war 1.0-SNAPSHOT Spring MVC file upload 1.8 4.3.5.RELEASE 1.2 3.1.0 1.1.3 1.7.12 org.springframework spring-webmvc ${spring.version} commons-logging commons-logging javax.servlet jstl ${jstl.version} javax.servlet javax.servlet-api ${servletapi.version} provided org.slf4j jcl-over-slf4j ${jcl.slf4j.version} ch.qos.logback logback-classic ${logback.version} org.apache.maven.plugins maven-compiler-plugin 3.3 ${jdk.version} ${jdk.version} org.eclipse.jetty jetty-maven-plugin 9.2.11.v20150529 10 /spring4upload org.apache.maven.plugins maven-eclipse-plugin 2.9 true true 2.0 /spring4upload
3. MultipartConfigElement
サーブレット初期化クラスを作成し、javax.servlet.MultipartConfigElement
を登録します
MyWebInitializer.java
package com.example; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; import javax.servlet.MultipartConfigElement; import javax.servlet.ServletRegistration; import java.io.File; public class MyWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { private int maxUploadSizeInMb = 5 * 1024 * 1024; // 5 MB @Override protected Class>[] getServletConfigClasses() { return new Class[]{SpringWebMvcConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } @Override protected Class>[] getRootConfigClasses() { return null; } @Override protected void customizeRegistration(ServletRegistration.Dynamic registration) { // upload temp file will put here File uploadDirectory = new File(System.getProperty("java.io.tmpdir")); // register a MultipartConfigElement MultipartConfigElement multipartConfigElement = new MultipartConfigElement(uploadDirectory.getAbsolutePath(), maxUploadSizeInMb, maxUploadSizeInMb * 2, maxUploadSizeInMb / 2); registration.setMultipartConfig(multipartConfigElement); } }
MultipartConfigElementメソッドシグネチャを確認します。
public MultipartConfigElement(java.lang.String location, long maxFileSize, long maxRequestSize, int fileSizeThreshold)
4. スプリング構成
multipartResolver
Beanを登録し、StandardServletMultipartResolver
を返します
SpringWebMvcConfig.java
package com.example; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.multipart.support.StandardServletMultipartResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @EnableWebMvc @Configuration @ComponentScan({"com.example"}) public class SpringWebMvcConfig extends WebMvcConfigurerAdapter { // Bean name must be "multipartResolver", by default Spring uses method name as bean name. @Bean public MultipartResolver multipartResolver() { return new StandardServletMultipartResolver(); } /* // if the method name is different, you must define the bean name manually like this : @Bean(name = "multipartResolver") public MultipartResolver createMultipartResolver() { return new StandardServletMultipartResolver(); }*/ @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/views/jsp/"); viewResolver.setSuffix(".jsp"); return viewResolver; } }
この段階で、Servlet 3.0マルチパートリクエスト解析が適切に構成され、ファイルのアップロードを開始できます。
4. 単一ファイルのアップロード
4.1 Normal HTML form tag.
upload.jsp
Spring MVC file upload example
4.2 Another page to show the upload status.
uploadStatus.jsp
Upload Status
Message : ${message}
4.3 In the Controller, map the uploaded file to MultipartFile
UploadController.java
package com.example.controller; import org.springframework.stereotype.Controller; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.StringJoiner; @Controller public class UploadController { //Save the uploaded file to this folder private static String UPLOADED_FOLDER = "F://temp//"; @GetMapping("/") public String index() { return "upload"; } //@RequestMapping(value = "/upload", method = RequestMethod.POST) @PostMapping("/upload") // //new annotation since 4.3 public String singleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) { if (file.isEmpty()) { redirectAttributes.addFlashAttribute("message", "Please select a file to upload"); return "redirect:uploadStatus"; } try { // Get the file and save it somewhere byte[] bytes = file.getBytes(); Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename()); Files.write(path, bytes); redirectAttributes.addFlashAttribute("message", "You successfully uploaded '" + file.getOriginalFilename() + "'"); } catch (IOException e) { e.printStackTrace(); } return "redirect:/uploadStatus"; } @GetMapping("/uploadStatus") public String uploadStatus() { return "uploadStatus"; } }
5. 複数ファイルアップロード
5.1 Just add more file input.
uploadMulti.jsp
Spring MVC multi files upload example
5.2 In Spring Controller, maps the multiple uploaded files to MultipartFile []
UploadController.java
//... @PostMapping("/uploadMulti") public String multiFileUpload(@RequestParam("files") MultipartFile[] files, RedirectAttributes redirectAttributes) { StringJoiner sj = new StringJoiner(" , "); for (MultipartFile file : files) { if (file.isEmpty()) { continue; //next pls } try { byte[] bytes = file.getBytes(); Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename()); Files.write(path, bytes); sj.add(file.getOriginalFilename()); } catch (IOException e) { e.printStackTrace(); } } String uploadedFileName = sj.toString(); if (StringUtils.isEmpty(uploadedFileName)) { redirectAttributes.addFlashAttribute("message", "Please select a file to upload"); } else { redirectAttributes.addFlashAttribute("message", "You successfully uploaded '" + uploadedFileName + "'"); } return "redirect:/uploadStatus"; } @GetMapping("/uploadMultiPage") public String uploadMultiPage() { return "uploadMulti"; } //...
6. 最大アップロードサイズを超えた場合の処理
一般的な最大アップロードサイズ超過例外を処理するために、@ControllerAdvice
を宣言し、MultipartException
をキャッチします
GlobalExceptionHandler.java
package com.example.exception; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.multipart.MultipartException; import org.springframework.web.servlet.mvc.support.RedirectAttributes; @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MultipartException.class) public String handleError1(MultipartException e, RedirectAttributes redirectAttributes) { redirectAttributes.addFlashAttribute("message", e.getCause().getMessage()); return "redirect:/uploadStatus"; } // For commons-fileupload solution /*@ExceptionHandler(MaxUploadSizeExceededException.class) public String handleError2(MaxUploadSizeExceededException e, RedirectAttributes redirectAttributes) { redirectAttributes.addFlashAttribute("message", e.getCause().getMessage()); return "redirect:/uploadStatus"; }*/ }
Tomcat Connection Reset
Tomcatにデプロイし、ファイルサイズ超過の例外をキャッチできない場合、TomcatのmaxSwallowSize
設定が原因である可能性があります。 これを読んでください–Spring file upload and connection reset issue
7. DEMO
以下のソースコードを入手して、組み込みのJettyサーバーmvn jetty:run
でテストしてください。
7.1 Review the pom.xml
above, the embedded Jetty will deploy the web application on this /spring4upload
context.
ターミナル
project $ mvn jetty:run //... [INFO] Started o.e.j.m.p.JettyWebAppContext@341672e{/spring4upload, file:/SpringMVCUploadExample/src/main/webapp/,AVAILABLE}{file:/SpringMVCUploadExample/src/main/webapp/} [WARNING] !RequestLog [INFO] Started ServerConnector@3ba1308d{HTTP/1.1}{0.0.0.0:8080} [INFO] Started @3743ms [INFO] Started Jetty Server [INFO] Starting scanner at interval of 10 seconds.
7.2 Access http://localhost:8080/spring4upload
7.3 Select a file ‘MyFirstExcel.xml‘ and upload it.
7.5 Select few files and upload it.
7.6 Select a file larger than 5mb, you will visit this page.
8. ソースコードをダウンロード
ダウンロード–spring-mvc-file-upload-example.zip(10 KB)
P.S For Spring 2.5.x, try this Spring.2.5-file-upload-example.zip (10KB)