Spring MVC4使用Servlet3 MultiPartConfigElement文件上传实例

广告位

在这篇文章中,我们将使用Spring MultipartResolver 实现 StandardSe…

在这篇文章中,我们将使用Spring MultipartResolver 实现 StandardServletMultipartResolver在Servlet3环境中实现单点和多文件上传功能。Spring提供了内置的multipart支持来处理Web应用程序文件上传。

简短的概述

在这篇文章中,我们将使用Servlet3.0以及javax.servlet.MultipartConfigElement,为了激活 Servlet3.0环境和Spring 的Multipart支持,你需要做以下:

1.添加 StandardServletMultipartResolver Bean 在 Spring 配置。这是一个标准实现 MultipartResolver 接口,基于Servlet3.0 javax.servlet.http.Part API。

2. 启用在Servlet3.0环境的多解析(MultiParsing)。要做到这一点,你有多种方案可供选择。

  • 方案A. 对方案性 Servlet 注册设置 javax.servlet.MultipartConfigElement。MultipartConfigElement是javax.servlet.annotation.MultipartConfig 的注释值(如选择C所述)的简单Java类表示。 这篇文章将特别侧重于这个选择。
  • 方案B. 如果您使用基于XML的配置,可以在web.xml中在servlet配置声明 multipart-configsection 部分,如下图所示:
        <servlet>          <servlet-name>SpringDispatcher</servlet-name>          <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>          <multipart-config>              <location>/tmp</location>              <max-file-size>5242880</max-file-size><!--5MB-->              <max-request-size>20971520</max-request-size><!--20MB-->              <file-size-threshold>0</file-size-threshold>          </multipart-config>      </servlet>
  • 方案C. 可以创建一个自定义 Servlet 和 javax.servlet.annotation.MultipartConfig 标注其标注,如下图所示:
    @WebServlet(name = "fileUploadServlet", urlPatterns = {"/upload"})  @MultipartConfig(location=/tmp,                   fileSizeThreshold=0,                       maxFileSize=5242880,       // 5 MB                   maxRequestSize=20971520)   // 20 MB  public class FileUploadServlet extends HttpServlet {          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {          //handle file upload      } 
话虽这么说,我们将专注于在这个例子中选择。

完整的例子

使用以下技术:
  • Spring 4.2.0.RELEASE
  • validation-api 1.1.0.Final
  • Bootstrap v3.3.2
  • Maven 3
  • JDK 1.7
  • Tomcat 8.0.21
  • Eclipse JUNO Service Release 2

Let’s begin.

项目结构

Spring MVC4使用Servlet3 MultiPartConfigElement文件上传实例

在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.yiibai.springmvc</groupId>  	<artifactId>Spring4MVCFileUploadMultipartFile</artifactId>  	<packaging>war</packaging>  	<version>1.0.0</version>  	<name>Spring4MVCFileUploadMultipartFile Maven Webapp</name>  	<url>http://maven.apache.org</url>    	<properties>  		<springframework.version>4.2.0.RELEASE</springframework.version>  	</properties>    	<dependencies>  		<dependency>  			<groupId>org.springframework</groupId>  			<artifactId>spring-webmvc</artifactId>  			<version>${springframework.version}</version>  		</dependency>    		<dependency>  			<groupId>javax.validation</groupId>  			<artifactId>validation-api</artifactId>  			<version>1.1.0.Final</version>  		</dependency>    		<dependency>  			<groupId>javax.servlet</groupId>  			<artifactId>javax.servlet-api</artifactId>  			<version>3.1.0</version>  		</dependency>  		<dependency>  			<groupId>javax.servlet</groupId>  			<artifactId>jstl</artifactId>  			<version>1.2</version>  		</dependency>  	</dependencies>      	<build>  		<pluginManagement>  			<plugins>  				<plugin>  					<groupId>org.apache.maven.plugins</groupId>  					<artifactId>maven-war-plugin</artifactId>  					<version>2.4</version>  					<configuration>  						<warSourceDirectory>src/main/webapp</warSourceDirectory>  						<warName>Spring4MVCFileUploadMultipartFile</warName>  						<failOnMissingWebXml>false</failOnMissingWebXml>  					</configuration>  				</plugin>  			</plugins>  		</pluginManagement>    		<finalName>Spring4MVCFileUploadMultipartFile</finalName>  	</build>  </project>     

MultiPartConfigElement的编程注册

这个注册提供一个配置,以设置像最大文件大小,请求大小,位置和门限值。文件上传操作期间暂时存储在磁盘上的特定属性。
package com.yiibai.springmvc.configuration;    import javax.servlet.MultipartConfigElement;  import javax.servlet.ServletRegistration;    import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;    public class HelloWorldInitializer extends  		AbstractAnnotationConfigDispatcherServletInitializer {    	@Override  	protected Class<?>[] getRootConfigClasses() {  		return new Class[] { HelloWorldConfiguration.class };  	}    	@Override  	protected Class<?>[] getServletConfigClasses() {  		return null;  	}    	@Override  	protected String[] getServletMappings() {  		return new String[] { "/" };  	}    	@Override  	protected void customizeRegistration(ServletRegistration.Dynamic registration) {  		registration.setMultipartConfig(getMultipartConfigElement());  	}    	private MultipartConfigElement getMultipartConfigElement() {  		MultipartConfigElement multipartConfigElement = new MultipartConfigElement(	LOCATION, MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD);  		return multipartConfigElement;  	}    	private static final String LOCATION = "C:/temp/"; // Temporary location where files will be stored    	private static final long MAX_FILE_SIZE = 5242880; // 5MB : Max file size.  														// Beyond that size spring will throw exception.  	private static final long MAX_REQUEST_SIZE = 20971520; // 20MB : Total request size containing Multi part.  	  	private static final int FILE_SIZE_THRESHOLD = 0; // Size threshold after which files will be written to disk  } 
请注意,我们如何才能注册所需的 MultiPartConfigElement 到 DispatcherServlet 的重写函数 customizeRegistration。

创建配置

配置StandardServletMultipartResolver Bean。这是一个标准实现MultipartResolver接口,基于Servlet3.0 javax.servlet.http.Part API。

package com.yiibai.springmvc.configuration;    import org.springframework.context.MessageSource;  import org.springframework.context.annotation.Bean;  import org.springframework.context.annotation.ComponentScan;  import org.springframework.context.annotation.Configuration;  import org.springframework.context.support.ResourceBundleMessageSource;  import org.springframework.web.multipart.support.StandardServletMultipartResolver;  import org.springframework.web.servlet.config.annotation.EnableWebMvc;  import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;  import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;  import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;  import org.springframework.web.servlet.view.InternalResourceViewResolver;  import org.springframework.web.servlet.view.JstlView;    @Configuration  @EnableWebMvc  @ComponentScan(basePackages = "com.yiibai.springmvc")  public class HelloWorldConfiguration extends WebMvcConfigurerAdapter {    	@Bean(name = "multipartResolver")  	public StandardServletMultipartResolver resolver() {  		return new StandardServletMultipartResolver();  	}    	@Override  	public void configureViewResolvers(ViewResolverRegistry registry) {  		InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();  		viewResolver.setViewClass(JstlView.class);  		viewResolver.setPrefix("/WEB-INF/views/");  		viewResolver.setSuffix(".jsp");  		registry.viewResolver(viewResolver);  	}    	@Bean  	public MessageSource messageSource() {  		ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();  		messageSource.setBasename("messages");  		return messageSource;  	}    	@Override  	public void addResourceHandlers(ResourceHandlerRegistry registry) {  		registry.addResourceHandler("/static/**").addResourceLocations( "/static/");  	}    } 
以XML格式配置类将是:
<beans xmlns="http://www.springframework.org/schema/beans"      xmlns:context="http://www.springframework.org/schema/context"      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xmlns:mvc="http://www.springframework.org/schema/mvc"      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd      http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">         <context:component-scan base-package="com.yiibai.springmvc" />      <mvc:annotation-driven />        <bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>        <mvc:resources mapping="/static/**" location="/static/" />      <mvc:default-servlet-handler />          <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">          <property name="basename">              <value>messages</value>          </property>      </bean>          <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">          <property name="prefix">              <value>/WEB-INF/views/</value>          </property>          <property name="suffix">              <value>.jsp</value>          </property>      </bean>  </beans> 

创建模型类

Spring提供 org.springframework.web.multipart.MultipartFile, 这是一个 multipart 请求获得上传文件的表示。 它提供了方便的方法,如getName(),getContentType(),GetBytes(),getInputStream()等。这让我们处理更容易一点,同时检索有关被上传文件的信息。

让我们写一个包装类,进一步简化我们应用程序的使用。
package com.yiibai.springmvc.model;    import org.springframework.web.multipart.MultipartFile;    public class FileBucket {    	MultipartFile file;  	  	public MultipartFile getFile() {  		return file;  	}    	public void setFile(MultipartFile file) {  		this.file = file;  	}  } 
为了展示Multiple上传的例子,让我们再创建一个包装类。
package com.yiibai.springmvc.model;    import java.util.ArrayList;  import java.util.List;    public class MultiFileBucket {    	List<FileBucket> files = new ArrayList<FileBucket>();  	  	public MultiFileBucket(){  		files.add(new FileBucket());  		files.add(new FileBucket());  		files.add(new FileBucket());  	}  	  	public List<FileBucket> getFiles() {  		return files;  	}    	public void setFiles(List<FileBucket> files) {  		this.files = files;  	}  } 
这个类可以处理多达3个文件上传。

创建控制器

package com.yiibai.springmvc.controller;    import java.io.File;  import java.io.IOException;  import java.util.ArrayList;  import java.util.List;    import javax.validation.Valid;    import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.stereotype.Controller;  import org.springframework.ui.ModelMap;  import org.springframework.util.FileCopyUtils;  import org.springframework.validation.BindingResult;  import org.springframework.web.bind.WebDataBinder;  import org.springframework.web.bind.annotation.InitBinder;  import org.springframework.web.bind.annotation.RequestMapping;  import org.springframework.web.bind.annotation.RequestMethod;  import org.springframework.web.multipart.MultipartFile;    import com.yiibai.springmvc.model.FileBucket;  import com.yiibai.springmvc.model.MultiFileBucket;  import com.yiibai.springmvc.util.FileValidator;  import com.yiibai.springmvc.util.MultiFileValidator;    @Controller  public class FileUploadController {    	private static String UPLOAD_LOCATION="C:/mytemp/";    	@Autowired  	FileValidator fileValidator;    	@Autowired  	MultiFileValidator multiFileValidator;    	@InitBinder("fileBucket")  	protected void initBinderFileBucket(WebDataBinder binder) {  		binder.setValidator(fileValidator);  	}    	@InitBinder("multiFileBucket")  	protected void initBinderMultiFileBucket(WebDataBinder binder) {  		binder.setValidator(multiFileValidator);  	}    	@RequestMapping(value = { "/", "/welcome" }, method = RequestMethod.GET)  	public String getHomePage(ModelMap model) {  		return "welcome";  	}    	@RequestMapping(value = "/singleUpload", method = RequestMethod.GET)  	public String getSingleUploadPage(ModelMap model) {  		FileBucket fileModel = new FileBucket();  		model.addAttribute("fileBucket", fileModel);  		return "singleFileUploader";  	}    	@RequestMapping(value = "/singleUpload", method = RequestMethod.POST)  	public String singleFileUpload(@Valid FileBucket fileBucket,  			BindingResult result, ModelMap model) throws IOException {    		if (result.hasErrors()) {  			System.out.println("validation errors");  			return "singleFileUploader";  		} else {  			System.out.println("Fetching file");  			MultipartFile multipartFile = fileBucket.getFile();    			// Now do something with file...  			FileCopyUtils.copy(fileBucket.getFile().getBytes(), new File( UPLOAD_LOCATION + fileBucket.getFile().getOriginalFilename()));  			String fileName = multipartFile.getOriginalFilename();  			model.addAttribute("fileName", fileName);  			return "success";  		}  	}    	@RequestMapping(value = "/multiUpload", method = RequestMethod.GET)  	public String getMultiUploadPage(ModelMap model) {  		MultiFileBucket filesModel = new MultiFileBucket();  		model.addAttribute("multiFileBucket", filesModel);  		return "multiFileUploader";  	}    	@RequestMapping(value = "/multiUpload", method = RequestMethod.POST)  	public String multiFileUpload(@Valid MultiFileBucket multiFileBucket,  			BindingResult result, ModelMap model) throws IOException {    		if (result.hasErrors()) {  			System.out.println("validation errors in multi upload");  			return "multiFileUploader";  		} else {  			System.out.println("Fetching files");  			List<String> fileNames = new ArrayList<String>();  			// Now do something with file...  			for (FileBucket bucket : multiFileBucket.getFiles()) {  				FileCopyUtils.copy(bucket.getFile().getBytes(), new File(UPLOAD_LOCATION + bucket.getFile().getOriginalFilename()));  				fileNames.add(bucket.getFile().getOriginalFilename());  			}    			model.addAttribute("fileNames", fileNames);  			return "multiSuccess";  		}  	}    }   

以上控制器是相当微不足道。它处理上传视图的GET和POST请求的文件。当文件从文件选择器,用户选择点击上传,我们只是创建具有相同的名称和字节的内容作为原始文件的新文件,从原始复制文件的字节数。为此,我们正在使用Spring FileCopyUtils工具类流从源复制到目的地。在这个例子中,我们指定的目的地是 C:/mytemp 文件夹,所有文件将存在这个文件夹中。

创建验证类

我们使用的是一些验证,以验证用户确实选择了要上传的文件。它们如下所示。
package com.yiibai.springmvc.util;    import org.springframework.stereotype.Component;  import org.springframework.validation.Errors;  import org.springframework.validation.Validator;    import com.yiibai.springmvc.model.FileBucket;    @Component  public class FileValidator implements Validator {  	  	public boolean supports(Class<?> clazz) {  		return FileBucket.class.isAssignableFrom(clazz);  	}    	public void validate(Object obj, Errors errors) {  		FileBucket file = (FileBucket) obj;  		  		if(file.getFile()!=null){  			if (file.getFile().getSize() == 0) {  				errors.rejectValue("file", "missing.file");  			}  		}  	}  } 
package com.yiibai.springmvc.util;    import org.springframework.stereotype.Component;  import org.springframework.validation.Errors;  import org.springframework.validation.Validator;    import com.yiibai.springmvc.model.FileBucket;  import com.yiibai.springmvc.model.MultiFileBucket;    @Component  public class MultiFileValidator implements Validator {  	  	public boolean supports(Class<?> clazz) {  		return MultiFileBucket.class.isAssignableFrom(clazz);  	}    	public void validate(Object obj, Errors errors) {  		MultiFileBucket multiBucket = (MultiFileBucket) obj;  		  		int index=0;  		  		for(FileBucket file : multiBucket.getFiles()){  			if(file.getFile()!=null){  				if (file.getFile().getSize() == 0) {  					errors.rejectValue("files["+index+"].file", "missing.file");  				}  			}  			index++;  		}  		  	}  } 

messages.properties

missing.file= Please select a file. 

创建视图

singleFileUploader.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>  <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>  <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>  <html>    <head>  	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">  	<title>Spring 4 MVC File Upload Example</title>  	<link href="<c:url value='/static/css/bootstrap.css' />"  rel="stylesheet" type="text/css"></link>  	<link href="<c:url value='/static/css/app.css' />" rel="stylesheet" type="text/css"></link>  </head>  <body>     	<div class="form-container">  		<h1>Spring 4 MVC File Upload Example </h1>  		<form:form method="POST" modelAttribute="fileBucket" enctype="multipart/form-data" class="form-horizontal">  		  			<div class="row">  				<div class="form-group col-md-12">  					<label class="col-md-3 control-lable" for="file">Upload a file</label>  					<div class="col-md-7">  						<form:input type="file" path="file" id="file" class="form-control input-sm"/>  						<div class="has-error">  							<form:errors path="file" class="help-inline"/>  						</div>  					</div>  				</div>  			</div>  	  			<div class="row">  				<div class="form-actions floatRight">  					<input type="submit" value="Upload" class="btn btn-primary btn-sm">  				</div>  			</div>  		</form:form>  		<a href="<c:url value='/welcome' />">Home</a>  	</div>  </body>  </html> 

success.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>  <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>  <html>  <head>  	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">  	<title>File Upload Success</title>  	<link href="<c:url value='/static/css/bootstrap.css' />" rel="stylesheet"></link>  	<link href="<c:url value='/static/css/app.css' />" rel="stylesheet"></link>  </head>  <body>  	<div class="success">  		File  <strong>${fileName}</strong> uploaded successfully.  		<br/><br/>  		<a href="<c:url value='/welcome' />">Home</a>	  	</div>  </body>  </html> 

multiFileUploader.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>  <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>  <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>  <html>    <head>  	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">  	<title>Spring 4 MVC File Multi Upload Example</title>  	<link href="<c:url value='/static/css/bootstrap.css' />"  rel="stylesheet" type="text/css"></link>  	<link href="<c:url value='/static/css/app.css' />" rel="stylesheet" type="text/css"></link>  </head>  <body>     	<div class="form-container">  		<h1>Spring 4 MVC Multi File Upload Example </h1>  		<form:form method="POST" modelAttribute="multiFileBucket" enctype="multipart/form-data" class="form-horizontal">  		  			<c:forEach var="v" varStatus="vs" items="${multiFileBucket.files}">  				<form:input type="file" path="files[${vs.index}].file" id="files[${vs.index}].file" class="form-control input-sm"/>  				<div class="has-error">  					<form:errors path="files[${vs.index}].file" class="help-inline"/>  				</div>  			</c:forEach>  			<br/>  			<div class="row">  				<div class="form-actions floatRight">  					<input type="submit" value="Upload" class="btn btn-primary btn-sm">  				</div>  			</div>  		</form:form>  		  		<br/>  		<a href="<c:url value='/welcome' />">Home</a>  	</div>  </body>  </html> 

multiSuccess.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>  <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>  <html>  <head>  	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">  	<title>File Upload Success</title>  	<link href="<c:url value='/static/css/bootstrap.css' />" rel="stylesheet"></link>  	<link href="<c:url value='/static/css/app.css' />" rel="stylesheet"></link>  </head>  <body>  	<div class="success">  			<c:forEach var="fileName" items="${fileNames}">  				File  <strong>${fileName}</strong> uploaded successfully<br/>  			</c:forEach>  			<br/>  		<a href="<c:url value='/welcome' />">Home</a>  	</div>  </body>  </html> 

welcome.jsp

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>  <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>  <html>    <head>  	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">  	<title>Spring 4 MVC File Upload Example</title>  	<link href="<c:url value='/static/css/bootstrap.css' />"  rel="stylesheet"></link>  	<link href="<c:url value='/static/css/app.css' />" rel="stylesheet"></link>  </head>  <body>  	<div class="form-container">  		<h1>Welcome to FileUploader Example</h1>  		  		Click on below links to see FileUpload in action.<br/><br/>  		  		<a href="<c:url value='/singleUpload' />">Single File Upload</a>  OR  <a href="<c:url value='multiUpload' />">Multi File Upload</a>  	</div>   </body>  </html> 

构建,部署和运行应用程序

现在构建 war(前面的Eclipse教程)或通过Maven的命令行( mvn clean install).部署 war 到Servlet3.0容器。

打开浏览器,浏览 

Spring MVC4使用Servlet3 MultiPartConfigElement文件上传实例

现在点击单个文件上传的链接。

Spring MVC4使用Servlet3 MultiPartConfigElement文件上传实例

点击上传,而不是选择一个文件。它应该显示验证失败消息。

Spring MVC4使用Servlet3 MultiPartConfigElement文件上传实例

单击选择文件。

Spring MVC4使用Servlet3 MultiPartConfigElement文件上传实例

应显示文件选择器。选择一个文件。
点击上传。开始上传文件。

Spring MVC4使用Servlet3 MultiPartConfigElement文件上传实例

您可以查看上传的文件夹 [C:/mytemp] 对于上传的文件。 

现在回去,然后点击 multiupload 链接。

Spring MVC4使用Servlet3 MultiPartConfigElement文件上传实例

点击上传没有任何文件的选择,会收到验证错误。

Spring MVC4使用Servlet3 MultiPartConfigElement文件上传实例

选择要上传的文件。

Spring MVC4使用Servlet3 MultiPartConfigElement文件上传实例

点击上传。所有选中的文件都会被上传。

Spring MVC4使用Servlet3 MultiPartConfigElement文件上传实例

最后,查看存储文件夹 [C:/mytemp].

Spring MVC4使用Servlet3 MultiPartConfigElement文件上传实例

所有步骤完成,就讲解到这里,包教不包会!

代码下载:

  

拾荒的老头

关于作者: 拾荒的老头

为您推荐

广告位

发表评论