标签:
2.1)CommonsMultipartResolver:使用 Jakarta Commons FileUpload 解析 multipart请求;2.2)StandardServletMultipartResolver:依赖于Servlet3.0 对 multipart 请求 的支持;(干货——优选方案,因为它不依赖于第三方库)
@Bean public MultipartResolver multipartResolver() throws IOException { return new StandardServletMultipartResolver(); }
2.1)看个荔枝:最基本的 DispatcherServlet multipart配置,它将临时路径设置为 "/tmp/spittr/uploads"DispatcherServlet ds = new DispatcherServlet(); Dynamic registration = context.addServlet("appServlet", ds); registration.addMapping("/"); registration.setMultipartConfig( new MultipartConfigElement("/tmp/spittr/uploads"));2.2)如果配置DispatcherServlet 的 Servlet初始化类继承了 AbstractAnnotationConfigDispatcherServletInitializer 或 AbstractDispatcherServletInitializer,那么我们就不会直接创建 DispatcherServlet实例并将其注册到 Servlet上下文中;这样的话,将不会有对 Dynamic Servlet registration 的引用供我们使用了。但我们可以通过重载 customizeRegistration() 方法 来配置 multipart 的具体细节;@Override protected void customizeRegistration(Dynamic registration) { registration.setMultipartConfig( new MultipartConfigElement("/tmp/spittr/uploads")); }对以上代码的分析(Analysis):上述代码所使用的 只有一个参数的 MultipartConfigElement 构造器,指定的是文件系统中的一个绝对目录,上传文件将会临时写入到该目录中;
parameter1)上传文件的最大容量(以字节为单位),默认是没有限制的;parameter2)整个mulitpart 请求的最大容量(以字节为单位),不会关心有多少个part以及每个part的大小,默认是没有限制的;parameter3)在上传的过程中,如果文件大小得到了一个指定最大容量(以字节为单位),将会写入到临时文件路径中。默认值为0.也就是所上传的文件都会写入到磁盘上;
3.1)看个荔枝:限制文件大小不超过2M,整个请求不超过4M,而且所有的文件都写到磁盘上,则设置为:@Override protected void customizeRegistration(Dynamic registration) { registration.setMultipartConfig( new MultipartConfigElement("/tmp/spittr/uploads", 2097152, 4194304, 0)); }
<servlet> <servlet-name>appServlet</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> <multipart-config> <location>/tmp/spittr/uploads</location> <max-file-size>2097152</max-file-size> <max-request-size>4194304</max-request-size> </multipart-config> </servlet>
2.1)将CommonsMultipartResolver 声明为 spring bean的 简单方式如下:@Bean public MultipartResolver multipartResolver() { return new CommonsMultipartResolver(); }2.2)CommonsMultipartResolver:不会强制要求设置临时文件路径,默认case下,这个路径就是 Servlet容器的临时目录;不过通过 updateTempDir属性类设置不同 位置;@Bean public MultipartResolver multipartResolver() throws IOException { CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); multipartResolver.setUploadTempDir( new FileSystemResource("/tmp/spittr/uploads")); return multipartResolver; }2.3)看个荔枝: 设置最大的文件容量为2M,最大的内存大小为0字节(所有的文件都会写到磁盘中),与MultipartConfigElement 不同的是,我们无法设置 multipart 请求整体的最大容量;@Bean public MultipartResolver multipartResolver() throws IOException { CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); multipartResolver.setUploadTempDir( new FileSystemResource("/tmp/spittr/uploads")); multipartResolver.setMaxUploadSize(2097152); multipartResolver.setMaxInMemorySize(0); return multipartResolver; }
method1)multipartFile;method2)part形式
2.1)修改前台模板添加上传图片插件;(省略)2.2)修改控制器方法@RequestMapping(value="/register", method=POST) public String processRegistration( @RequestPart("profilePicture") byte[] profilePicture, // highlight line. @Valid Spitter spitter, Errors errors) { //... }对以上代码的分析(Analysis):
A1)profilePicture属性:将会给定一个 byte数组,这个数组中包含了请求中对应的part数据(通过@RequestPart类指定);如果用户提交表单的时候没有选择文件,那么这个数组是空的(而不是null);A2)获取到图片数据后:processRegistration方法接下来就是将文件保存到某个位置了;(下面讲如何处理文件的存储)
A1)Multipart提供了获取上传文件byte的方式,但是它所提供的功能并不仅限于此,还能获得原始的文件名,大小以及内容类型;A2)它还提供了一个 InputStream,用来将文件数据以流的方式进行读取;A3)MultipartFile 还提供了一个便利的 transferTo()方法,能够帮助我们将上传的文件写入到文件系统中;profilePicture.transferTo( new File("/data/spittr/" + profilePicture.getOriginalFilename()));
@RequestMapping(value="/register", method=POST) public String processRegistration( @RequestPart("profilePicture") Part profilePicture, @Valid Spitter spitter, Errors errors) { //... }
package javax.servlet.http; import java.io.*; import java.util.*; public interface Part { public InputStream getInputStream() throws IOException; public String getContentType(); public String getName(); public String getSubmittedFileName(); public long getSize(); public void write(String fileName) throws IOException; public void delete() throws IOException; public String getHeader(String name); public Collection<String> getHeaders(String name); public Collection<String> getHeaderNames(); }
A1)Part方法与 MultipartFile 方法有些类似:如getSubmittedFileName() 方法 同 getOriginalFilename()方法类似,write()方法 与 transferTo()方法类似;A2)借助于该方法(write方法),可以将上传的文件写入文件系统中:profilePicture.write("/data/spittr/" + profilePicture.getOriginalFilename());Attention)只有使用 MultipartFile 的时候才需要 MultipartResolver;
2)处理异常的最简单的方法:就是将其映射到 HTTP 状态码上,进而放到响应中;way1)特定的spring 异常将会自动映射为指定 的 HTTP 状态码;way2)异常上可以添加 @ResponseStatus注解,从而将其映射为某一个HTTP 状态码;way3)在方法上添加 @ExceptionHandler 注解,使其用来处理异常;
2.1)不加 @ResponseStatus注解的case:SpittleNotFoundException 将会产生500状态码的响应,实际上,如果出现任何没有映射的异常,响应都会带有500状态码;2.2)加上 @ResponseStatus注解的case:使用该注解将 SpittleNotFoundException 映射为 HTTP 状态码 404;@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="spittle not found") public class SpittleNotFoundException extends RuntimeException{ }
1.1)problem:如果我们想在响应中不仅要包括状态码,还要包含所产生的错误,怎么来处理?1.2)solution:我们不能将异常视为 HTTP 错误了,而是要按照处理请求的方式来处理异常;
3.1)step1:首先将saveSpittle方法中的异常处理剥离掉;3.2)step2:为SpittleController 添加新方法,处理抛出的异常;
func1)@ExceptionHandler 注解标注的方法;func2)@InitBinder注解标注的方法;func3)@ModelAttribute注解标注的方法;
1.1)传递简单数据(如String,int类型):使用 URL 模板进行重定向;1.2)传递复杂数据(如对象):使用 Flash 属性;
2.1)problem:正在发起重定向功能的方法该如何发送数据给重定向的目标方法呢?一般来讲,当一个处理器方法完成后,该方法所指定的模型数据将会copy 到 请求中,并作为请求中的属性,请求会转发(forward)到视图上进行渲染。因为控制器方法和视图所处理的是同一个请求,所以在转发过程中,请求属性能够得以保存;但是重定向(redirect) 的case就不同了;
2.2)solution:如下图所示,当控制器的结果是重新向的话,原始的请求就结束了,并且会发出一个新的 GET 请求;原始请求中所带有的模型数据也就消亡了;
way1)使用 URL 模板以路径变量 或/和 查询参数的形式传递数据;way2)通过flash 属性发送数据;
return "redirect:/spitter/{username}";
@RequestMapping(value="/register", method=RequestMethod.POST) public String processRegistration( Spitter spitter, Model model) { spitterRepository.save(spitter); model.addAttribute("username", spitter.getUsername()); return "redirect:/spitter/{username}"; }
@RequestMapping(value = "/register", method = RequestMethod.POST) public String processRegistration2(Spitter spitter, Model model) { spitterRepository.save(spitter); model.addAttribute("username", spitter.getUsername()); // highlight line. model.addAttribute("spitterId", spitter.getId()); // highlight line. return "redirect:/spitter/{username}"; }
1.1)problem:发送实际的 Spitter对象,而不是简单的int类型数据;1.2)solution:
1.2.1)schema1:将Spitter对象 放入到 会话中,然后重定向后再将其从会话中取出;1.2.2)schema2:spring 提供了提供了将数据发送为 flash 属性的功能。flash 属性会一直携带这些数据直到下一次请求才会消失;(干货——flash属性的作用)
标签:
原文地址:http://blog.csdn.net/pacosonswjtu/article/details/51610593