SpringMVC全局异常处理+拦截器使用+参数校验

作者 : admin 本文共7738个字,预计阅读时间需要20分钟 发布时间: 2024-06-5 共1人阅读

SpringMVC全局异常处理+拦截器使用+参数校验

文章目录

  • SpringMVC全局异常处理+拦截器使用+参数校验
    • 1 全局异常的处理机制
      • 1.1 异常处理两种方式
      • 1.2 基于注解异常声明异常处理
    • 2 拦截器的使用
      • 2.1 拦截器的概念
      • 2.2 拦截器的使用
    • 3 参数校验

1 全局异常的处理机制

1.1 异常处理两种方式

开发过程中是不可避免地会出现各种异常情况的,例如网络连接异常、数据格式异常、空指针异常等等。异常的出现可能导致程序的运行出现问题,甚至直接导致程序崩溃。因此,在开发过程中,合理处理异常、避免异常产生、以及对异常进行有效的调试是非常重要的。

对于异常的处理,一般分为两种方式:

  • 编程式异常处理:是指在代码中显式地编写处理异常的逻辑。它通常涉及到对异常类型的检测及其处理,例如使用 try-catch 块来捕获异常,然后在 catch 块中编写特定的处理代码,或者在 finally 块中执行一些清理操作。在编程式异常处理中,开发人员需要显式地进行异常处理,异常处理代码混杂在业务代码中,导致代码可读性较差。
  • 声明式异常处理:则是将异常处理的逻辑从具体的业务逻辑中分离出来,通过配置等方式进行统一的管理和处理。在声明式异常处理中,开发人员只需要为方法或类标注相应的注解(如 @Throws@ExceptionHandler),就可以处理特定类型的异常。相较于编程式异常处理,声明式异常处理可以使代码更加简洁、易于维护和扩展。

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

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

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

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

1.2 基于注解异常声明异常处理

//@ControllerAdvice   //可以返回逻辑视图  转发和重定向的!
@RestControllerAdvice   //@ResponseBody  直接返回json字符串
public class GlobalExceptionHandler {

    /**
     * 算数异常的处理
     * @return
     */
    @ExceptionHandler(ArithmeticException.class)
    public Object ArithmeticException(ArithmeticException e){
        //自定义处理异常即可  handler
        String message = e.getMessage();
        System.out.println("message = " + message);
        return message;
    }

    /**
     * 全局异常 当精确查找不到对应的异常时  就查找父异常
     */
    @ExceptionHandler(Exception.class)
    public Object ExceptionHandler(Exception e){
        //自定义处理异常即可 handler
        String message = e.getMessage();
        System.out.println("message = " + message);
        return message;
    }
}

2 拦截器的使用

2.1 拦截器的概念

拦截器 Springmvc VS 过滤器 javaWeb:

  • 相似点
    • 拦截:必须先把请求拦住,才能执行后续操作
    • 过滤:拦截器或过滤器存在的意义就是对请求进行统一处理
    • 放行:对请求执行了必要操作后,放请求过去,让它访问原本想要访问的资源
  • 不同点
    • 工作平台不同
      • 过滤器工作在 Servlet 容器中
      • 拦截器工作在 SpringMVC 的基础上
    • 拦截的范围
      • 过滤器:能够拦截到的最大范围是整个 Web 应用
      • 拦截器:能够拦截到的最大范围是整个 SpringMVC 负责的请求
    • IOC 容器支持
      • 过滤器:想得到 IOC 容器需要调用专门的工具方法,是间接的
      • 拦截器:它自己就在 IOC 容器中,所以可以直接从 IOC 容器中装配组件,也就是可以直接得到 IOC 容器的支持

选择:

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

image-20240604150349001
img

2.2 拦截器的使用

package com.atguigu.interceptor;

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

/**
 * @author XXDTG
 * @version 1.0
 * @api 自定义拦截器
 * @since 2024年 月 日
 */
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 + ", response = " + response + ", handler = " + handler);
        return true;
    }

    /**
     * 当handler执行完毕后  prehandler return 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 {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 整体处理完毕调用的方法
     * @param request
     * @param response
     * @param handler
     * @param ex    handler报错了 异常对象
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

package com.atguigu.config;
import com.atguigu.interceptor.MyInterceptor;
import org.springframework.context.annotation.Bean;
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;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
/**
* @author XXDTG
* @version 1.0
* @api 项目的配置类 controller handlerMapping handlerAdapter加入ioc容器
* @since 2024年 月 日
*/
@EnableWebMvc   //handlerAdapter配置json转化器
@Configuration
@ComponentScan("com.atguigu")
public class MvcConfig implements WebMvcConfigurer {
/**
* 开启静态资源查找
* @param configurer
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
/**
* 拦截器
* 如果使用了多个拦截器 则先声明的优先级高  优先级高的在外层
* 先执行优先级高的preHandler方法 最后执行优先级高的post/after方法
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
//配置方案一:拦截全部请求
registry.addInterceptor(new MyInterceptor());
//配置方案二:指定地址拦截
/*
* 任意一层字符串
** 任意多层字符串
*/
registry.addInterceptor(new MyInterceptor())
//   /user/** 拦截user下所有请求
.addPathPatterns("/user/**");
//配置方案三:排除拦截
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/user/**")
.excludePathPatterns("/user/data1");
}
}

3 参数校验

image-20240604154451009

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

  1. 校验概述

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

注解规则
@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)标注值必须符合指定的正则表达式

JSR 303 只是一套标准,需要提供其实现才可以使用。Hibernate Validator 是 JSR 303 的一个参考实现,除支持所有标准的校验注解外,它还支持以下的扩展注解:

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

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 在完成数据绑定后执行数据校验的工作。

导入依赖

<!-- 校验注解 -->
<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>
package com.atguigu.pojo;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Past;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;
import java.util.Date;
/**
* @author XXDTG
* @version 1.0
* @api 参数校验
* @since 2024年 月 日
*/
@Data
public class User {
/**
* name  不为null和空字符串
字符串不为空 @NotBlank     集合不为空 @NotEmpty  包装不为空 @NotNull
* password  长度大于6
* age 必须 >= 1
* email 邮箱格式的字符串
* birthday 过去时间
*/
@NotBlank
private String name;
@Length(min = 6)
private String password;
@Min(1)
private int age;
@Email
private String email;
@Past
private Date birthday;
}
/**
* @author XXDTG
* @version 1.0
* @api
* @since 2024年 月 日
*/
@Controller
@RequestMapping("user")
public class UserController {
/**
* 步骤一:  实体类属性添加检验注解
* 步骤二:  handler(@validated实体类 对象)
* 细节:  param | json 校验注解都有效果
*          json参数  - @RequestBody
* 如果 不符合校验规则 直接向前端抛出异常
* 接收错误绑定信息!自定义返回结果!约定:参数错误 ——》{code:400} -> 前端
* 捕捉错误绑定错误信息
*      1. handler(校验对象,BindingResult result) 要求:BindingResult必须紧挨着校验对象
*      2. bindingresult获取绑定错误
*/
@PostMapping("register")
public Object register(@Validated @RequestBody User user, BindingResult result){
if(result.hasErrors()){
//有绑定错误 就不直接返回了 自己写处理代码
Map data = new HashMap();
data.put("code",400);
data.put("msg","参数校验异常了");
return data;
}
System.out.println("user = " + user);
return user;
}
}
本站无任何商业行为
个人在线分享 » SpringMVC全局异常处理+拦截器使用+参数校验
E-->