Spring MVCファイルのアップロードの例
Springは、 `MultipartResolver`インタフェースを使用して、Webアプリケーションのファイルアップロードを処理します.2つの実装:
-
StandardServletMultipartResolver
– サーブレット3.0のマルチパートリクエスト
解析する。
-
CommonsMultipartResolver
– クラシックのcommons-fileupload.jar
この記事で使用されているツール:
-
Spring 4.3.5.RELEASE
-
Maven 3
-
Tomcat 7または8、Jetty 9または任意のServlet 3.0コンテナ
簡単に言えば、この記事では、Spring MVC Webアプリケーションでのファイルアップロードの処理方法と、一般的なmax exceededファイルサイズの例外を処理する方法について説明します。
P.S記事がSpring 2.5.xからSpring 4.3.x
に更新されました
1.プロジェクトの構成
標準のMavenプロジェクト構造。
プロジェクトの依存関係
標準のSpring依存性、ファイルアップロード用の余分なライブラリは不要です。
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4__0__0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mkyong</groupId> <artifactId>spring-mvc-file-upload</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>Spring MVC file upload</name> <properties> <jdk.version>1.8</jdk.version> <spring.version>4.3.5.RELEASE</spring.version> <jstl.version>1.2</jstl.version> <servletapi.version>3.1.0</servletapi.version> <logback.version>1.1.3</logback.version> <jcl.slf4j.version>1.7.12</jcl.slf4j.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <!-- compile only, deployed container will provide this --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servletapi.version}</version> <scope>provided</scope> </dependency> <!-- Logging --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${jcl.slf4j.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source>${jdk.version}</source> <target>${jdk.version}</target> </configuration> </plugin> <!-- embedded Jetty server, for testing --> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.2.11.v20150529</version> <configuration> <scanIntervalSeconds>10</scanIntervalSeconds> <webApp> <contextPath>/spring4upload</contextPath> </webApp> </configuration> </plugin> <!-- configure Eclipse workspace --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-eclipse-plugin</artifactId> <version>2.9</version> <configuration> <downloadSources>true</downloadSources> <downloadJavadocs>true</downloadJavadocs> <wtpversion>2.0</wtpversion> <wtpContextName>/spring4upload</wtpContextName> </configuration> </plugin> </plugins> </build> </project>
3. MultipartConfigElement
サーブレットイニシャライザクラスを作成し、 `javax.servlet.MultipartConfigElement`を登録します。
MyWebInitializer.java
package com.mkyong; 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`ビーンを登録し、
StandardServletMultipartResolver`を返します。
SpringWebMvcConfig.java
package com.mkyong; 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.mkyong"}) 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通常のHTMLフォームタグ。
upload.jsp
<html> <body> <h1>Spring MVC file upload example</h1> <form method="POST" action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data"> <input type="file" name="file"/><br/> <input type="submit" value="Submit"/> </form> </body> </html>
4.2アップロードステータスを表示する別のページ。
uploadStatus.jsp
<html> <body> <h1>Upload Status</h1> <h2>Message : ${message}</h2> </body> </html>
4.3コントローラで、アップロードしたファイルを `MultipartFile`にマップします。
UploadController.java
package com.mkyong.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ファイル入力を追加するだけです。
uploadMulti.jsp
<html> <body> <h1>Spring MVC multi files upload example</h1> <form method="POST" action="${pageContext.request.contextPath}/uploadMulti" enctype="multipart/form-data"> <input type="file" name="files"/><br/> <input type="file" name="files"/><br/> <input type="file" name="files"/><br/> <input type="submit" value="Submit"/> </form> </body> </html>
5.2 Spring Controllerでは、アップロードされた複数のファイルを
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.mkyong.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ファイルのアップロードと接続のリセットの問題
デモ
以下のソースコードを入手し、埋め込まれたJettyサーバ `mvn jetty:run`でテストしてください。
7.1上記の
pom.xml`を見てみると、埋め込まれたJettyはこの
/spring4upload`コンテキストにWebアプリケーションをデプロイします。
ターミナル
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.3ファイル ‘
MyFirstExcel.xml
‘を選択してアップロードします。
7.5いくつかのファイルを選択してアップロードします。
7.6 5MB以上のファイルを選択すると、このページにアクセスします。
8.ソースコードをダウンロードする
ダウンロード:
spring-mvc-file-upload-example.zip
(10 KB)
P.S Spring 2.5.xの場合、このリンクを試してください://wp-content/uploads/2010/08/SpringMVCForm-FileUpload-Example.zip[Spring.2.5-file-upload-example.zip](10KB)