简介
在用spring mvc做web开发的时候,有一个很典型的任务就是上传文件。 它的实现相对比较简单,可以说有固定的套路可以使用。当然,对于文件的上传以及管理在具体应用中还是相对比较复杂的,需要根据具体的情况来分析。目前来说,针对具体应用所使用的servlet容器版本,有两种常见的文件上传实现方法。一种是使用CommonsMultipartResolver,另外一种是StandardServletMultipartResolver。但是StandardServletMultipartResolver仅适用于servlet3.0及以上的容器中。我们针对两种的具体实现做一个分析讨论。
commons multipart resolver
CommonsMultipartResolver相对来说可以适用于比较老一点的servlet容器版本。它的具体实现有对第三方的库的依赖。如果需要使用这种方式,需要在依赖文件里定义如下的内容:
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency>
我们其他部分和前面文章中定义的项目类似。首先,我们定义的domain model对象如下:
public class Product { private Long id; private String productId; private String name; private BigDecimal unitPrice; private String description; private String manufacturer; private String category; private long unitsInStock; private long unitsInOrder; private boolean discontinued; private String condition; private MultipartFile productImage; public Product() { super(); } public Product(String productId, String name, BigDecimal unitPrice) { this.productId = productId; this.name = name; this.unitPrice = unitPrice; } }
这里省略了部分内容。 另外,为了使得前面的multipartresolver生效,我们还需要修改dispatcher-servlet.xml文件,里面需要添加的内容如下:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10240000"/> </bean>
上述内容里定义了上传文件的大小限制,比如这里的大小是1M。我们可以根据具体的需要来调整。
现在定义提交内容的表单页面:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <spring:message var="productIdLabel" code="addProduct.form.productId.label"/> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"> <title>Products</title> </head> <body> <section> <div class="jumbotron"> <div class="container"> <h1>Products</h1> <p>Add products</p> </div> </div> </section> <section class="container"> <form:form modelAttribute="newProduct" class="form-horizontal" enctype="multipart/form-data"> <fieldset> <legend>Add new product</legend> <form:errors path="*" cssClass="alert alert-danger" element="div"/> <div class="form-group"> <label class="control-label col-lg-2 col-lg-2" for="productId"><spring:message code="addProduct.form.productId.label"/></label> <div class="col-lg-10"> <form:input id="productId" path="productId" type="text" class="form:input-large"/> <form:errors path="productId" cssClass="text-danger"/> </div> </div> <div class="form-group"> <label class="control-label col-lg-2" for="productImage"><spring:message code="addProduct.form.productImage.label"/></label> <div class="col-lg-10"> <form:input id="productImage" path="productImage" type="file" class="form:input-large" /> </div> </div> <div class="form-group"> <div class="col-lg-offset-2 col-lg-10"> <input type="submit" id="btnAdd" class="btn btn-primary" value ="Add"/> </div> </div> </fieldset> </form:form> </section> </body> </html>
出于篇幅的考虑,这里省略了部分内容。上述部分的要点在于对表单的定义部分,<form:form modelAttribute="newProduct" class="form-horizontal" enctype="multipart/form-data"> 这里多了一个enctype="multipart/form-data"的定义,表示提交的内容包含有multipart内容,也就是说包含有文件相关的内容。然后,在productImage的部分也有如下的定义:<form:input id="productImage" path="productImage" type="file" class="form:input-large" />。 它表示输入的是文件类型。
在定义好提交表单后,剩下的就是定义处理表单数据的controller了。它的实现如下:
@Controller @RequestMapping("/products") public class ProductController { @RequestMapping(value = "/add", method = RequestMethod.POST) public String processAddNewProductForm(@ModelAttribute("newProduct") @Valid Product productToBeAdded, BindingResult result) { if(result.hasErrors()) { return "addProduct"; } MultipartFile productImage = productToBeAdded.getProductImage(); if (productImage!=null && !productImage.isEmpty()) { try { productImage.transferTo(new File("/home/frank/" + productToBeAdded.getProductId() + ".png")); } catch (Exception e) { throw new RuntimeException("Product Image saving failed", e); } } return "redirect:/products"; } }
在processAddNewProductForm方法中,由于前面的表单绑定属性,这里就将得到MultipartFile的对象,productImage。由于MultipartFile有一个transferTo方法。于是只需要在transferTo方法里传入一个File对象就可以了。具体的实现可以参照附件里的uploadfile工程。
standard servlet multipart resolver
上述的方法虽然足够通用,但是在新的servlet容器里,实现上传文件的方法可以更加简单。它不需要有对第三方库的依赖。这种新的方法需要做的修改如下。
首先在web.xml里增加如下部分的定义内容:
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/spring/dispatcher-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <multipart-config> <location>/home/frank/Documents</location> <max-file-size>2097152</max-file-size> <max-request-size>4194304</max-request-size> </multipart-config> </servlet>
这里定义了上传文件的一些配置信息,比如上传的文件大小为2M,而发送请求的内容长度为4M。甚至这里也可以配置文件上传的路径。
在这一步配置好之后,后面需要定义的是上传内容的表单,这里仅仅列出和上面示例不同的地方:
<div class="form-group"> <label class="control-label col-lg-2" for="productImage"><spring:message code="addProduct.form.productImage.label"/></label> <div class="col-lg-10"> <input id="productImage" name="productImage" type="file" class="form:input-large" /> </div> </div>
这部分的内容和普通的html表单的定义一样,并没有使用spring taglib form。所以这里提交的字段productImage不会自动绑定到domain model中。在domain model定义中,我们可以去掉productImage的定义。这种方式有一个好处,就是有时候我们不需要将领域对象模型和需要上传的对象内容直接关联起来。但是在提交表单的时候又需要将它们放在一起处理。
下面剩下的就是定义处理这个表单的controller:
@Controller @RequestMapping("/products") public class ProductController { @RequestMapping(value = "/add", method = RequestMethod.POST) public String processAddNewProductForm(@ModelAttribute("newProduct") Product productToBeAdded, @RequestPart("productImage") MultipartFile productImage, BindingResult result) { if(result.hasErrors()) { return "addProduct"; } if (productImage!=null && !productImage.isEmpty()) { try { productImage.transferTo(new File(productToBeAdded.getProductId() + ".png")); } catch (Exception e) { throw new RuntimeException("Product Image saving failed", e); } } return "redirect:/products"; } }
上述的代码有一个不一样的地方就是方法的定义里多了一个参数@RequestPart("productImage") MultipartFile productImage,在RequestPart定义的属性正好和我们前面表单里定义的productImage一致,这样在表单的这个地方它会自动绑定这个属性。然后剩下的内容就和前面的一样,将MultipartFile输出到某个文件。这部分详细内容的输出可以参考后面附件里的示例工程multiparthandler。
当然,standard servlet multipart resolver并不止我们想象的这么简单。它默认会将表单里提交的所有内容都上传到指定的目录。如果我们尝试将controller里该方法的内容给清空再去看上传目录就会看到相关的上传。
总结
在spring mvc里实现文件的上传其实比较简单,主要通过commons multipart resolver或者standard servlet multipart resolver来处理。它们的差别在于使用后面这种方法作为原生的支持更加简单一点。在实际文件上传中,一般我们需要考虑将文件上传到某个具体的路径,所以可以在方法里使用具体的参数。也可以在默认路径配置好的情况下单纯操作文件。
其实最复杂的部分在于文件上传之后的管理。对于简单的文件处理,我们可以将文件设置到某个目录中。在实际工程中更加推荐采用一些云存储服务,将具体文件对象上传到云存储服务器。这样对于它们的管理更加简单方便,不会出现简单的文件目录管理问题。
参考材料
相关推荐
赠送Maven依赖信息文件:spring-webmvc-5.0.8.RELEASE.pom; 包含翻译后的API文档:spring-webmvc-5.0.8.RELEASE-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.springframework:spring-webmvc:5.0.8.RELEASE...
《看透Spring MVC:源代码分析与实践》是一本深入探讨Spring MVC框架核心机制的书籍。通过对源代码的解析,读者可以深入了解这个广泛使用的Java Web开发框架的工作原理,从而更好地运用和优化自己的项目。该书提供了...
在IT行业中,Spring框架是Java开发中的一个核心组件,尤其在企业级应用开发中占据了重要地位。...通过不断的实践和学习,你可以进一步提升在Spring MVC上的技能,构建出更加复杂且健壮的Web应用程序。
Spring MVC 是一个基于Java的轻量级Web应用框架,它是Spring框架的重要组成部分,主要用于构建Web应用程序的后端控制器。...通过学习,开发者可以熟练地运用Spring MVC来构建高效、可维护的Web应用。
在本文中,我们将深入探讨如何使用Spring MVC框架与Ajax技术结合来实现文件上传的功能。Spring MVC是Spring框架的一部分,提供了一种模型-视图-控制器(MVC)架构模式,用于构建Web应用程序。Ajax(Asynchronous ...
在Spring MVC框架中,文件上传和下载是常见的功能需求,特别是在构建Web应用程序时。这个压缩包文件"Spring MVC 文件上传下载 后端 - Java.zip"包含的文档可能详细阐述了如何在Java后端实现这些功能。以下是关于...
赠送Maven依赖信息文件:spring-webmvc-5.2.15.RELEASE.pom; 包含翻译后的API文档:spring-webmvc-5.2.15.RELEASE-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.springframework:spring-webmvc:5.2.15....
赠送Maven依赖信息文件:spring-webmvc-5.3.10.pom; 包含翻译后的API文档:spring-webmvc-5.3.10-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.springframework:spring-webmvc:5.3.10; 标签:spring...
赠送Maven依赖信息文件:spring-webmvc-5.3.15.pom; 包含翻译后的API文档:spring-webmvc-5.3.15-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.springframework:spring-webmvc:5.3.15; 标签:spring、web...
赠送Maven依赖信息文件:spring-webmvc-5.3.7.pom; 包含翻译后的API文档:spring-webmvc-5.3.7-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.springframework:spring-webmvc:5.3.7; 标签:springframework...
书名:《看透Spring MVC:源代码分析与实践》 作者:韩路彪 Spring MVC相关的源码分析
在Spring MVC框架中,文件上传是一项常见的功能,而实现文件上传进度条则能提供更好的用户体验。这个场景通常涉及到前端的JavaScript或jQuery库(如jQuery File Upload)与后端的Spring MVC控制器之间的交互,以及...
本书共计10章,分别介绍了快速搭建Spring Web应用、精通MVC结构、URL映射、文件上传与错误处理、创建Restful应用、保护应用、单元测试与验收测试、优化请求、将Web应用部署到云等内容,循序渐进地讲解了Spring MVC4...
NULL 博文链接:https://shmilyaw-hotmail-com.iteye.com/blog/2244136
看透Spring MVC:源代码分析与实践
赠送Maven依赖信息文件:spring-webmvc-5.3.15.pom; 包含翻译后的API文档:spring-webmvc-5.3.15-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:org.springframework:spring-webmvc:5.3.15; 标签:...
在Spring MVC中,文件的上传和下载是常见的功能需求,这涉及到客户端与服务器之间的数据传输。本篇文章将深入探讨Spring MVC如何实现文件上传和下载。 ### 文件上传 1. **依赖配置**:在Spring MVC项目中,为了...