`
dakulaliu
  • 浏览: 98055 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

简简单单-在Spring MVC中使用FileUpload功能

阅读更多
  先让我们来看一段摘自《Spring 2.5 Reference 中文版》(http://www.redsaga.com/spring_ref/2.5/spring-reference.pdf)的一段关于FileUpload的开场描述:
  "Spring支持web应用中的分段文件上传。这种支持是由即插即用的MultipartResolver来实现。这些解析器都定义在org.springframework.web.multipart包里。Sprig提供了现成的MultipartResolver可以支持Commons FileUpload(http://jakarta.apache.org/commons/fileupload)和COS FileUpload(http://www.servlets.ocm/cos)。"

是的,Spring通过配置一个分段上传解析器来完成对文件上传的解析和封装工作,那么Spring是如何完成这一工作的呢:

首先,DispatcherServlet必须找到一个文件上传解析器的实例,使用这个实例来检查本次请求的HttpServletRequest是否是一个分段文件上传的Request,通过下面的Spring 源码可以看到,首先必须保证有一个MultipartResolver的实例,并且由该类的Resolver的isMultipart方法来验证,本次Request是否为文件上传的Request.如果以上条件都满足,那么Spring将其转换为一个继承自HttpServletRequest的MultipartHttpServletRequest返回,这样在你的Controller中就可以使用这个经过转换的request,从中取到MultipartFile信息。
	protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
		if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
			if (request instanceof MultipartHttpServletRequest) {
				logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
						"this typically results from an additional MultipartFilter in web.xml");
			}
			else {
				return this.multipartResolver.resolveMultipart(request);
			}
		}
		// If not returned before: return original request.
		return request;
	}

由以上分析可以看出,我们必须配置一个MultipartResolver,在这里我们使用支持Commons FileUpload的CommonsMultipartResolver:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" p:defaultEncoding="utf-8"/>

而且我们可以在该Resolver中定义文件上传的最大长度:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" p:defaultEncoding="utf-8" p:maxUploadSize="100000"/>

当用户选择的上传文件大于maxUploadSize值的时候,commons fileupload会抛出一个异常MaxUploadSizeExceededException表示用户上传的文件超出了最大限制。

当然,我们可以通过Spring MVC中的ExceptionResolver来针对该异常定义一个显示错误的View,但针对有可能存在的多个文件上传Controller中都会发生文件大小超长这个异常的情况,除了我们自定义一个粒度更细的ExceptionResolver,我们还可以把上传文件合法性判断挪到用户自己的Controller中来做。而且我个人更偏向于后一种做法。

除了Spring Configuration之外,我们还需要准备一个页面上传的jsp文件供View视图使用:
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title>Insert title here</title>
	</head>
	
	<body style="text-align:left">
		<% if(request.getAttribute("success") != null) {%>
			Upload Successfully!!!<br/>
		<% }%>
		<form id="loginform" name="loginform" method="POST" enctype="multipart/form-data">
			<table width="100%" border="0" cellspacing="0" cellpadding="0">
				<tr>
					<td height="30" align="right">Choose File</td>
					<td align="left">
						<input name="imageFile" type="file"/>
					</td>
				</tr>
				<tr>
					<td align="center" colspan="2">
						<input type="submit" value="submit" name="submit" />
					</td>
				</tr>
			</table>
		</form>
	</body>
</html>

注意:在文件上传Form表单中,一定要将enctype设置为"multipart/form-data"因为只有这样才能使Spring知道这是一个文件上传的请求。

细心的读者也许能发现Form表单中action为默认值也就是说post到和上传页面同样的URL,因此我们定义了一个Controller分别来处理这个请求的GET和POST请求。下面让我们来看看这个Controller:

1.我们通过@Controller声明这个类为Spring组件,告知Spring容器在初始化的时候需要加载该类实例到Spring Context Container中。
2.通过@RequestMapping("/sec_upload.do")将sec_upload.do的请求指向该Controller处理。
@Controller
@RequestMapping("/sec_upload.do")
public class UploadController {
	//...
}

3.定义一个处理GET请求的方法,该方法简单的将选择文件Form表单页展现给用户:
@RequestMapping(method = RequestMethod.GET)
	public String handleUploadShow() {
		return "uploadView";
	}

4.定义一个处理POST请求的方法,该方法进行用户文件上传处理:
@RequestMapping(method = RequestMethod.POST)
	public String handleUploadProcess(
			@RequestParam("imageFile") MultipartFile file, Model model)
			throws Exception {
		//具体的业务逻辑操作。。。
		model.addAttribute("success", "true");
		return "uploadView";
	}

通过@RequestParam("imageFile")注解,Spring会将request请求中的imageFile的文件信息自动绑定到MultipartFile对象。

上面的Controller方法解决的文件绑定的问题,但假设我们的Form表单中除了文件选择框还有其他一些用户填写的信息,那么我们怎么处理呢?仿照上面的方法,我们可以为多个参数提供多个@RequestParam注解来完成数据绑定工作,但我们也可以通过MultipartHttpServletRequest对象来获取这些信息,因为在DispatcherServlet中Spring已经将一个普通的HttpServletRequest转换为了一个MultipartHttpServletRequest:
	@RequestMapping(method = RequestMethod.POST)
	public String handleAnotherUploadProcess(
			MultipartHttpServletRequest request, Model model) throws Exception {
		MultipartFile file = request.getFile("imageFile");
		//request.getParameter("xxx");
		//request.getContentType();
		//request.getContentLength();
		//some other processing...
		model.addAttribute("success", "true");
		return "uploadView";
	}


这种方式还是需要我们不断的通过request.getParameter("xxx")方式来获得参数,了解Spring MVC的同学可能想到了,使用CommandObject绑定-回答正确。假设我们定义了一个POJO对象:
public class BoUploadFile {
	private MultipartFile imageFile;

	public MultipartFile getImageFile() {
		return imageFile;
	}

	public void setImageFile(MultipartFile imageFile) {
		this.imageFile = imageFile;
	}

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

这个对象中不仅包括需要封装的上传文件信息,还包括其他一些用户输入的普通信息。那么有了这个封装对象,我们的Controller可以变成如下的样子:
	@RequestMapping(method = RequestMethod.POST)
	public String handleThirdUploadProcess(BoUploadFile uploadFile, Model model) throws Exception{
		MultipartFile file = uploadFile.getImageFile();
		//这里你可以通过uploadFile.getName()...等等获取用户输入的其他普通信息了。
		model.addAttribute("success", "true");
		return "uploadView";
	}


5.自定义一个文件验证类,来验证文件的合法性。
/**
 * 用户文件上传验证类
 * 
 * @author Jacky Lau created at 2008-8-27
 * @since 1.0
 * @version 1.0
 */
public class MultipartFileValidator {

	private final static long MAX_SIZE = 1024 * 1024;

	/**
	 * 文件大小上限
	 */
	private long maxSize = MAX_SIZE;

	/**
	 * 可接受的文件content-type
	 */
	private String[] allowedContentTypes;

	@PostConstruct
	public void afterPropertiesSet() {
		Assert
				.notEmpty(allowedContentTypes,
						"The content types allowed to be uploaded must contain one at least!");
	}

	/**
	 * 验证上传文件是否合法,如果不合法那么会抛出异常
	 * 
	 * @param file
	 *            用户上传的文件封装类
	 */
	public void validate(MultipartFile file) {
		Assert.notNull(file, "The multipart file is null!");
		if (file.getSize() > maxSize)
			throw new FileOutOfMaxLengthException("error.upload.outmaxlen",
					new Object[] { maxSize },
					"The file uploaded is out of max file size!");
		if (!ArrayUtils.contains(allowedContentTypes, file.getContentType()))
			throw new ContentTypeNotSupportException("error.upload.content.notsupported", null,
					"The content type '"+file .getContentType()+"' is not a valid content type !");
	}

	/**
	 * 设置文件上传大小上限
	 * 
	 * @param maxSize
	 *            文件上传大小上限
	 */
	public void setMaxSize(long maxSize) {
		this.maxSize = maxSize;
	}

	/**
	 * 设置可接受的文件content-type数组
	 * 
	 * @param allowedContentTypes
	 *            可接受的文件content-type数组
	 */
	public void setAllowedContentTypes(String[] allowedContentTypes) {
		this.allowedContentTypes = allowedContentTypes;
	}

}


这样我们可以通过这个validator判断上传的文件是否超出了最大限制,文件格式是否正确等判断。我们可以通过配置文件配置该验证器,在这里为了方便起见在类中我用以下方式来初始化该验证器:
	private MultipartFileValidator validator;

	@PostConstruct
	public void init() {
		validator = new MultipartFileValidator();
		validator.setAllowedContentTypes(new String[] { "image/jpeg",
				"image/pjpeg" });
	}


至此,我们已经完成了文件上传的开发,可以看出这和普通的Controller开发没有任何区别,简单而且灵活。以下是该Controller的全部代码:

@Controller
@RequestMapping("/sec_upload.do")
public class UploadController {

	private MultipartFileValidator validator;

	@PostConstruct
	public void init() {
		validator = new MultipartFileValidator();
		validator.setAllowedContentTypes(new String[] { "image/jpeg",
				"image/pjpeg" });
	}

	@RequestMapping(method = RequestMethod.GET)
	public String handleUploadShow() {
		return "uploadView";
	}

	@RequestMapping(method = RequestMethod.POST)
	public String handleUploadProcess(
			@RequestParam("imageFile") MultipartFile file, Model model)
			throws Exception {
		validator.validate(file);
		String path = "d:\\temp\\ftp\\" + file.getOriginalFilename();
		String resizePath = "d:\\temp\\ftp\\resize\\"
				+ file.getOriginalFilename();
		FileHelper.save(path, file.getBytes());
		if (ImageHelper.isJpg(ImageHelper.getImageType(path)))
			ImageHelper.resizeJPG(path, resizePath, 120, 118);
		model.addAttribute("success", "true");
		return "uploadView";
	}
}


在以后的文章中,我会对Spring进行上传文件特殊处理做一些探究,比如用户上传一个csv的通讯录文件,那么通过Spring的属性编辑器一个custom的Editor来进行数据转换,可以将CSV中的信息转换成其他你所需要的信息:比如从CSV文件中抽取邮件地址放到一个字符串数组中,让你可以进行后续的业务逻辑操作。。。

本文章的第二部分:http://dakulaliu.iteye.com/blog/260122
17
1
分享到:
评论
4 楼 huadongjin 2012-06-09  
SuperDence 写道
楼主写的很好,不过如果楼主能把源代码放出来那就更好了。ArrayUtils和FileHelper表示搞不定...



汗!!你没认真看楼主的代码啊,再说了ArrayUtils可是common包里面默认有的,FileHelper也只是个文件保存的工具类,自己实现就好了。
3 楼 SuperDence 2010-12-21  
楼主写的很好,不过如果楼主能把源代码放出来那就更好了。ArrayUtils和FileHelper表示搞不定...
2 楼 futurep_p 2010-01-13  
相当不错!!!
1 楼 aixinnature 2009-04-22  
好文,很有参考价值

相关推荐

    开发工具 commons-fileupload-1.3.2

    开发工具 commons-fileupload-1.3.2开发工具 commons-fileupload-1.3.2开发工具 commons-fileupload-1.3.2开发工具 commons-fileupload-1.3.2开发工具 commons-fileupload-1.3.2开发工具 commons-fileupload-1.3.2...

    commons-fileupload-1.2.2

    commons-fileupload-1.2.2commons-fileupload-1.2.2commons-fileupload-1.2.2commons-fileupload-1.2.2commons-fileupload-1.2.2commons-fileupload-1.2.2commons-fileupload-1.2.2commons-fileupload-1.2.2commons-...

    commons-fileupload-1.3.3&commons-fileupload-1.3.3架包和代码.rar

    标题中的"commons-fileupload-1.3.3&commons-fileupload-1.3.3架包和代码.rar"提到了Apache Commons FileUpload的1.3.3版本的库及其源码。Apache Commons FileUpload是一个Java库,专门用于处理HTTP协议中的多部分...

    commons commons-fileupload历史版本jar包集合

    commons-fileupload-1.0.zip commons-fileupload-1.1.1.zip commons-fileupload-1.1.zip commons-fileupload-1.2.1-bin.zip commons-fileupload-1.3.1-bin.zip commons-fileupload-1.3.1-src.zip commons-fileupload...

    Spring MVC所需jar包

    5. **JSTL(JavaServer Pages Standard Tag Library)**:`jstl.jar` 和 `javax.servlet.jsp.jstl.jar` 用于在 JSP 页面中使用标准标签库,简化页面逻辑,提高开发效率。 6. **Apache Commons**:Spring MVC 开发中...

    8-Spring-mvc-文件上传1

    在Spring MVC框架中,文件上传是一项常见的功能,它允许用户通过Web表单上传文件到服务器。Spring MVC通过集成Apache Commons FileUpload库实现了这一功能。在本文中,我们将深入探讨如何配置和使用Spring MVC进行...

    commons-fileupload-1.4-API文档-中文版.zip

    赠送jar包:commons-fileupload-1.4.jar; 赠送原API文档:commons-fileupload-1.4-javadoc.jar; 赠送源代码:commons-fileupload-1.4-sources.jar; 赠送Maven依赖信息文件:commons-fileupload-1.4.pom; 包含...

    Spring MVC 文件上传下载 后端 - Java.zip

    在Spring MVC框架中,文件上传和下载是常见的功能需求,特别是在构建Web应用程序时。这个压缩包文件"Spring MVC 文件上传下载 后端 - Java.zip"包含的文档可能详细阐述了如何在Java后端实现这些功能。以下是关于...

    commons-fileupload-1.3.3-API文档-中文版.zip

    赠送jar包:commons-fileupload-1.3.3.jar; 赠送原API文档:commons-fileupload-1.3.3-javadoc.jar; 赠送源代码:commons-fileupload-1.3.3-sources.jar; 赠送Maven依赖信息文件:commons-fileupload-1.3.3.pom;...

    Spring Mvc 应用Jar包

    - 压缩包中可能包含了`commons-fileupload.jar`和`commons-io.jar`:这两个Apache Commons库提供了处理HTTP请求中文件上传的功能,Spring MVC通过它们来支持文件上传操作。 4. **日志库** - 虽然提到无需导入...

    commons-fileupload-1.3.3.jar和commons-io-2.6.jar

    在Java开发中,上传文件是一项常见的任务,而`commons-fileupload-1.3.3.jar`和`commons-io-2.6.jar`是Apache Commons项目中的两个重要库,专门用于处理HTTP请求中的文件上传功能。这两个库为开发者提供了便捷、高效...

    spring mvc框架需要用到的jar包

    以下将详细阐述这些关键jar包的作用及其在Spring MVC中的重要性。 1. **spring-webmvc.jar**:这是Spring MVC的核心库,包含了处理HTTP请求、控制器注解、视图解析等核心功能。它提供了一个DispatcherServlet,它是...

    commons-fileupload commons-fileupload-1.2.1-bin

    commons-fileupload-1.2.1-bin commons-fileupload 文件上传 commons-fileupload-1.2.1-bin commons-fileupload 文件上传 jar包 及相关文档

    Spring MVC 4.2.4.RELEASE 中文文档

    HTTP 缓存支持是关于如何在 Spring MVC 中使用 HTTP 缓存控制头,如 Cache-Control、ETag 和 Last-Modified,以及如何对静态资源进行缓存处理。控制器类名-处理器映射 ControllerClassNameHandlerMapping 是一种基于...

    commons-fileupload-1.3.2.jar

    在本文中,我们将深入探讨Apache Commons FileUpload库的核心功能、特性以及如何在实际项目中使用它。 Apache Commons FileUpload库解决了Java Web应用中一个常见问题:处理通过表单提交的大文件。在HTTP协议中,...

    commons-fileupload-1.4-bin.zip

    5. **使用示例**:在Servlet中使用FileUpload通常涉及以下步骤: - 创建`DiskFileItemFactory`实例,设置内存阈值和临时目录。 - 使用`DiskFileItemFactory`创建`ServletFileUpload`实例。 - 调用`...

    Expert Spring MVC

    《Expert Spring MVC and Web Flow》这本书还介绍了 Spring MVC 与 Spring Web Flow 的结合使用,Spring Web Flow 是一个用于构建复杂 Web 应用程序的框架,它可以处理复杂的交互式对话流程。 - **Web Flow** 提供...

    Spring mvc工程所需jar包资源

    在Spring MVC中,通常会将DispatcherServlet配置在Web应用的上下文中。 4. **Spring AOP**: 支持面向切面编程,可以方便地实现日志记录、事务管理等功能。 5. **Spring JDBC**: 提供了与数据库交互的抽象层,简化...

    关于Spring MVC项目(maven)中通过fileupload上传文件

    在本场景中,我们关注的是使用Maven构建的Spring MVC项目,并涉及到`commons-fileupload`和`commons-io`这两个库,它们是Java中处理文件上传的核心工具。以下是关于这个主题的详细知识点: 1. **Spring MVC**: ...

    fileUpload组件所需jar包

    1. **添加依赖**:在使用FileUpload组件之前,需要将其jar包引入到项目中。提供的压缩包文件"fileupload"很可能包含了这个必要的库。在Maven项目中,可以将以下依赖添加到pom.xml文件: ```xml &lt;groupId&gt;commons-...

Global site tag (gtag.js) - Google Analytics