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

server/2024/9/24 11:23:08/

文章目录

    • 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/server/47979.html

相关文章

无需开孔,安全美观:低功耗微波雷达模块开启宠物喂食器新未来

在快节奏的现代生活中&#xff0c;宠物已成为许多家庭的重要成员。然而&#xff0c;忙碌的主人常常为如何确保宠物按时进食而困扰。近年来&#xff0c;智能家居技术飞速发展&#xff0c;宠物喂食器也逐渐智能化&#xff0c;极大地方便了宠物主人。今天&#xff0c;我们要介绍的…

ES 生命周期管理

一 .概念 ILM定义了四个生命周期阶段&#xff1a;Hot&#xff1a;正在积极地更新和查询索引。Warm&#xff1a;不再更新索引&#xff0c;但仍在查询。cold&#xff1a;不再更新索引&#xff0c;很少查询。信息仍然需要可搜索&#xff0c;但是如果这些查询速度较慢也可以。Dele…

安徽某高校数据挖掘作业4-5 (与一些碎碎念)

1. 编写程序求函数、、的极限。 解答&#xff1a; import sympy as sp# 定义符号变量 x x sp.symbols(x)# 定义函数 f1 sp.sin(20 * x) / x f2 (1 4 * x)**(2 / x) f3 (1 4 / x)**(2 * x)# 计算极限 limit1 sp.limit(f1, x, 0) limit2 sp.limit(f2, x, 0) limit3 sp…

从了解到掌握 Spark 计算框架(二)RDD

文章目录 RDD 概述RDD 组成RDD 的作用RDD 算子分类RDD 的创建1.从外部数据源读取2.从已有的集合或数组创建3.从已有的 RDD 进行转换 RDD 常用算子大全转换算子行动算子 RDD 算子综合练习RDD 依赖关系窄依赖宽依赖宽窄依赖算子区分 RDD 血统信息血统信息的作用血统信息的组成代码…

kafka-消费者服务搭建配置简单消费(SpringBoot整合Kafka)

文章目录 1、使用efak 创建 主题 my_topic1 并建立6个分区并给每个分区建立3个副本2、创建生产者发送消息3、application.yml配置4、创建消费者监听器5、创建SpringBoot启动类6、屏蔽 kafka debug 日志 logback.xml7、引入spring-kafka依赖 1、使用efak 创建 主题 my_topic1 并…

c语言项目-贪吃蛇项目2-游戏的设计与分析

文章目录 前言游戏的设计与分析地图&#xff1a;这里简述一下c语言的国际化特性相关的知识<locale.h> 本地化头文件类项setlocale函数 上面我们讲到需要打印★&#xff0c;●&#xff0c;□三个宽字符找到这三个字符打印的方式有两种&#xff1a; 控制台屏幕的长宽特性&a…

java web爬虫

目录 读取本地文件 从网站读取文件 java爬虫 总结 读取本地文件 import java.io.File; import java.io.PrintWriter; import java.util.Scanner;public class ReplaceText {public static void main() throws Ex

天润融通,荣获2024中国AI应用层创新企业

AI技术发展日新月异&#xff0c;可谓“AI一天&#xff0c;人间一年”。 从2023年到2024年&#xff0c;短短一年的时间&#xff0c;大模型技术的发展就已经逐步从追求“技术突破”转向了追求“应用落地”。如何将大模型的技术与企业的生产、运营、销售等场景结合起来&#xff0…