文件上传

Web 应用中,允许用户上传文件是很常见的需求。文件上传通常是采用 multipart 格式,而 DispatcherServlet 并没有任何解析 multipart 请求数据的功能,它将这个解析的任务委托给了 Spring 中的 MultipartResolver 策略接口的实现,通过这个实现类来解析 multipart 请求中的内容。

Spring 3.1 开始, Spring 内置了两个 MultipartResolver 实现供我们选择:

  • CommonsMultipartResolver: 使用 Jakarta Commons FileUpload 解析 multipart 请求
  • StandardServletMultipartResolver: 依赖于 Servlet 3.0multipart 请求的支持


使用 CommonsMultipartResolver

@Bean
public MultipartResolver multipartResolver() throws IOException {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
// 配置存放路径,默认存放在 Servlet 容器临时目录
multipartResolver.setUploadTempDir(new FileSystemResource("/tmp/spring/uploads"));
// 配置最大文件容量为 2MB
multipartResolver.setMaxUploadSize(2097152);
// 配置最大内存容量为0,即直接写入到硬盘中
multipartResolver.setMaxInMemorySize(0);
return multipartResolver;
}

使用 StandardServletMultipartResolver

相比于CommonsMultipartResolver 来说 StandardServletMultipartResolver 没有构造器和属性,所以它的申明会很简单:

@Bean
public MultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}

那么我们要如何取设置文件保存路径和大小呢?

我们可以在 Serlvet 中指定 multipart 的配置,我们之前通过继承 AbstractAnnotationConfigDispatcherServletInitializer 来实现了配置 DispatcherServlet,那么可以重载 customizeRegistration() 方法来配置 multipart:

@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
super.customizeRegistration(registration);
// 设置文件存放路径、文件最大文件容量为 2MB
// 整个请求不超过 4MB 并且直接写入到硬盘
registration.setMultipartConfig(
new MultipartConfigElement("/tmp/spring/uploads",2097152,
4194304,0));
}

可以看到 StandardServletMultipartResolver 相比于 CommonsMultipartResolver 多了一个设置整个请求大小的属性。


处理 multipart 请求

处理 multipart 请求有三种方式:

  • 原始的 byte[]
  • Spring 提供的 MultipartFile 接口
  • Servlet3 支持的 Part

**原始的 byte[] **

@RequestMapping("/register")
public String processRegistration(@RequestPart("profilePicture") byte[] profilePicture){
......
}

byte 数组形式不能提供给我们文件类型、文件原始名称等信息。


Spring 提供的 MultipartFile 接口

接口定义

public interface MultipartFile extends InputStreamSource {
String getName(); String getOriginalFilename(); String getContentType(); boolean isEmpty(); long getSize(); byte[] getBytes() throws IOException; InputStream getInputStream() throws IOException; void transferTo(File var1) throws IOException, IllegalStateException;
}

MultipartFile 提供了获取原始文件名称、大小、内容类型等信息,还提供了一个 transferTo 方法,帮助我们将上传的文件写入到文件系统中。


** Servlet3 支持的 Part**

接口定义:

public interface Part {

    InputStream getInputStream() throws IOException;

    String getContentType();

    String getName();

	String getSubmittedFileName();

    long getSize();

	void write(String fileName) throws IOException;

	void delete() throws IOException;

	String getHeader(String name);

	Collection<String> getHeaders(String name);

	Collection<String> getHeaderNames();
}

PartMultipartFile 基本差别不大,要注意的是如果使用了 *Part 那么就不需要配置 MultipartResolver 了。


异常处理

Spring 提供了多种方式将异常转为响应:

  • 特定的 Spring 异常将会自动映射为指定的 HTTP 状态码
  • 异常上可以添加 @ResponseStatus 注解,从而将其映射为某一个 HTTP 状态码
  • 在方法上添加 @ExceptionHandler 注解,使其用来处理异常

将异常映射为 HTTP 状态码

Spring 异常 状态码
BindException 400-Bad Request
ConversionNotSupportedException 500-Intemal Server Error
HttpMediaTypeNotAcceptableException 406-Not Acceptable
HttpMediaTypeNotSupportedException 415-Unsupported Media Type
HttpMessageNotReadableException 400-Bad Request
HttpMessageNotWritableException 500-Intemal Server Error
HttpRequestMethodNotSupportedException 405-Method NOt Allowed
MethodArgumentNotValidException 400-Bad Request
MissingServletRequestParameterException 400-Bad Request
MissingServletRequestPartException 400-Bad Request
NoSuchRequestHandlingMethodException 404-Not Found
TypeMismatchException 400-Bad Request

上面表中列出的异常一般会由 Spring 自身抛出,如果是应用自身抛出的异常它们就无能为力了,我们可以通过 @ResponseStatus 注解,将异常映射为特定的状态码。

@ResponseStatus(value=HttpStatus.NOT_FOUND,reason="not found")
public class SpringNotFoundException extends RuntimeException{ }

如果控制器抛出 SpringNotFoundException 异常后,响应状态将会变为 404

异常处理方法

除了返回状态之外,我们还想返回异常包含的信息,我们可以通过 @ExceptionHandler 注解来处理异常信息。

@ExceptionHandler(SpringNotFoundException.class)
public String handleExceptionHandler(){
......
}

@ExceptionHandler 可以处理同一个 Controller 中的异常,但是如果是其他 Controller 的话就无能为力了。Spring 也考虑到了这个问题,为我们提供了 @ControllerAdvice 注解,它会捕获到所有的 Controller 异常。

@ControllerAdvice
public class AppWideExceptionHandler{
@ExceptionHandler(SpringNotFoundException.class)
public String handleExceptionHandler(){
......
}
}

Spring学习之旅(九)--SpringMVC高级技术的更多相关文章

  1. Spring学习之旅(六)--SpringMVC集成

    对大多数 Java 开发来说,基于 web 的应用程序是我们主要的关注点. Spring 也提供了对于 web 的支持,基于 MVC 模式的 Spring MVC 能够帮助我们灵活和松耦合的完成 we ...

  2. Spring学习之旅(八)--SpringMVC请求参数

    现在我们已经完成了一个无参的接口了,但是应用中有很多需要携带参数的场景,我们来看看 ** SpringMVC** 对它的支持. 参数绑定 SpringMVC 提供了一种绑定机制,通过这个机制可以从请求 ...

  3. Spring学习之旅(七)--SpringMVC视图

    在之前的实例中我们只是在 Controller 中返回了 home 字符类型的值,而没有直接生成可以在浏览器中直接渲染的 HTML,这是因为 SpringMVC 将请求处理的逻辑和视图渲染的实现进行了 ...

  4. Spring学习之旅(十)--MockMvc

    在之前的 Spring学习之旅(八)--SpringMVC请求参数 我们是通过在控制台输出来验证参数是否正确,但是这样做实在是太耗时间了,我们今天来学习下 MockMvc,它可以让我们不需要启动项目就 ...

  5. Spring学习之旅(八)Spring 基于AspectJ注解配置的AOP编程工作原理初探

    由小编的上篇博文可以一窥基于AspectJ注解配置的AOP编程实现. 本文一下未贴出的相关代码示例请关注小编的上篇博文<Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AO ...

  6. 【Spring学习笔记-MVC-9】SpringMVC数据格式化之日期转换@DateTimeFormat

    作者:ssslinppp       1. 摘要 本文主要讲解Spring mvc数据格式化的具体步骤: 并讲解前台日期格式如何转换为java对象: 在之前的文章<[Spring学习笔记-MVC ...

  7. 【Spring学习笔记-MVC-4】SpringMVC返回Json数据-方式2

    <Spring学习笔记-MVC>系列文章,讲解返回json数据的文章共有3篇,分别为: [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://www ...

  8. 【Spring学习笔记-MVC-3】SpringMVC返回Json数据-方式1

    <Spring学习笔记-MVC>系列文章,讲解返回json数据的文章共有3篇,分别为: [Spring学习笔记-MVC-3]SpringMVC返回Json数据-方式1:http://www ...

  9. spring-mvc高级技术

    Spring MVC高级技术包括但不限于web.xml配置.异常处理.跨重定向请求传递数据 1.web.xml文件的配置 <!DOCTYPE web-app PUBLIC "-//Su ...

随机推荐

  1. bat命令闪退问题

    今天执行一个bat命令,然而会出现问题:双击执行bat命令时,命令提示符界面会闪退. 然而该bat命令在他人电脑上可正常执行,而我会遇到这种问题. 以下是我尝试的方法: 首先尝试编辑bat命令,在ba ...

  2. 【Java中级】(二)集合框架

    2.1.ArraList 1.自增长 容器的容量"capacity"会随着对象的增加,自动增长 只需要不断往容器里增加英雄即可,不用担心会出现数组的边界问题. 2.常用方法 关键字 ...

  3. Java EE产生的背景

    为了满足开发多层体系结构的企业级应用的需求,Java公司的创始人Sun公司在早期的J2SE(Java 2 Platform Standard Edition)基础上,针对企业级应用的各种需求,提出了J ...

  4. mysql添加外键失败解决方案

    mysql重启命令: [root@wshCentOS centOS7Share]# service mysqld stopRedirecting to /bin/systemctl stop  mys ...

  5. difflib python

    difflib -帮助进行差异化比较 这个模块提供的类和方法用来进行差异化比较,它能够生成文本或者html格式的差异化比较结果,如果需要比较目录的不同,可以使用filecmp模块. 例子: # -*- ...

  6. java练习---8

    //程序员:罗元昊 2017.10.16 题目3.7 import java.util.Scanner; public class L { @SuppressWarnings("resour ...

  7. Java生鲜电商平台-统一异常处理及架构实战

    Java生鲜电商平台-统一异常处理及架构实战 补充说明:本文讲得比较细,所以篇幅较长. 请认真读完,希望读完后能对统一异常处理有一个清晰的认识. 背景 软件开发过程中,不可避免的是需要处理各种异常,就 ...

  8. Codeforces1144B(B题)Parity Alternated Deletions

    B. Parity Alternated Deletions Polycarp has an array aa consisting of nn integers. He wants to play ...

  9. js里的Document对象介绍

    activeElement     返回代表文档中dangqianhuodejiaodianyuansudeduixaing body                    返回代表文档中body元素 ...

  10. 实用小工具推荐 OpenWrite

    [实用小工具推荐]给技术同学们推荐一款比较好用的工具,可以实现一稿多发,主流的技术渠道基本涵盖了:https://www.openwrite.cn/ 因为工作的关系,认识了很多做技术公众号的小伙伴,同 ...