• SpringMVC



    大家好呀,我是小笙,今天我来分享一下我的SpringMVC的学习笔记!

    Spring Web MVC

    概述

    SpringMVC 是 WEB 层框架 [SpringMVC 接管了 Web 层组件, 比如控制器, 视图, 视图解析, 返回给用户的数据格式, 同时支持 MVC 的开发模式/开发架构]

    SpringMVC 采用低耦合的组件设计方式,具有更好扩展和灵活性

    支持 REST 统一格式的 URL 请求

    SpringMVC 是基于 Spring 框架进行开发的,核心组件如下

    image-20220908143018595

    SpringMVC 执行流程

    image-20220917193945273

    基本注解

    @RequestMapping

    概念:可以用来修饰类和方法(用来指定访问的 url,修饰类就类似同个类下访问方法的共同路径,修饰方法就是访问该方法的特有路径)

    举例加深理解

    @Controller
    @RequestMapping(value = "/user") // 修饰类
    public class UserServlet {
        
        // 访问路径: http://ip:port/工程路径/user/login
        @RequestMapping(value = "/login") // 修饰方法
        public String login(){
            System.out.println("login ok....");
            return "login_ok";
        }
        
        // 访问路径: http://ip:port/工程路径/user/bug
        @RequestMapping(value = "/bug") // 修饰方法
        public String bug(){
            System.out.println("bug ok....");
            return "bug_ok";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    注解源码分析

    主要讲解一下 path、method、params

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Mapping
    public @interface RequestMapping {
        String name() default "";
    
        @AliasFor("path")
        String[] value() default {};
    
        // 上文的路径指定,以下为路径匹配通配符(注意路径不能重复)
        // ?:匹配文件中的一个字符
        // *:匹配文件名中的任意字符
        // **:匹配多层路径
        @AliasFor("value")
        String[] path() default {}; 
        
        // 指定范围的方法:  GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS,TRACE; (默认支持 GET,POST)
        // 注意:我们也可以通过注解就指定是什么请求形式,如下
        // @GetMappping、@PostMapping、@PutMapping、@DeleteMapping等等
        RequestMethod[] method() default {}; 
    
        // 表示请求必须包含名为"xx"的请求参数,但是值不做限定,格式如:params="xxx" 或者 params = {"xxx","yyy"}
        // params="xxx=100" 表示必须给一个 xxx 参数,并且值必须为100,不然报 400 错误
        String[] params() default {};
    
        String[] headers() default {};
    
        String[] consumes() default {};
    
        String[] produces() default {};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    @RequestHeader

    概述:获取请求头信息比如:host、accept-encoding等等

    @Controller
    public class UserServlet {
    
        @GetMapping(value = "/test")
        // 不需要请求携带数据
        public String test(@RequestHeader("host") String host){
            System.out.println("host:" + host);
            return "ok";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    @PathVariable

    概念:路径变量,就是在传 url 的时候把值也顺便传进来了

    通过例子对比一下就清楚了

    // 不使用该注解
    // 请求url: http://localhost:8080/test?bookId=100
    @RequestMapping(value = "/test") 
    public String book(int bookId){
        System.out.println("书本id:" + bookId);
        return "ok";
    }
    
    // 使用该注解 @PathVariable
    // 请求url: http://localhost:8080/test/100
    @RequestMapping(value = "/test/{bookId}")  // 通过 url 传入值
    public String book(@PathVariable int bookId){
        System.out.println("书本id:" + bookId);
        return "ok";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    @RequestParam

    概述:可以用来指定某形参的接收参数名

    @Controller
    public class UserServlet {
        /**
         * @RequestParam 指定接收的参数名
         * 不添加注解 url: http://localhost:8080/web工程路径/test?param="steven" 
         * 添加注解 url:http://localhost:8080/web工程路径/test?par="steven" 
         * required 指的是该形参是否是必须的
         */
        @GetMapping(value = "/test")
        public String test(@RequestParam(value = "par",required = false) String param){
            System.out.println(param);
            return "ok";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    @ModeAttribute

    概述:前置处理,调用其他 Handler 的时候,都会先调用这个方法

    @ModelAttribute
    public void beforeHandler(){
        System.out.println("前置处理注解");
    }
    
    • 1
    • 2
    • 3
    • 4

    @DateTimeFormat

    概述:控制日期格式,标注在字段上

    @DateTimeFormat(pattren="yyyy-MM-dd")
    private Date birthday;
    
    • 1
    • 2

    JSR 303 提供的基本验证注解
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-validationartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.进行数据转换/格式化,将错误的信息放入到 BindingResult 中

    2.进行数据校验(判空以及判 null),将错误的信息放入到 BindingResult 中

    image-20230102215512830

    注意:检验的时候需要在控制层对应方法形参前添加注解 @Valid


    @Responsebody

    概述:表示目标方法返回的数据格式为 json 格式

    @Controller
    class TestJsonController{
        @RequestMapping(value = "/json")
        @Responsebody
        public Dog TestJson(){
            // 返回的为 json 格式的对象
            return Dog对象;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    @RequestBody

    概述:前端以 json 格式的数据请求后端的时候,将他封装成对象的 javaBean 对象中

    @Controller
    class TestJsonController{
        @RequestMapping(value = "/json2")
        @Responsebody
        public User TestJson(@RequestBody User user){
            return Dog对象;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    注意:@RequestBody、@Responsebody 底层数据转换流程图

    image-20230105211228104

    接收请求过程

    请求方式 Rest
    概述

    概述:常用请求方式(GET、POST、PUT、DELETE) 分别对应 crud 的操作

    但是由于浏览器发送的请求只支持 POST、GET 请求,所以我们需要添加 Spring 的 HiddenHttpMethodFilter 过滤器进行转换

    注意:只能把浏览器发送的 POST 的请求转换成对应Spring 的 PUT、DELETE 请求

    
    <filter>
        <filter-name>hiddenHttpMethodFilterfilter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
    filter>
    <filter-mapping>
        <filter-name>hiddenHttpMethodFilterfilter-name>
        <url-pattern>/*url-pattern>
    filter-mapping>
    
    
    <mvc:annotation-driven/>
    <mvc:default-servlet-handler/>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    HiddenHttpMethodFilter 源码解析
    // 如果想要发送 delete 或者 put 请求,则需要发送 post 请求并且携带 _method = delete 类似参数
    public class HiddenHttpMethodFilter extends OncePerRequestFilter {
        private static final List<String> ALLOWED_METHODS;
        public static final String DEFAULT_METHOD_PARAM = "_method";
        private String methodParam = "_method";
    
        // 把浏览器发送的 POST 的请求转换成对应 Spring 的 PUT、DELETE 请求
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            HttpServletRequest requestToUse = request;
            if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {
                String paramValue = request.getParameter(this.methodParam);
                if (StringUtils.hasLength(paramValue)) {
                    String method = paramValue.toUpperCase(Locale.ENGLISH);
                    if (ALLOWED_METHODS.contains(method)) {
                        requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
                    }
                }
            }
    
            filterChain.doFilter((ServletRequest)requestToUse, response);
        }
    
        // 类加载初始化方法含有的列表:PUT、DELETE、PATCH
        static {
            ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    接收 Java 对象

    概述:就是将接收到的数据,赋值到对象的属性值上(注意对象的属性需要有 get 和 set 方法)并封装成对象(底层就是反射和注解)

    例子如下

    @Controller
    public class UserServlet {
        @GetMapping(value = "/test")
        public String test(Obj obj){
            System.out.println(obj);
            return "ok";
        }
    }
    
    // @Data 是 lombok 类中用来代替 get、set、toString方法的注解
    @Data
    class Obj {
        private Integer id;
        private String name;
        // 如果属性是对象的话,请求的参数可以通过 obj2.id 的形式来传参(级联操作)
        private Obj2 obj2;
    }
    
    @Data
    class Obj2 {
        private Integer id;
        private String name;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    注意:前端请求参数赋值到接收的对象的属性上时候,SpringMVC 机制里还实现了将该对象放入到 request 请求域中,可以将这些数据带给需要显示参数的页面(属性名为类名首字母小写)

    存放数据域的操作

    存放数据到 request 域

    方式 1:通过 HttpServletRequest 放入 request 域

    需要导入类 servlet-api.jar 包

    @RequestMapping(value = "/test") 
    public String test(Master master, HttpServletRequest request, HttpServletResponse response) { 
        // 可以手动放入 request 域中
        request.setAttribute("address", "杭州"); 
        // 从本质看:请求响应的方法 return "xx", 是返回了一个字符串,其实本质是返回了一个 ModelAndView 对象,只是默认被封装起来了
        return "ok"; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    方式2:通过请求的方法参数 Map 放入 request 域

    @RequestMapping(value = "/test") 
    public String test(Master master, Map<String,Object> map) { 
        // 原理分析:springmvc 底层会遍历 map ,然后将 map 中的数据放入到 request
        map.put("address", "杭州"); 
        // 如果已经存放在 request 域中的数据将会被覆盖
        map.put("master", null); 
        return "ok"; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    方式 3: 通过返回 ModelAndView 对象实现 request 域数据

    @GetMapping(value = "/test")
    public ModelAndView test(Monster master){
        // 创建 ModelAndView 对象
        ModelAndView modelAndView = new ModelAndView(); 
        // 将需要数据放入到该对象,并将该数据放入到 request 域中
        modelAndView.addObject("address","杭州");
        // 指定跳转的页面名为 ok 的页面
        modelAndView.setViewName("ok");
        // 返回结果
        return modelAndView;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    存放数据到 session 域

    方式 1:通过 HttpSession 放入 session 域

    @RequestMapping(value = "/test") 
    public String test(Master master, HttpSession session) { 
        session.setAttribute("address","杭州");
        return "ok"; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    自定义视图

    工作流程概述
    1. SpringMVC 调用目标方法, 返回自定义 View 在 IOC 容器中的 id
    2. SpringMVC 调用 BeanNameViewResolver 解析视图(从 IOC 容器中获取返回 id 值对应的 bean, 即自定义的 View 的对象)
    3. SpringMVC 调用自定义视图的 renderMergedOutputModel 方法渲染视图

    注意:如果在 SpringMVC 调用目标方法, 返回自定义 View 在 IOC 容器中的 id 不存在, 则仍然按照默认的视图处理器机制处理

    代码实现
    // 自定义视图
    @Component(value="view")
    public class MyView extends AbstractView { 
        @Override 
        protected void renderMergedOutputModel(Map<String, Object> map, HttpServletRequest req, HttpServletResponse resp) throws Exception { 
            System.out.println("进入到自己的视图"); 
            // 确定到哪个页面去,默认的视图解析机制就无效 
            req.  
                ("/WEB-INF/pages/my_view.jsp").forward(req, resp); 
        } 
    }
    
    // handler 控制层
    @RequestMapping(value = "/test") 
    public String test(Master master, HttpSession session) {
        return "view"; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    配置视图解析器

    
    <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"> 
        
        <property name="order" value="99">property> 
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    源码分析

    BeanNameViewResolver 的源码分析

    public class BeanNameViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered {
        // 优先级设置
        private int order = 2147483647;
    
        public BeanNameViewResolver() {
        }
    
        public void setOrder(int order) {
            this.order = order;
        }
    
        public int getOrder() {
            return this.order;
        }
    
        // 视图解析器
        @Nullable
        public View resolveViewName(String viewName, Locale locale) throws BeansException {
            ApplicationContext context = this.obtainApplicationContext();
            // ioc 容器中是否存在该 beanName 对象名
            if (!context.containsBean(viewName)) {
                return null; 
                // 查看类型是否匹配,因为 AbstractView 实现了 View 接口,所以就是查看是否继承了 AbstractView 类
            } else if (!context.isTypeMatch(viewName, View.class)) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Found bean named '" + viewName + "' but it does not implement View");
                }
                return null;
            } else {
                // 获取到 View 对象
                return (View)context.getBean(viewName, View.class);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    InternalResourceViewResolver 默认视图源码分析

    注意:默认视图解析器(优先级高)一旦执行,则不再执行自定义视图解析器

    public class InternalResourceViewResolver extends UrlBasedViewResolver {
        private static final boolean jstlPresent = ClassUtils.isPresent("javax.servlet.jsp.jstl.core.Config", InternalResourceViewResolver.class.getClassLoader());
        @Nullable
        private Boolean alwaysInclude;
    
        public InternalResourceViewResolver() {
            Class<?> viewClass = this.requiredViewClass();
            if (InternalResourceView.class == viewClass && jstlPresent) {
                viewClass = JstlView.class;
            }
    
            this.setViewClass(viewClass);
        }
    
        // 配置文件中有配置该信息
        public InternalResourceViewResolver(String prefix, String suffix) {
            this();
            // 获取到前缀和后缀 拼接 url
            // 
            // 
            this.setPrefix(prefix);
            this.setSuffix(suffix);
        }
    
        public void setAlwaysInclude(boolean alwaysInclude) {
            this.alwaysInclude = alwaysInclude;
        }
    
        protected Class<?> requiredViewClass() {
            return InternalResourceView.class;
        }
    
        protected AbstractUrlBasedView instantiateView() {
            return (AbstractUrlBasedView)(this.getViewClass() == InternalResourceView.class ? new InternalResourceView() : (this.getViewClass() == JstlView.class ? new JstlView() : super.instantiateView()));
        }
    
        protected AbstractUrlBasedView buildView(String viewName) throws Exception {
            // 通过前缀 + viewName + 后缀,拼接出 url 并创建出 view 对象
            InternalResourceView view = (InternalResourceView)super.buildView(viewName);
            if (this.alwaysInclude != null) {
                view.setAlwaysInclude(this.alwaysInclude);
            }
    
            view.setPreventDispatchLoop(true);
            return view;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    请求转发、重定向

    注意事项:

    1. 默认处理器返回的方式是请求转发,然后用视图解析器来进行处理(如上述)

    2. 可以在目标方法指定重定向或转发的 url 地,可以请求转发到 /WEBN-INF 目录中的资源

      // handler 控制层
      @RequestMapping(value = "/test") 
      public String test() {
          // 指定转发的 url 地址
          return " v  :url"; 
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    3. 可以使用重定向,但是注意不能重定向到 /WEBN-INF 目录中的资源

      // handler 控制层
      @RequestMapping(value = "/test") 
      public String test() {
          return "redirect:url"; 
       }
      
      • 1
      • 2
      • 3
      • 4
      • 5

    文件的上传和下载

    文件的下载

    @RequestMapping("/download")
    public ResponseEntity<byte[]> downloadFile(HttpSession session) throws IOException {
        // 1.获取资源的流
        InputStream resourceAsStream = session.getServletContext().getResourceAsStream("/imgs/1.png");
    
        // 2.将资源流数据保存到二进制数组里
        byte[] bytes = new byte[resourceAsStream.available()];
        resourceAsStream.read(bytes);
    
        // 3.组装 ResponseEntity 数据进行返回
        // 3.1参数(@Nullable T body, @Nullable MultiValueMap headers, HttpStatus status)
        final HttpStatus CG = HttpStatus.OK;
        MultiValueMap<String, String> headers = new HttpHeaders();
        // 3.2以附件的形式进行下载
        headers.add("Content-Disposition","attachment;filename=2.png");
        return new ResponseEntity<byte[]>(bytes,headers,CG);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    文件的上传

    引入依赖

    <dependency>
        <groupId>commons-fileuploadgroupId>
        <artifactId>commons-fileuploadartifactId>
        <version>1.3.1version>
    dependency>
    <dependency>
        <groupId>commons-iogroupId>
        <artifactId>commons-ioartifactId>
        <version>2.2version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    配置 spring xml 文件

    
    <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
          id="multipartResolver"/>
    
    • 1
    • 2
    • 3

    代码实现

    /**
      * 文件上传
      */
    @RequestMapping("/upload")
    public void uploadFile(@RequestParam("file") MultipartFile file,
                           @RequestParam("introduce") String introduce){
        System.out.println("文件介绍: " + introduce);
        try {
            // 传入文件名
            String originalFilename = file.getOriginalFilename();
            // 文件资源路径(根目录 + 文件夹 + 文件名) 
            String filePath = this.getClass().getResource("").getPath() + "/uploadFile/" + originalFilename;
            // 创建文件夹
            File saveFile = new File(filePath);
            // 文件是否存在
            if(!saveFile.exists()){
                // 创建文件
                saveFile.mkdirs();
            }
            // 文件保存到资源路径
            file.transferTo(saveFile);
            System.out.println("文件接收成功");
        } catch (IOException e) {
            System.out.println("文件上传失败" + e.getMessage());
        }finally{
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    拦截器

    概述 :对请求进行拦截处理(类似 javaWeb 的过滤器)

    条件 :自定义拦截器必须实现 HandlerInterceptor 接口

    方法

    • preHandle() 目标方法处理请求之前调用
    • postHandle() 目标方法处理完请求之后调用
    • afterCompletion() 主要进行一些资源清理的操作

    注意事项

    • 如果 preHandle() 方法返回 false,则不再执行 postHandle() 方法 以及 afterCompletion() 方法

    示意图

    image-20230110223137664

    代码实现

    拦截器的相关配置是放在 spring.xml 文件中

    
       
    <mvc:interceptors>
        
        <ref bean="myInterceptor01"/>
    mvc:interceptors>
    
            
    <mvc:interceptors>
        
        <mvc:interceptor>
            <mvc:mapping path="/path"/>
            <ref bean="myInterceptor01"/>
        mvc:interceptor>
    mvc:interceptors>
    
            
    <mvc:interceptors>
        
        <mvc:interceptor>
            <mvc:mapping path="/h*"/>
            <mvc:exclude-mapping path="/hello"/>
            <ref bean="myInterceptor01"/>
        mvc:interceptor>
    mvc:interceptors>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    拦截器的实现

    @Component
    public class MyInterceptor01 implements HandlerInterceptor {
    
        /**
         * 目标方法处理请求之前调用
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println();
            return false;
        }
    
        /**
         * 目标方法处理完请求之后调用
         */
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        }
    
        /**
         * 视图渲染后被执行,可以做资源清理工作
         */
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    多个拦截器流程示意图

    注意:配置前后就表示拦截器的先后顺序

    image-20230116225746582

    异常处理

    概述:SpringMVC 通过 HandlerExceptionResolver 处理程序异常,包括:Handler 映射、数据绑定以及目标方法执行时发生的异常

    注解:@ExceptionHandler({Exception.class、…等等局部异常类})

    匹配机制:首先去寻找本类是否有被上述注解修饰的方法,如果有,则被该方法捕获,反之则找到 @ControllerAdvice 修饰的类的该注解修饰的方法,可以用作全局异常处理器

    格式:

    // 局部异常
    @ExceptionHandler({Exception.class})
    public String localException(Exception e){
        // 显示异常信息
        System.out.println("异常信息" + e.getMessage();
        return "xxx";
    }
    
    // 全局异常
    @ControllerAdvice
    class GlobalExcepiton{
        @ExceptionHandler({Exception.class})
        public String localException(Exception e){
            // 显示异常信息
            System.out.println("异常信息" + e.getMessage();
            return "xxx";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    优先级:局部异常捕获的优先级高于全局异常捕获

    注意:自定义异常查看 JavaSE 基础

  • 相关阅读:
    创邻科技获评环紫金港创新生态圈智源创新企业
    使用 类加载器 或者 类对象 读取文件
    视频批量加水印:保护版权,提升效率
    计算机毕业设计选题大全-springboot高校党务管理系统java源码调试、开题、lw
    react路由v6版本NavLink的两个小坑及解决
    模型压缩与量化
    传感模块:MATEKSYS Optical Flow & LIDAR 3901-L0X
    【VR开发】【Unity】0-课程简介和概述
    用Python来开发安卓程序:(1)BeeWare安卓开发环境的搭建
    C++异常和断言
  • 原文地址:https://blog.csdn.net/Al_tair/article/details/127428930