统一响应,自定义校验器,自定义异常,统一异常处理器

embedded/2024/9/24 11:27:26/

文章目录

    • 1.基本准备(构建一个SpringBoot模块)
        • 1.在A_universal_solution模块下创建新的子模块unified-processing
        • 2.pom.xml引入基本依赖
        • 3.编写springboot启动类
        • 4.启动测试
    • 2.统一响应处理
        • 1.首先定义一个响应枚举类 RespBeanEnum.java 每个枚举对象都有code和message
        • 2.然后定义一个响应的Bean RespBean.java ,可以调用响应枚举类,进行响应
        • 3.测试使用
          • 1.目录结构
          • 2.ResponseTest.java
          • 3.浏览器测试
            • 1.成功响应,不携带数据。
            • 2.成功响应,携带数据。
            • 3.失败响应,不携带数据。
            • 4.失败响应,携带数据。
            • 5.测试withData方法。
            • 6.测试withMessage方法。
    • 3.自定义校验器
        • 1.首先编写一个Bean测试使用,LoginVo.java
        • 2.需求分析
        • 3.通用校验器模板
          • 1.定义通用校验器接口 GenericValidatorInterface.java
          • 2.自定义校验注解 GenericValidation.java
          • 3.通用校验器实现类 GenericValidatorImpl.java
          • 4.使用方式
            • 1.需求分析
            • 2.将模板复制一份,放到validator包下,准备进行修改
            • 3.要校验的字段为Integer类型,也就是修改value类型
            • 4.注解中的value是int数组类型,也就是修改annotationValue的类型
            • 5.修改三个类的名字前缀为Test,直接修改然后alter +enter 让IDEA自动修改
            • 6.TestValidatorImpl.java编写校验逻辑
            • 7.修改LoginVo.java 添加测试校验字段
            • 8.编写controller加上@Valid字段进行校验
            • 9.测试
    • 4.统一异常处理器整合自定义校验器
        • 1.编写自定义异常携带响应枚举对象 CustomException.java
        • 2.编写全局异常处理器 GlobalExceptionHandler.java
        • 3.最佳实践
          • 1.当需要响应error时直接抛出自定义异常对象,指定响应枚举对象
          • 2.此时当出现参数绑定异常时也会交给统一异常处理解决
          • 3.当出现其他异常时,就会响应服务端异常,控制台也会打印错误信息

1.基本准备(构建一个SpringBoot模块)

1.在A_universal_solution模块下创建新的子模块unified-processing

image-20240506125441280

2.pom.xml引入基本依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><!-- 继承spring-boot父模块 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.4</version><relativePath/> <!-- 如果交给父模块统一管理,但是又要继承springboot的父模块,就必须加这个 --></parent><artifactId>unified-processing</artifactId><packaging>jar</packaging><name>unified-processing</name><url>http://maven.apache.org</url><!-- 解决java: -source 1.5 中不支持 diamond 运算符 问题 --><properties><java.version>1.8</java.version><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><!--validation 参数校验--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>2.4.5</version></dependency><!-- springboot两个常规配置 --><!-- spring-boot-starter-web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- spring-boot-starter-test --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- lombok也是常规配置 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- jupiter测试 --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.7.2</version><scope>compile</scope></dependency></dependencies><!-- maven打包插件--><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
3.编写springboot启动类
java">package com.sun.solution;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** Description:** @Author sun* @Create 2024/5/6 13:00* @Version 1.0*/
@SpringBootApplication
public class UnifiedApplication {public static void main(String[] args) {SpringApplication.run(UnifiedApplication.class, args);}
}
4.启动测试

image-20240506130251247

2.统一响应处理

java_codemessage_117">1.首先定义一个响应枚举类 RespBeanEnum.java 每个枚举对象都有code和message
java">package com.sxs.seckill.vo;import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;/*** Description: 响应枚举类** @Author sun* @Create 2024/5/5 15:15* @Version 1.0*/@Getter
@AllArgsConstructor
@ToString
public enum RespBeanEnum {// 通用SUCCESS(200, "SUCCESS"),ERROR(500, "服务端异常"),//登录模块LOGIN_ERROR(500210, "用户名或者密码错误"),MOBILE_ERROR(500211, "手机号码格式不正确"),BING_ERROR(500212, "参数绑定异常"),MOBILE_NOT_EXIST(500213, "手机号码不存在"),PASSWORD_UPDATE_FAIL(500214, "更新密码失败");//其他模块。。。// 响应码和响应信息private final Integer code;private final String message;
}
java__156">2.然后定义一个响应的Bean RespBean.java ,可以调用响应枚举类,进行响应
java">package com.sxs.seckill.vo;import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;/*** 通用响应数据封装类。* 提供了构造函数和静态方法来创建响应对象,支持链式调用来设置属性。*/
@Getter
@Setter
@Accessors(chain = true) // 支持链式调用
public class RespBean {private long code;private String message;private Object data;/*** 默认构造函数。*/public RespBean() {}/*** 构造函数,初始化响应码和消息。* @param code 响应码。* @param message 响应消息。*/public RespBean(long code, String message) {this.code = code;this.message = message;}/*** 构造函数,初始化响应码、消息和数据。* @param code 响应码。* @param message 响应消息。* @param data 响应数据。*/public RespBean(long code, String message, Object data) {this.code = code;this.message = message;this.data = data;}/*** 成功响应,携带数据。* @param data 响应数据。* @return 生成的成功响应对象。*/public static RespBean success(Object data) {return new RespBean(RespBeanEnum.SUCCESS.getCode(), RespBeanEnum.SUCCESS.getMessage(), data);}/*** 成功响应,不携带数据。* @return 生成的成功响应对象。*/public static RespBean success() {return new RespBean(RespBeanEnum.SUCCESS.getCode(), RespBeanEnum.SUCCESS.getMessage(), null);}/*** 错误响应,只携带错误枚举。* @param respBeanEnum 错误枚举,包含错误码和消息。* @return 生成的错误响应对象。*/public static RespBean error(RespBeanEnum respBeanEnum) {return new RespBean(respBeanEnum.getCode(), respBeanEnum.getMessage(), null);}/*** 错误响应,携带错误枚举和额外数据。* @param respBeanEnum 错误枚举,包含错误码和消息。* @param data 额外数据。* @return 生成的错误响应对象。*/public static RespBean error(RespBeanEnum respBeanEnum, Object data) {return new RespBean(respBeanEnum.getCode(), respBeanEnum.getMessage(), data);}/*** 设置响应数据。* @param data 响应数据。* @return 当前对象,支持链式调用。*/public RespBean withData(Object data) {this.data = data;return this;}/*** 设置响应消息。* @param message 响应消息。* @return 当前对象,支持链式调用。*/public RespBean withMessage(String message) {this.message = message;return this;}
}
3.测试使用
1.目录结构

image-20240506131857665

java_269">2.ResponseTest.java
java">package com.sun.solution.conroller;import com.sun.solution.unified_response_processing.RespBean;
import com.sun.solution.unified_response_processing.RespBeanEnum;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** Description:** @Author sun* @Create 2024/5/6 13:07* @Version 1.0*/
@RestController
public class ResponseTest {/*** 成功响应,不携带数据。** @return*/@RequestMapping("/success1")public RespBean success1() {return RespBean.success();}/*** 成功响应,携带数据。** @return*/@RequestMapping("/success2")public RespBean success2() {return RespBean.success("成功响应,携带数据。");}/*** 失败响应,不携带数据。** @return*/@RequestMapping("/error1")public RespBean error1() {return RespBean.error(RespBeanEnum.ERROR);}/*** 失败响应,携带数据。** @return*/@RequestMapping("/error2")public RespBean error2() {return RespBean.error(RespBeanEnum.ERROR, "失败响应,携带数据。");}/*** 测试withData方法** @return*/@RequestMapping("/withData")public RespBean withData() {return RespBean.error(RespBeanEnum.ERROR).withData("测试withData方法");}/*** 测试withMessage方法** @return*/@RequestMapping("/withMessage")public RespBean withMessage() {return RespBean.error(RespBeanEnum.ERROR).withMessage("测试withMessage方法");}}
3.浏览器测试
1.成功响应,不携带数据。

image-20240506132159483

2.成功响应,携带数据。

image-20240506132322584

3.失败响应,不携带数据。

image-20240506132344487

4.失败响应,携带数据。

image-20240506132403115

5.测试withData方法。

image-20240506132427551

6.测试withMessage方法。

image-20240506132447397

3.自定义校验器

java_381">1.首先编写一个Bean测试使用,LoginVo.java
java">package com.sun.solution.vo;import lombok.Data;/*** Description:** @Author sun* @Create 2024/5/6 13:29* @Version 1.0*/
@Data
public class LoginVo {private String mobile;private String password;
}
2.需求分析
自定义校验器来校验手机号和密码
3.通用校验器模板
java_408">1.定义通用校验器接口 GenericValidatorInterface.java
java">package com.sun.solution.validator;/*** Description: 通用校验器接口,用于重新定义校验方法,使其更加灵活** @Author sun* @Create 2024/5/6 13:34* @Version 1.0*/public interface GenericValidatorInterface {/*** 校验接口* @param value 待校验的值,根据情况自定义类型* @param annotationValue 注解中的value值,根据情况自定义类型* @param required 是否必填* @return*/boolean isValid(String value, String annotationValue, boolean required);
}
java_434">2.自定义校验注解 GenericValidation.java
java">package com.sun.solution.validator;import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;/*** Description: 自定义校验注解** @Author sun* @Create 2024/5/6 13:38* @Version 1.0*/
@Documented
@Constraint(validatedBy = GenericValidatorImpl.class) // 1.这里是校验器的实现类
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface GenericValidation {// 2.这里是注解的属性// message是校验失败时的提示信息String message() default "校验失败!";// value是注解的值,可以根据情况自定义类型,类型改变则校验器也需要改变String value() default "";// required是是否必填boolean required() default true;// 下面这两个属性必须添加,是默认属性Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
java_470">3.通用校验器实现类 GenericValidatorImpl.java
java">package com.sun.solution.genericvalidator;import org.springframework.util.StringUtils;import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;/*** Description: 通用校验器实现类,ConstraintValidator<TestValidation, String>中的两个参数分别是注解和校验的值类型** @Author sun* @Create 2024/5/6 13:42* @Version 1.0*/
public class GenericValidatorImpl implements ConstraintValidator<GenericValidation, String>, GenericValidatorInterface {// 注解中的value值,根据情况自定义类型private String annotationValue;// 注解中的required值,表示是否必填private boolean required;/*** 初始化方法,获取注解中的value值和required值* @param annotation*/@Overridepublic void initialize(GenericValidation annotation) {this.annotationValue = annotation.value();this.required = annotation.required();}/*** 初始的校验方法* @param value* @param context* @return*/@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {return isValid(value, annotationValue, required);}/*** 增强的校验方法* @param value 待校验的值* @param annotationValue 注解中的value值,根据情况自定义类型* @param required 是否必填* @return*/@Overridepublic boolean isValid(String value, String annotationValue, boolean required) {// 校验逻辑编写,根据三个参数进行校验return false;}
}
4.使用方式
1.需求分析

假设,要校验的字段类型是Integer类型,注解中的value是int数组类型

2.将模板复制一份,放到validator包下,准备进行修改

image-20240506142134488

3.要校验的字段为Integer类型,也就是修改value类型

GenericValidatorInterface.java

image-20240506142712265

GenericValidatorImpl.java

image-20240506142756701

4.注解中的value是int数组类型,也就是修改annotationValue的类型

GenericValidation.java

image-20240506143335834

GenericValidatorImpl.java

image-20240506143407645

GenericValidatorInterface.java

image-20240506143434441

5.修改三个类的名字前缀为Test,直接修改然后alter +enter 让IDEA自动修改

image-20240506143656011

java_569">6.TestValidatorImpl.java编写校验逻辑
java">    /*** 增强的校验方法* @param value 待校验的值* @param annotationValue 注解中的value值,根据情况自定义类型* @param required 是否必填* @return*/@Overridepublic boolean isValid(Integer value, int[] annotationValue, boolean required) {// 如果不是必填项,且值为空,则直接返回trueif (!required && value == null) {return true;}// 如果是必填项,且值为空,则直接返回falseif (required && value == null) {return false;}// 如果注解中的value值不为空,且待校验的值不在value值中,则返回falseif (annotationValue.length > 0) {for (int i : annotationValue) {if (value == i) {return true;}}return false;}return true;}
java__602">7.修改LoginVo.java 添加测试校验字段
java">package com.sun.solution.vo;import com.sun.solution.validator.TestValidation;
import lombok.Data;/*** Description:** @Author sun* @Create 2024/5/6 13:29* @Version 1.0*/
@Data
public class LoginVo {private String mobile;private String password;@TestValidation(value = {1, 2, 3}, required = true)private Integer test;
}
8.编写controller加上@Valid字段进行校验
java">package com.sun.solution.conroller;import com.sun.solution.unified_response_processing.RespBean;
import com.sun.solution.vo.LoginVo;
import org.springframework.web.bind.annotation.*;import javax.validation.Valid;/*** Description:** @Author sun* @Create 2024/5/6 14:56* @Version 1.0*/
@RestController
public class ValidationTest {@PostMapping("/test")public RespBean test(@Valid @RequestBody LoginVo loginVo) {return RespBean.success("success!");}
}
9.测试

image-20240506150821623

image-20240506150835102

4.统一异常处理器整合自定义校验器

java_662">1.编写自定义异常携带响应枚举对象 CustomException.java
java">package com.sun.solution.exception;import com.sun.solution.unified_response_processing.RespBeanEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** Description: 自定义异常类,具有响应枚举的属性。** @Author sun* @Create 2024/5/6 15:15* @Version 1.0*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CustomException extends RuntimeException{private RespBeanEnum respBeanEnum;
}
java_688">2.编写全局异常处理器 GlobalExceptionHandler.java
java">package com.sun.solution.exception;import com.sun.solution.unified_response_processing.RespBean;
import com.sun.solution.unified_response_processing.RespBeanEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;/*** Description:** @Author sun* @Create 2024/5/6 15:16* @Version 1.0*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {// 处理所有的异常@ExceptionHandler(Exception.class)public RespBean exceptionHandler(Exception e) {// 日志记录异常信息及堆栈log.error("Exception caught: ", e); // 如果得到的是自定义异常的对象,那么直接返回这个异常的响应枚举类信息if (e instanceof CustomException) {CustomException ex = (CustomException) e;return RespBean.error(ex.getRespBeanEnum());} else if (e instanceof BindException) {// 如果是绑定异常,就获取绑定异常的message信息,返回给前端// 需要获取改异常 BindException,进行打印BindException ex = (BindException) e;// 获取绑定异常的信息RespBean respBean = RespBean.error(RespBeanEnum.BING_ERROR).withMessage("参数校验异常:" +ex.getBindingResult().getAllErrors().get(0).getDefaultMessage());return respBean;}// 如果不是自定义异常,那么返回服务端异常return RespBean.error(RespBeanEnum.ERROR);}
}
3.最佳实践
1.当需要响应error时直接抛出自定义异常对象,指定响应枚举对象

image-20240506153836780

image-20240506153848112

2.此时当出现参数绑定异常时也会交给统一异常处理解决

image-20240506154042389

3.当出现其他异常时,就会响应服务端异常,控制台也会打印错误信息

image-20240506154219232

image-20240506154225690


http://www.ppmy.cn/embedded/46706.html

相关文章

k8s集群修改apiserver的ip地址

有时候由于服务器的调整&#xff0c;导致ip的的变化&#xff0c;k8s集群的api大管家的ip变动会导致kubectl的接口都无法正常使用&#xff0c;这是只需要将k8s主节点配置文件的ip替换即可。 例如无需要将原来的192.168.146.202的ip替换成192.168.85.202&#xff0c;执行一下操作…

四川古力未来科技抖音小店安全靠谱,购物新体验

在数字化浪潮席卷而来的今天&#xff0c;电商行业蓬勃发展&#xff0c;各种线上购物平台如雨后春笋般涌现。其中&#xff0c;抖音小店凭借其独特的短视频直播购物模式&#xff0c;迅速赢得了广大消费者的青睐。而四川古力未来科技抖音小店&#xff0c;更是以其安全靠谱、品质保…

SpringBoot读取json文件

使用SpringBoot读取json文件作为接口&#xff0c;前端Vue可以通过跨域访问接口数据 一、创建SpringBoot 文件 创建一个 SpringBoot 文件&#xff0c;文件结构目录如下&#xff1a; 二、在pom.xml添加依赖 <!--Spring Boot 依赖--> <parent><artifactId>sp…

【2024新版】银系统源码/超市收银系统/智慧新零售/ERP进销存管理/线上商城/商户助手

>>>系统简述&#xff1a;本系统适用于超吃便利店&#xff0c;美妆母婴行业&#xff0c;服装鞋帽行业&#xff0c;食品零售行业&#xff0c;3C数码电子行业&#xff0c;食品生鲜等一切零售行业&#xff0c;产品功能角色介绍如下 合伙人&#xff1a;无限发展代理商和商…

小熊家务帮day13-day14 门户管理(ES搜索,Canal+MQ同步,索引同步)

目录 1 服务搜索1.1 需求分析1.2 技术方案1.2.1 使用Elasticsearch进行全文检索&#xff08;为什么数据没有那么多还要用ES&#xff1f;&#xff09;1.2.2 索引同步方案1.2.2.1 Canal介绍1.2.2.1 Canal工作原理 1 服务搜索 1.1 需求分析 服务搜索的入口有两处&#xff1a; 在…

【java前端课堂】04_类的继承

类的继承 在Java中&#xff0c;继承是面向对象编程的四大基本特性之一&#xff0c;它允许我们根据一个已有的类来定义一个新的类&#xff0c;这个新的类继承了原有类的特性&#xff08;属性和方法&#xff09;&#xff0c;并可以添加新的特性或修改原有特性。这样&#xff0c;…

【动态规划】速解简单多状态类问题

目录 17.16 按摩师 题⽬描述&#xff1a; 解法&#xff08;动态规划&#xff09;&#xff1a; 1. 状态表⽰&#xff1a; 2. 状态转移⽅程&#xff1a; 3. 初始化&#xff1a; 4. 填表顺序 5. 返回值 代码 总结&#xff1a; 213.打家劫舍II&#xff08;medium&#x…

多模块工程中Controller中注入Service报错的问题

问题 2024-06-05 22:05:12,241 ERROR [http-nio-8888-exec-1][DirectJDKLog.java:175] - Servlet.service() for servlet [dispatcherServlet] in context with path [/content] threw exception [Request processing failed; nested exception is org.apache.ibatis.binding.…