五、SpringMVC其他扩展(全局异常处理机制、拦截器、参数校验)

五、SpringMVC其他扩展

1、全局异常处理机制

1、异常处理的两种方式

1、编程式异常

1、是指在代码中显式地编写处理异常的逻辑。

2、它通常涉及到对异常类型的检测及其处理

3、例如使用 try-catch 块来捕获异常,然后在 catch 块中编写特定的处理代码,或者在 finally 块中执行一些清理操作。

4、在编程式异常处理中,开发人员需要显式地进行异常处理,异常处理代码混杂在业务代码中,导致代码可读性较差。

5、就相当于我们正常写代码,假设每个方法都有异常都要去解决,要么try-catch接收处理异常、要么throw抛出

2、声明式异常

1、是将异常处理的逻辑从具体的业务逻辑中分离出来,通过配置等方式进行统一的管理和处理

2、在声明式异常处理中,开发人员只需要为方法或类标注相应的注解(如 @Throws 或 @ExceptionHandler),就可以处理特定类型的异常

3、相较于编程式异常处理,声明式异常处理可以使代码更加简洁、易于维护和扩展。

4、说人话:就是我们把有可能出现的异常,我们写在一个类中,如果程序会出现该异常,就会被该异常方法捕获。

3、站在宏观角度来看待声明式事务处理:

1、整个项目从架构这个层面设计的异常处理的统一机制和规范。

2、一个项目中会包含很多个模块,各个模块需要分工完成。如果张三负责的模块按照 A 方案处理异常,李四负责的模块按照 B 方案处理异常……各个模块处理异常的思路、代码、命名细节都不一样,那么就会让整个项目非常混乱。

3、使用声明式异常处理,可以统一项目处理异常思路,项目更加清晰明了!

2、基于注解异常声明异常处理

1、思路

  • 我们统一用一个类来处理异常,一个异常就对应一个handler方法

2、实现

  • 就是用到两个注解
  • 一个是放在类上方便的:@RestControllerAdvice
  • @RestControllerAdvice = @ResponseBody+@ControllerAdvice
  • 另外一个是具体方法上:@ExceptionHandler(xxxx.class【异常类】)

3、例子

1、异常类

package com.atgui.error;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice // 如果发生异常,会优先走这个类
public class GlobalExceptionHandler {

//    发生异常:
//    指定的异常:可以精确的指定异常,也可以查找父异常

    @ExceptionHandler(ArithmeticException.class)
    public Object ArithmeticExceptionHandler(ArithmeticException e){
        String message = e.getMessage();
        System.out.println("message = " + message);
        return message;
    }

    @ExceptionHandler(Exception.class)
    public Object ExceptionHandler(Exception e){
        String message = e.getMessage();
        System.out.println("message = " + message);
        return  message;
    }
}

2、可能有异常的controller方法

package com.atgui.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("user")
public class UserController {

    @GetMapping("data1")
    public  void data1() {
        int [] res = new int[1];
        System.out.println("res = " + res[3]);
    }
    @GetMapping("data2")
    public void data2(){
        int a = 1/0;
    }
}

2、拦截器

1、什么是拦截器

1、拦截器和过滤器解决问题

  • 生活中

    为了提高乘车效率,在乘客进入站台前统一检票

    image-20240117175906415

  • 程序中

    在程序中,使用拦截器在请求到达具体 handler 方法前,统一执行检测

    image-20240117175917762

2、拦截器SpringMVC 对比过滤器javaWeb

  • 相似点

    • 拦截:必须先把请求拦住,才能执行后续操作

    • 过滤:拦截器或过滤器存在的意义就是对请求进行统一处理

    • 放行:对请求执行了必要操作后,放请求过去,让它访问原本想要访问的资源

  • 不同点

    • 工作平台不同
    • 过滤器工作在 Servlet 容器中
    • 拦截器工作在 SpringMVC 的基础上
    • 拦截的范围
    • 过滤器:能够拦截到的最大范围是整个 Web 应用
    • 拦截器:能够拦截到的最大范围是整个 SpringMVC 负责的请求
    • IOC 容器支持
    • 过滤器:想得到 IOC 容器需要调用专门的工具方法,是间接的
    • 拦截器:它自己就在 IOC 容器中,所以可以直接从 IOC 容器中装配组件,也就是可以直接得到 IOC 容器的支持

3、选择

  • 功能需要如果用 SpringMVC 的拦截器能够实现,就不使用过滤器。
  • image-20240117180150925

2、拦截器的使用

1、步骤

1、先创建一个拦截器

  • 创建一个类,
  • 这个类实现HandlerInterceptor 接口
  • 有3个方法
  • preHandle()
  • postHandle()
  • afterCompletion()

2、在配置类中添加拦截器组件

  • 实现这个addInterceptors()方法

2、配置类中的详情

1、默认拦截全部

  • 就直接实现这个方法addInterceptors()

2、精准配置拦截

  • 设置路径

  • 就是在实现这个addInterceptors()方法后面添加一个addPathPatterns()方法

  • registry.addInterceptor(new MyInterceptor()).addPathPatterns("/user/**");

3、排除拦截

  • 设置路径
  • 就是在实现这个addPathPatterns()方法后面添加一个方法excludePathPatterns()

3、3个方法介绍

1、preHandle方法

  • 作用
    • 执行handler之前!调用的拦截器!
    • 编码格式设置,登录保护,权限处理

2、postHandle

  • 作用
    • 执行handler之后,返回modelAndView之前 ,对结果处理,敏感词检查
    • 这个方法只能在preHandle方法返回true之后执行

3、afterCompletion方法

  • 作用
    • 整理处理完毕调用!

4、例子

1、拦截器类

package com.atgui.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MyInterceptor implements HandlerInterceptor {

    /**
     * 执行handler之前!调用的拦截器!
     * 编码格式设置,登录保护,权限处理
     * @param request 请求对象
     * @param response 响应对象
     * @param handler 我们handler调用的方法
     * @return true是放行,false是拦截
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("request = " + request);
        return true;
    }

    /**
     *  执行handler之后,返回modelAndView之前 ,对结果处理,敏感词检查
     *  这个方法只能在preHandle方法返回true之后执行
     * @param request 请求
     * @param response 响应
     * @param handler handler方法
     * @param modelAndView 返回的视图和共享域对象
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor.postHandle");
    }

    /**
     * 整理图例完毕调用!
     * @param request current HTTP request
     * @param response current HTTP response
     * @param handler the handler that started asynchronous
     * execution, for type and/or instance examination
     * @param ex any exception thrown on handler execution, if any; this does not
     * include exceptions that have been handled through an exception resolver
     * @throws Exception 捕获异常对象
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor.afterCompletion");
    }
}

2、配置类设置

package com.atgui.config;

import com.atgui.interceptor.MyInterceptor;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@ComponentScan("com.atgui")
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
//        配置方法1:拦截全部请求
//        registry.addInterceptor(new MyInterceptor());
//        配置方法2:指定地址拦截.addPathPatterns("/xxx/xxx");
//                也可以模糊:*:任意字符串;**:任意多层字符串
//        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/user/**");
//        配置方法3:排除拦截 排除的地址应该拦截地址的内部
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/user/**").excludePathPatterns("/user/data1");
    }
}

5、多个拦截器执行的顺序

1、图解

image-20240117181536787

2、执行

  • preHandle() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置顺序调用各个 preHandle() 方法。
  • postHandle() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置相反的顺序调用各个 postHandle() 方法。
  • afterCompletion() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置相反的顺序调用各个 afterCompletion() 方法。

3、底层代码中,先按List集合来遍历执行preHandle()方法

4、然后再按List集合相反顺序来遍历postHandle() 、postHandle() 、afterCompletion()

3、参数校验

1、在 Web 应用三层架构体系中,表述层负责接收浏览器提交的数据,业务逻辑层负责数据的处理。为了能够让业务逻辑层基于正确的数据进行处理,我们需要在表述层对数据进行检查,将错误的数据隔绝在业务逻辑层之外。

2、图解

image-20240117192455756

1、校验概述

1、JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 6.0 标准中。JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证。

2、注解

1、基本

注解 规则
@Null 标注值必须为 null
@NotNull 标注值不可为 null
@AssertTrue 标注值必须为 true
@AssertFalse 标注值必须为 false
@Min(value) 标注值必须大于或等于 value
@Max(value) 标注值必须小于或等于 value
@DecimalMin(value) 标注值必须大于或等于 value
@DecimalMax(value) 标注值必须小于或等于 value
@Size(max,min) 标注值大小必须在 max 和 min 限定的范围内
@Digits(integer,fratction) 标注值值必须是一个数字,且必须在可接受的范围内
@Past 标注值只能用于日期型,且必须是过去的日期
@Future 标注值只能用于日期型,且必须是将来的日期
@Pattern(value) 标注值必须符合指定的正则表达式

2、扩展

@Email 标注值必须是格式正确的 Email 地址
@Length 标注值字符串大小必须在指定的范围内
@NotEmpty 标注值字符串不能是空字符串
@Range 标注值必须在指定的范围内

3、补充说明

  • Spring 4.0 版本已经拥有自己独立的数据校验框架,同时支持 JSR 303 标准的校验框架。Spring 在进行数据绑定时,可同时调用校验框架完成数据校验工作。在SpringMVC 中,可直接通过注解驱动 @EnableWebMvc 的方式进行数据校验。
  • Spring 的 LocalValidatorFactoryBean 既实现了 Spring 的 Validator 接口,也实现了 JSR 303 的 Validator 接口。只要在Spring容器中定义了一个LocalValidatorFactoryBean,即可将其注入到需要数据校验的 Bean中。
  • Spring本身并没有提供JSR 303的实现,所以必须将JSR 303的实现者的jar包放到类路径下。
  • 配置 @EnableWebMvc后,SpringMVC 会默认装配好一个 LocalValidatorFactoryBean,通过在处理方法的入参上标注 @Validated 注解即可让 SpringMVC 在完成数据绑定后执行数据校验的工作。

3、操作步骤

1、导入相关依赖

<!-- 校验注解 -->
<dependency>
    <groupId>jakarta.platform</groupId>
    <artifactId>jakarta.jakartaee-web-api</artifactId>
    <version>9.1.0</version>
    <scope>provided</scope>
</dependency>

<!-- 校验注解实现-->        
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>8.0.0.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator-annotation-processor -->
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator-annotation-processor</artifactId>
    <version>8.0.0.Final</version>
</dependency>

2、实体类属性添加校验注解

3、handler方法参数前添加@Validated注解

4、BindingResult对象获取校验错误信息

5、 如果不符合校验郭泽,直接向前端抛出错误

  • 接收绑定错误,自定义返回结果
  • 捕获错误绑定信息
    • 1、handler(校验对象,BindingResult result
    • 2、BindingResult result.hasErrors()绑定错误信息

4、例子

1、创建实体类

package com.atgui.pojo;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Past;
import lombok.Data;
import org.hibernate.validator.constraints.Length;

@Data
public class User {

    @NotNull
    private String name;
    @Length(min = 6)
    private  String password;
    @Min(1)
    private  int age;
    @Email
    private   String email;
    @Past
    private Data birthDate;
}

2、添加控制器及注解

/*
        步骤
            1、导入依赖
            2、实体类属性添加校验注解
            3、handler方法参数前添加@Validated注解
            4、BindingResult对象获取校验错误信息

        如果不符合校验郭泽,直接向前端抛出错误
        接收绑定错误,自定义返回结果
        捕获错误绑定信息
            1、handler(校验对象,BindingResult result
            2、BindingResult result.hasErrors()绑定错误信息
     */
    @PostMapping("register")
    public Object register(@Validated @RequestBody User user, BindingResult result){
//        设置绑定错误,
        if(result.hasErrors()){
            Map data = new HashMap();
            data.put("code",400);
            return data;
        }

        System.out.println("user = " + user);
        return user;
    }

5、注意

1、一定要加Validated注解。否则无法实现

2、如果需要抛出错误,就必须实现BindingResult result。紧挨着所需要校验的实体类。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇