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

2021-07-20 06:05

阅读:546

YPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">

简短的概述

在这篇文章中,我们将使用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 部分,如下图所示:
        SpringDispatcherorg.springframework.web.servlet.DispatcherServlet/tmp5242880209715200
  • 方案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.

项目结构

技术分享图片

在pom.xml声明依赖关系
4.0.0com.yiibai.springmvc
	Spring4MVCFileUploadMultipartFile
	war1.0.0Spring4MVCFileUploadMultipartFile Maven Webapphttp://maven.apache.org4.2.0.RELEASEorg.springframework
			spring-webmvc
			${springframework.version}javax.validation
			validation-api
			1.1.0.Finaljavax.servlet
			javax.servlet-api
			3.1.0javax.servlet
			jstl
			1.2org.apache.maven.plugins
					maven-war-plugin
					2.4src/main/webappSpring4MVCFileUploadMultipartFilefalseSpring4MVCFileUploadMultipartFile
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格式配置类将是:
messages/WEB-INF/views/.jsp
创建模型类

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 files = new ArrayList();
	
	public MultiFileBucket(){
		files.add(new FileBucket());
		files.add(new FileBucket());
		files.add(new FileBucket());
	}
	
	public List getFiles() {
		return files;
	}

	public void setFiles(List 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 fileNames = new ArrayList();
			// 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

Spring 4 MVC File Upload Example

Spring 4 MVC File Upload Example

Home

success.jsp




	File Upload Success
File ${fileName} uploaded successfully.

Home

multiFileUploader.jsp






	Spring 4 MVC File Multi Upload Example

Spring 4 MVC Multi File Upload Example



Home

multiSuccess.jsp




	File Upload Success
File ${fileName} uploaded successfully

Home

welcome.jsp





	Spring 4 MVC File Upload Example

Welcome to FileUploader Example

Click on below links to see FileUpload in action.

Single File Upload OR Multi File Upload
构建,部署和运行应用程序

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

打开浏览器,浏览 http://localhost:8080/Spring4MVCFileUploadMultipart/

技术分享图片

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

技术分享图片

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

技术分享图片

单击选择文件。

技术分享图片

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

技术分享图片

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

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

技术分享图片

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

技术分享图片

选择要上传的文件。

技术分享图片

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

技术分享图片

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

技术分享图片


评论


亲,登录后才可以留言!