• Spring学习之旅(九)--SpringMVC高级技术


    文件上传

    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(){
    		......
    	}
    }
    
  • 相关阅读:
    禅道开源版本安装
    NATAPP内网穿透实现
    nginx部署前端项目
    docker-compose部署微服务
    python编写猜数字游戏
    Linux命令(用户管理、组和时间管理)
    Linux命令(文本编辑器)
    Linux的简单命令(防火墙篇)
    什么是泛型
    spring bean 的作用域之间有什么区别
  • 原文地址:https://www.cnblogs.com/markLogZhu/p/11400469.html
Copyright © 2020-2023  润新知