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

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

package org.springframework.samples.mvc.fileupload; 


import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestMethod; 


@Controller
@RequestMapping("/fileupload") 
publicclass FileUploadController { 


 @RequestMapping(method=RequestMethod.GET) 
 publicvoid fileUploadForm() { 
 } 


}
package org.springframework.samples.mvc.fileupload;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/fileupload")
public class FileUploadController {

	@RequestMapping(method=RequestMethod.GET)
	public void fileUploadForm() {
	}

}

这个类和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,后台报错:

2012-03-2019:12:44.557:WARN::/web/fileupload 
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.) 
 at org.springframework.web.servlet.view.InternalResourceView.prepareForRendering(InternalResourceView.java:292) 
...
2012-03-20 19:12:44.557:WARN::/web/fileupload
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.)
	at org.springframework.web.servlet.view.InternalResourceView.prepareForRendering(InternalResourceView.java:292)
...

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

ERROR: PWC6117: File "/Users/stephansun/Documents/workspace/samples/samples-web/src/main/webapp/WEB-INF/views/fileupload.jsp" not found
ERROR: PWC6117: File "/Users/stephansun/Documents/workspace/samples/samples-web/src/main/webapp/WEB-INF/views/fileupload.jsp" not found

fileUploadForm.jsp文件为:

package org.springframework.samples.mvc.fileupload; 


import java.io.IOException; 


import org.springframework.stereotype.Controller; 
import org.springframework.ui.Model; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RequestMethod; 
import org.springframework.web.bind.annotation.RequestParam; 
import org.springframework.web.multipart.MultipartFile; 


@Controller
@RequestMapping("/fileupload") 
publicclass FileUploadController { 


 @RequestMapping(method=RequestMethod.GET) 
 publicvoid fileUploadForm() { 
 } 


 @RequestMapping(method=RequestMethod.POST) 
 publicvoid processUpload(@RequestParam MultipartFile file, Model model) throws IOException { 
 model.addAttribute("message", "File '" + file.getOriginalFilename() + "' uploaded successfully"); 
 } 


}
package org.springframework.samples.mvc.fileupload;

import java.io.IOException;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@Controller
@RequestMapping("/fileupload")
public class FileUploadController {

	@RequestMapping(method=RequestMethod.GET)
	public void fileUploadForm() {
	}

	@RequestMapping(method=RequestMethod.POST)
	public void processUpload(@RequestParam MultipartFile file, Model model) throws IOException {
		model.addAttribute("message", "File '" + file.getOriginalFilename() + "' uploaded successfully");
	}
	
}

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

java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured? 
 at org.springframework.util.Assert.notNull(Assert.java:112)
java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
	at org.springframework.util.Assert.notNull(Assert.java:112)

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

@RequestMapping(method=RequestMethod.POST) 
 publicvoid processUpload(@RequestParam MultipartFile file, Model model) throws IOException { 
 model.addAttribute("message", "File '" + file.getOriginalFilename() + "' uploaded successfully"); 
 }
@RequestMapping(method=RequestMethod.POST)
	public void processUpload(@RequestParam MultipartFile file, Model model) throws IOException {
		model.addAttribute("message", "File '" + file.getOriginalFilename() + "' uploaded successfully");
	}

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

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

import org.apache.commons.fileupload.FileItem; 
import org.apache.commons.fileupload.FileItemFactory; 
import org.apache.commons.fileupload.FileUpload; 
import org.apache.commons.fileupload.FileUploadBase; 
import org.apache.commons.fileupload.FileUploadException; 
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

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

相关推荐