基于Spring MVC的Web应用开发(4) - FileUpload

本文深入探讨了使用SpringMVC进行文件上传的方法,并详细解释了MVC模式中的ModelAndView概念。通过创建FileUploadController类,实现文件上传功能,并配置视图解析器以正确显示上传页面。此外,文章还介绍了如何处理上传请求,配置MultipartResolver解决上传问题,以及最终上传文件的验证过程。最后,添加了依赖以确保上传组件的正常工作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇文章介绍了Spring MVC如何处理静态资源文件,本文讲解如何使用Spring MVC做文件上传,附带深入一下Spring MVC的ModelAndView。增加一个Controller,叫FileUploadController:

Java代码   收藏代码
  1. package org.springframework.samples.mvc.fileupload;  
  2.   
  3. import org.springframework.stereotype.Controller;  
  4. import org.springframework.web.bind.annotation.RequestMapping;  
  5. import org.springframework.web.bind.annotation.RequestMethod;  
  6.   
  7. @Controller  
  8. @RequestMapping("/fileupload")  
  9. public class FileUploadController {  
  10.   
  11.     @RequestMapping(method=RequestMethod.GET)  
  12.     public void fileUploadForm() {  
  13.     }  
  14.   
  15. }  

这个类和HelloWorld中的Controller类就有点差别了,首先类名上加入了@RequestMapping注解,这样在做HandlerMapping时,SpringMVC会将类名和方法名的@RequestMapping连接起来,而本例方法名前并没有具体路径(当然也可以写),因此最终映射的URL还是"/fileupload",另外一点就是在方法级@RequestMapping的注解增加了一个RequestMothod.GET,意思是只有以GET方式提交的"/fileupload"URL请求才会进入fileUploadForm()方法,其实根据HTTP协议,HTTP支持一系列提交方法(GET,POST,PUT,DELETE),同一个URL都可以使用这几种提交方式,事实上SpringMVC正是通过将同一个URL的不同提交方法对应到不同的方法上达到RESTful。

访问http://localhost:8080/web/fileupload,后台报错:

Java代码   收藏代码
  1. 2012-03-20 19:12:44.557:WARN::/web/fileupload  
  2. javax.servlet.ServletException: Circular view path [fileupload]: would dispatch back to the current handler URL [/web/fileupload] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)  
  3.     at org.springframework.web.servlet.view.InternalResourceView.prepareForRendering(InternalResourceView.java:292)  
  4. ...  

正如Hint中指出的,没有指定一个View,大家可能会有疑问,HelloWorld中不是可以将结果返回到浏览器么?注意HelloWorld中的@ResponseBody跟View没有任何关系,HelloWorld中其实也是返回了一个ModelAndView,但这个View为null,并且在返回前,已经将结果通过HttpServletResponse发送给浏览器了。
那么怎么指定一个View呢?通常我们会想到一个默认的View,即如果没有写特殊的View,所有的结果都将转到这个默认的View上,最后将这个View推到浏览器展示。在servlet-context.xml中增加一个配置:

Xml代码   收藏代码
  1. <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->  
  2. <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
  3.     <beans:property name="prefix" value="/WEB-INF/views/" />  
  4.     <beans:property name="suffix" value=".jsp" />  
  5. </beans:bean>  

配置了一个Bean,对应的类为InternalResourceViewResolver,并设置了prefix属性为"/WEB-INF/views",suffix属性为".jsp",这个类为视图解析器(view resolver),支持InternalResourceView(比如Servlet和JSP)及其子类如JstlView,默认的是InternalResourceView,如果有JSTL API存在的话,就是JstlView。

现在有一个默认的View了,这个View将view名字解析到/WEB-INF/views/目录下对应的jsp文件。
哪里有view名字?当带有@RequestMapping的方法返回void时,@RequestMapping映射的URL路径即view名字。

所以当使用GET方式访问http://localhost:8080/web/fileupload时,最终会找WEB-INF/views/目录下有没有fileupload.jsp文件,有则将此jsp文件显示在浏览器上,没有则报如下错误:

Java代码   收藏代码
  1. ERROR: PWC6117: File &quot;/Users/stephansun/Documents/workspace/samples/samples-web/src/main/webapp/WEB-INF/views/fileupload.jsp&quot; not found  

fileUploadForm.jsp文件为:

Html代码   收藏代码
  1. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>  
  2. <html>  
  3. <head>  
  4.     <title>fileupload | mvc-showcase</title>  
  5.     <link href="<c:url value="/resources/form.css" />rel="stylesheet"  type="text/css" />       
  6.     <script type="text/javascript" src="<c:url value="/resources/jquery/1.6/jquery.js" />"></script>  
  7.     <script type="text/javascript" src="<c:url value="/resources/jqueryform/2.8/jquery.form.js" />"></script>   
  8. </head>  
  9. <body>  
  10.     <div id="fileuploadContent">  
  11.         <h2>File Upload</h2>  
  12.         <p>  
  13.             See the <code>org.springframework.samples.mvc.fileupload</code> package for the @Controller code      
  14.         </p>  
  15.         <form id="fileuploadForm" action="fileupload" method="POST" enctype="multipart/form-data" class="cleanform">  
  16.             <div class="header">  
  17.                 <h2>Form</h2>  
  18.                 <c:if test="${not empty message}">  
  19.                     <div id="message" class="success">${message}</div>            
  20.                 </c:if>  
  21.             </div>  
  22.             <label for="file">File</label>  
  23.             <input id="file" type="file" name="file" />  
  24.             <p><button type="submit">Upload</button></p>          
  25.         </form>     
  26.     </div>  
  27. </body>  
  28. </html>  

 上传页面正确显示后,我们需要一个方法处理上传请求,processUpload,现在FileUploadController看起来是这样的:

Java代码   收藏代码
  1. package org.springframework.samples.mvc.fileupload;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.springframework.stereotype.Controller;  
  6. import org.springframework.ui.Model;  
  7. import org.springframework.web.bind.annotation.RequestMapping;  
  8. import org.springframework.web.bind.annotation.RequestMethod;  
  9. import org.springframework.web.bind.annotation.RequestParam;  
  10. import org.springframework.web.multipart.MultipartFile;  
  11.   
  12. @Controller  
  13. @RequestMapping("/fileupload")  
  14. public class FileUploadController {  
  15.   
  16.     @RequestMapping(method=RequestMethod.GET)  
  17.     public void fileUploadForm() {  
  18.     }  
  19.   
  20.     @RequestMapping(method=RequestMethod.POST)  
  21.     public void processUpload(@RequestParam MultipartFile file, Model model) throws IOException {  
  22.         model.addAttribute("message""File '" + file.getOriginalFilename() + "' uploaded successfully");  
  23.     }  
  24.       
  25. }  

 这里出现了一个新注解@RequestParam,先看一下JSP页面的代码片段:

Html代码   收藏代码
  1. <input id="file" type="file" name="file" />  

 input框提交的参数名就是file,@RequestParam注解自动将POST提交的参数中名为file的封装到一个MultipartFile类中,一切都在开发人员眼皮底下做好了,大大减少了开发人员的代码量。现在我们在上传页面选择一个文件上传,后台报错,看报错日志:

Java代码   收藏代码
  1. java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?  
  2.     at org.springframework.util.Assert.notNull(Assert.java:112)  

说"是不是没配置MultipartResolver?",恩,还没有配,所有在servlet-context.xml中加上这么一段配置:

Xml代码   收藏代码
  1. <!-- Only needed because we require fileupload in the org.springframework.samples.mvc.fileupload package -->  
  2.     <beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />  

这个Bean也是一个视图解析器(view resolver)。

完整的XML:

Xml代码   收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans:beans xmlns="http://www.springframework.org/schema/mvc"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xmlns:beans="http://www.springframework.org/schema/beans"  
  5.     xmlns:context="http://www.springframework.org/schema/context"  
  6.     xmlns:mvc="http://www.springframework.org/schema/mvc"  
  7.     xsi:schemaLocation="  
  8.         http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd  
  9.         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
  10.         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">  
  11.   
  12.     <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->  
  13.       
  14.     <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory -->  
  15.     <resources mapping="/resources/**" location="/resources/" />  
  16.       
  17.     <!-- Imports user-defined @Controller beans that process client requests -->  
  18.     <beans:import resource="controllers.xml" />  
  19.       
  20.     <!-- You have to add this because you had a <resources/> declare -->  
  21.     <mvc:annotation-driven/>  
  22.       
  23.     <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->  
  24.     <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
  25.         <beans:property name="prefix" value="/WEB-INF/views/" />  
  26.         <beans:property name="suffix" value=".jsp" />  
  27.     </beans:bean>  
  28.       
  29.     <!-- Only needed because we require fileupload in the org.springframework.samples.mvc.fileupload package -->  
  30.     <beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />  
  31.       
  32. </beans:beans>  

然后再次上传文件,页面显示:

Xml代码   收藏代码
  1. File 'a.js' uploaded successfully  

上传成功,最后我们分析一下FileUploadController中的processUpload方法:

Java代码   收藏代码
  1. @RequestMapping(method=RequestMethod.POST)  
  2.     public void processUpload(@RequestParam MultipartFile file, Model model) throws IOException {  
  3.         model.addAttribute("message""File '" + file.getOriginalFilename() + "' uploaded successfully");  
  4.     }  

Model就是MVC模式中的M,Model层封装了要传递给View层显示的值。

最后更新一下pom.xml文件,添加两个依赖:

Xml代码   收藏代码
  1. <!-- File Upload -->  
  2. <dependency>  
  3.     <groupId>commons-fileupload</groupId>  
  4.     <artifactId>commons-fileupload</artifactId>  
  5.     <version>1.2.2</version>  
  6. </dependency>   
  7. <dependency>  
  8.     <groupId>commons-io</groupId>  
  9.     <artifactId>commons-io</artifactId>  
  10.     <version>2.0.1</version>  
  11. </dependency>  

好像前面写的代码根本没有涉及到这两个jar包啊,为什么要引入?

 之前我写道

@RequestParam注解自动将POST提交的参数中名为file的封装到一个MultipartFile类中,一切都在开发人员眼皮底下做好了,大大减少了开发人员的代码量。

 底层真正由谁来做的呢?我们加入了multipartResolver这个Bean,它对应的类为

org.springframework.web.multipart.commons.CommonsMultipartResolver,

看看这个类的源代码,import中赫然写着:

Java代码   收藏代码
  1. import org.apache.commons.fileupload.FileItem;  
  2. import org.apache.commons.fileupload.FileItemFactory;  
  3. import org.apache.commons.fileupload.FileUpload;  
  4. import org.apache.commons.fileupload.FileUploadBase;  
  5. import org.apache.commons.fileupload.FileUploadException;  
  6. import org.apache.commons.fileupload.servlet.ServletFileUpload;  

因此SpringMVC封装了commons-fileupload上传组件,真正起上传作用的还是commons-fileupload-1.2.2.jar这个jar包里面的类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值