美文网首页
Spring MVC进阶知识

Spring MVC进阶知识

作者: TheMrBigHead | 来源:发表于2018-09-09 11:01 被阅读0次

    1. Spring MVC配置

    1.1 自定义DispatcherServlet配置

    覆写AbstractAnnotationConfigDispatcherServletInitializer的customizeRegistration()方法

    @Override
    protected void customizeRegistration(Dynamic registration) {
      registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
    }
    

    1.2 添加servlet、filter

    实现WebApplicationInitializer接口

    注册一个servlet:

    package com.myapp.config;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRegistration.Dynamic;
    import org.springframework.web.WebApplicationInitializer;
    import com.myapp.MyServlet;
    
    public class MyServletInitializer implements WebApplicationInitializer {
      @Override
      public void onStartup(ServletContext servletContext) throws ServletException {
        Dynamic myServlet = servletContext.addServlet("myServlet", MyServlet.class);
        myServlet.addMapping("/custom/**"); 
      }
    }
    

    注册一个filter:

    public class MyServletInitializer implements WebApplicationInitializer {
      @Override
      public void onStartup(ServletContext servletContext) throws ServletException {
        javax.servlet.FilterRegistration.Dynamic filter =
          servletContext.addFilter("myFilter", MyFilter.class);
        filter.addMappingForUrlPatterns(null, false, "/custom/*");
      }
    }
    

    WebApplicationInitializer适用于通用的添加servlet、filter、listener。

    覆写AbstractAnnotationConfigDispatcherServletInitializer抽象类的getServletFilters()方法也可以添加filter:

    @Override
    protected Filter[] getServletFilters() {
        return new Filter[] { new MyFilter() };
    }
    

    1.3 在web.xml中声明DispatcherServlet

    image.png 定义DispatcherServlet配置文件的位置

    在web.xml中使用Java配置类:


    image.png
    image.png

    2. 处理multipart form

    在提交表单的时候,有时候会附带上传文件,文件会以二进制的形式提交。
    multipart form回将提交的数据分成几个独立的部分,每个部分拥有自己的属性,自己的类型。

    multipart request body样例:


    multipart request body

    2.1 配置multipart解析器

    实现MultipartResolver。

    Spring提供了两种MultipartResolver实现:

    1. CommonsMultipartResolver 使用Jakarta Commons FileUpload来解析multipart请求
    2. StandardServletMultipartResolver 依赖Servlet 3.0对于multipart请求的支持(since Spring 3.1)
    使用Servlet3.0来解析multipart请求
    @Bean
    public MultipartResolver multipartResolver() throws IOException {
      return new StandardServletMultipartResolver();
    }
    

    配置一些对于文件的上传的属性:
    (1) 如果是配置DispatcherServlet时实现了WebApplicationInitializer接口

    DispatcherServlet ds = new DispatcherServlet();
    Dynamic registration = context.addServlet("appServlet", ds);
    registration.addMapping("/");
    registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
    

    (2) 如果在配置DispatcherServlet时继承了AbstractAnnotationConfigDispatcherServletInitializer或AbstractDispatcherServletInitializer,那就覆写customizeRegistration()方法

    @Override
    protected void customizeRegistration(Dynamic registration) {
      registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
    }
    

    MultipartConfigElement的构造方法的参数作用:

    . 设置文件的临时位置
    . 限定上传文件的最大size(in bytes),默认是没有上限的
    . 配置整个multipart请求的最大size(in bytes),默认是没有上限的
    . 限定一个上传的文件不写入临时位置,而直接写入到磁盘的最大size(in bytes),这个值默认是0,也就是说默认情况下,所有的文件都会写到磁盘上

    /**
    * 单个文件不能超过2MB,整个请求不能超过4MB,所有文件都要直接写到磁盘上
    */
    @Override
    protected void customizeRegistration(Dynamic registration) {
      registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads", 2097152, 4194304, 0));
    }
    

    (3)如果在配置DispatcherServlet时使用了web.xml,就使用<multipart-config>元素就好了

    <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>
    
    配置JAKARTA COMMONS FILEUPLOAD 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;
    }
    

    2.2 处理multipart请求

    最常用的方法是在controller的方法参数加上注解@RequestPart

    前端form加上enctype="multipart/form-data"属性:

    <form method="POST" th:object="${spitter}" enctype="multipart/form-data">
      <label>Profile Picture</label>:
      <input type="file" name="profilePicture" accept="image/jpeg,image/png,image/gif" />
      <br/>
    </form>
    
    @RequestMapping(value="/register", method=POST)
    public String processRegistration(@RequestPart("profilePicture") byte[] profilePicture, 
                                      @Valid Spitter spitter, Errors errors) {
      ... 
    }
    
    接收MULTIPARTFILE

    Spring提供了MultipartFile用来对上传的文件封装,便于操作

    @RequestMapping(value="/register", method=POST)
    public String processRegistration(@RequestPart("profilePicture") MultipartFile profilePicture, 
                                      @Valid Spitter spitter, Errors errors) {
      ... 
    }
    
    package org.springframework.web.multipart;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    
    public interface MultipartFile {
      String getName();
      String getOriginalFilename();
      String getContentType();
      boolean isEmpty();
      long getSize();
      byte[] getBytes() throws IOException;
      InputStream getInputStream() throws IOException;
      void transferTo(File dest) throws IOException;
    }
    

    transferTo方法可以将文件保存至指定位置

    如果使用的Servlet3.0, 可以把上传的文件当做一个PART来解析
    @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();
    }
    

    使用write方法将文件保存至指定位置

    3. 异常处理

    3.1 将异常映射为Http状态码

    (1)Spring默认提供了一些状态码映射


    image.png

    (2) 使用@ResponseStatus注解
    首先自定义异常,并使用@ResponseStatus注解

    package spittr.web;
    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.ResponseStatus;
    @ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Spittle Not Found")
    public class SpittleNotFoundException extends RuntimeException {
    }
    

    然后跑出异常即可:


    image.png
    3.2 异常处理方法

    使用@ExceptionHandler注解:

    @ExceptionHandler(DuplicateSpittleException.class)
    public String handleDuplicateSpittle() {
      return "error/duplicate";
    }
    

    这个类可能会抛出DuplicateSpittleException异常:

    @RequestMapping(method=RequestMethod.POST)
    public String saveSpittle(SpittleForm form, Model model) {
      spittleRepository.save(new Spittle(null, form.getMessage(), new Date(),
              form.getLongitude(), form.getLatitude()));
      return "redirect:/spittles";
    }
    

    4. 增强Controller

    @ControllerAdvice注解
    @ExceptionHandler注解
    @InitBinder注解
    @ModelAttribute注解

    统一异常处理
    package spitter.web;
    
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    
    @ControllerAdvice
    public class AppWideExceptionHandler {
      @ExceptionHandler(DuplicateSpittleException.class)
      public String duplicateSpittleHandler() {
        return "error/duplicate";
      }
    }
    

    5. redirect

    controller返回页面时添加前缀redirect:

      return "redirect:/spitter/" + spitter.getUsername()
    
    image.png
    5.1 在redirect时,使用url来传递参数
    @RequestMapping(value="/register", method=POST)
    public String processRegistration(Spitter spitter, Model model) {
              spitterRepository.save(spitter);
              model.addAttribute("username", spitter.getUsername());
              model.addAttribute("spitterId", spitter.getId());
              return "redirect:/spitter/{username}";
    }
    
    5.2 在redirect时,使用flash属性

    在Spring中,flash属性被定义为:携带数据到下一次请求

    Spring使用Model的子类RedirectAttributes的addFlashAttribute()方法来做这个

    @RequestMapping(value="/register", method=POST)
    public String processRegistration(
        Spitter spitter, RedirectAttributes model) {
      spitterRepository.save(spitter);
      model.addAttribute("username", spitter.getUsername());
      model.addFlashAttribute("spitter", spitter);
      return "redirect:/spitter/{username}";
    }
    
    image.png
    @RequestMapping(value="/{username}", method=GET)
    public String showSpitterProfile(@PathVariable String username, Model model) {
      if (!model.containsAttribute("spitter")) {
        model.addAttribute(spitterRepository.findByUsername(username));
      }
      return "profile";
    }
    

    相关文章

      网友评论

          本文标题:Spring MVC进阶知识

          本文链接:https://www.haomeiwen.com/subject/zuvkgftx.html