SpringBoot使用validation-api实现参数校验的示例
作者:溪源的奇思妙想 发布时间:2022-12-02 14:33:40
我们在开发Java项目的时候,经常需要对参数进行一些必填项、格式、长度等进行校验,如果手写代码对参数校验,每个接口会需要很多低级的代码,这样会降低代码的可读性。那么我们能不能使用一种比较优雅的方式来实现,对请求中的参数进行校验呢?
knife4j的安装与使用可参考我的博客:SpringBoot使用knife4j进行在线接口调试
正文
ValidationApi框架就是用来解决参数校验中代码冗余问题,ValidationApi
框架提供一些注解用来帮助我们对请求参数进行校验:
SpringBoot使用validation-api实现参数校验
注入依赖
<!--参数校验-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<!--提供一些字符串操作-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<optional>true</optional>
</dependency>
<!--knife4j接口-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>
UserPojoReq.java请求封装类
如果成员变量是其他对象实体,该变量必须加 @Valid
,否则嵌套中的验证不生效
@Setter
@Getter
@ToString
@ApiModel("用户对象")
public class UserPojoReq extends Request implements Serializable {
private static final long serialVersionUID = -354657839724457905L;
@ApiModelProperty(required = true, notes = "主键", example = "123")
private String id;
@ApiModelProperty(required = true, notes = "用户名", example = "luo")
@NotNull(message = "用户姓名为必填项,不得为空")
@Size(min = 2,max = 20,message = "用户名长度要在2—8个字符")
private String name;
@ApiModelProperty(required = true, notes = "消息", example = "消息")
private String msg;
}
CouponTypeEnum.class :错误码枚举类
@Getter
public enum CouponTypeEnum {
PARAMETER_ERROR(1001, "请求参数有误!"),
UNKNOWN_ERROR(9999, "未知的错误!”);
/**
* 状态值
*/
private int couponType;
/**
* 状态描述
*/
private String couponTypeDesc;
CouponTypeEnum(int couponType, String couponTypeDesc){
this.couponType = couponType;
this.couponTypeDesc = couponTypeDesc;
}
public static String getDescByType(int couponType) {
for (CouponTypeEnum type : CouponTypeEnum.values()) {
if (type.couponType == couponType) {
return type.couponTypeDesc;
}
}
return null;
}
public String getcouponTypeStr(){
return String.valueOf(this.couponType);
}
}
BusinessException.java:自定义业务异常类
/**
* 业务自定义异常
*/
@Getter
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = -1895174013651345407L;
private final CouponTypeEnum errorCode;
private String primaryErrorCode;
private String primaryErrorMsg;
private String primaryErrorIP;
public BusinessException(CouponTypeEnum errorCode) {
this(errorCode, errorCode.getCouponTypeDesc());
}
public BusinessException(CouponTypeEnum errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public BusinessException(CouponTypeEnum errorCode, String message,String primaryErrorCode,String primaryErrorMsg,String primaryErrorIP) {
super(message);
this.errorCode = errorCode;
this.primaryErrorCode=primaryErrorCode;
this.primaryErrorMsg=primaryErrorMsg;
this.primaryErrorIP=primaryErrorIP;
}
public BusinessException(CouponTypeEnum errorCode,String primaryErrorCode,String primaryErrorMsg,String primaryErrorIP) {
this(errorCode, errorCode.getCouponTypeDesc());
this.primaryErrorCode=primaryErrorCode;
this.primaryErrorMsg=primaryErrorMsg;
this.primaryErrorIP=primaryErrorIP;
}
}
GlobalExceptionHandler.class 拦截异常并统一处理
MissingServletRequestParameterException
:必填项为null异常HttpMessageNotReadableException
:参数类型不匹配异常MethodArgumentNotValidException
:JSON校验失败异常(比如长度等)BusinessException
:自定义的异常Exception
:其他异常
@RestControllerAdvice("com.luo.producer.controller")
@Slf4j
public class GlobalExceptionHandler {
/**
* 忽略参数异常处理器
*
* @param e 忽略参数异常
* @return Response
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MissingServletRequestParameterException.class)
public Response parameterMissingExceptionHandler(MissingServletRequestParameterException e) {
log.error("", e);
return new Response(CouponTypeEnum.PARAMETER_ERROR.getcouponTypeStr(), "请求参数 " + e.getParameterName() + " 不能为空");
}
/**
* 缺少请求体异常处理器
*
* @param e 缺少请求体异常
* @return Response
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(HttpMessageNotReadableException.class)
public Response parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {
log.error("", e);
return new Response(CouponTypeEnum.PARAMETER_ERROR.getcouponTypeStr(), "参数体不能为空");
}
/**
* 参数效验异常处理器
*
* @param e 参数验证异常
* @return ResponseInfo
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Response parameterExceptionHandler(MethodArgumentNotValidException e) {
log.error("", e);
// 获取异常信息
BindingResult exceptions = e.getBindingResult();
// 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
if (exceptions.hasErrors()) {
List<ObjectError> errors = exceptions.getAllErrors();
if (!errors.isEmpty()) {
// 这里列出了全部错误参数,按正常逻辑,只需要第一条错误即可
FieldError fieldError = (FieldError) errors.get(0);
return new Response(CouponTypeEnum.PARAMETER_ERROR.getcouponTypeStr(), fieldError.getDefaultMessage());
}
}
return new Response(CouponTypeEnum.PARAMETER_ERROR);
}
/**
* 自定义参数错误异常处理器
*
* @param e 自定义参数
* @return ResponseInfo
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({BusinessException.class})
public Response paramExceptionHandler(BusinessException e) {
log.error("", e);
// 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
if (!StringUtils.isEmpty(e.getMessage())) {
return new Response(CouponTypeEnum.PARAMETER_ERROR.getcouponTypeStr(), e.getMessage());
}
return new Response(CouponTypeEnum.PARAMETER_ERROR);
}
/**
* 其他异常
*
* @param e
* @return
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({Exception.class})
public Response otherExceptionHandler(Exception e) {
log.error("其他异常", e);
// 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
if (!StringUtils.isEmpty(e.getMessage())) {
return new Response(CouponTypeEnum.UNKNOWN_ERROR.getcouponTypeStr(), e.getMessage());
}
return new Response(CouponTypeEnum.UNKNOWN_ERROR);
}
}
验证
测试接口
@Valid
被标记的实体将会开启一个校验的功能
@RequestBody
:请求实体需要加上@RequestBody
否则MethodArgumentNotValidException
异常将会被识别成Exception
异常,提示信息将与预期不符。
@RestController
@Slf4j
public class UserController {
@PostMapping("/helloluo")
@MyPermissionTag(value = "true")
public String helloluo(@RequestBody @Valid UserPojoReq userPojoReq){
return "Hello World”+userPojoReq;
}
}
模拟请求参数,进行接口访问:
来源:https://blog.csdn.net/weixin_40990818/article/details/108427242


猜你喜欢
- 欲达此目的,可以采用下列两种作法: ◆使用XmlConvert类。 ◆将一个XSLT转换套用至DataSet数据的XML表示。 程序范例 本
- 本文实例为大家分享了Unity实现俄罗斯方块的具体代码,供大家参考,具体内容如下一、使用SpriteRenderer作为小方块图片,创建7种
- 本文实例讲述了C#封装的常用文件操作类。分享给大家供大家参考。具体如下:这个C#类封装了我们经常能用到的文件操作方法,包括读写文件、获取文件
- List接口是Collection接口的子接口,List有一个重要的实现类--ArrayList类,List中的元素是有序排列的而且可重复,
- 导航是指支持用户导航、进入和退出应用中不同内容片段的交互。Android Jetpack 的导航组件可帮助您实现导航,无论是简单的按钮点击,
- springmvc @RequestBody String类型参数通过如下配置: <bean id="mapp
- 计算机在执行程序时,为了提高性能,编译器和处理器常常会对指令重排,一般分为以下三种:源代码 -> 编译器优化的重排 -> 指令并
- 1.首先,八种基本数据类型分别是:int、short、float、double、long、boolean、byte、char; &
- 以前公司的产品已经上线20多年了,主要是维护,也就是改bug。每周我们Team会从Jira上拿我们可以改的bug,因为每个团队负责的业务范围
- 目录对zygote的理解作用启动流程启动入口脚本讲解启动过程App_main::mainAndroidRuntime::start对zygo
- 本文实例为大家分享了Android studio实现简单计算器的具体代码,供大家参考,具体内容如下需求分析及概要设计目的开发一个简单的计算器
- XSS ,全名:cross-site scripting(跨站点脚本),是当前 web 应用中最危险和最普遍的漏洞之一。攻击者尝试注入恶意脚
- 引言周五去面试又被面试的一个问题问哑巴了面试官:StringBuilder和StringBuffer的区别在哪?我:StringBuilde
- 本文实例为大家分享了java统计文件中字符个数的具体代码,供大家参考,具体内容如下package com.zhu.io;import jav
- 查询数据会比较耗时,所以我们想把查询数据放在一个异步任务中,查询结果获得Cursor,然后在onPostExecute (Cursor re
- 做Android开发五年了,期间做做停停(去做后台开发,服务器管理),当回来做Android的时候,发现很生疏,好
- 个人感觉mob平台功能还是比较强大的,很多功能都可以通过他们平台来实现。建议仔细观看每一个步骤,如果一个步骤没处理好,可能就会让你的这个功能
- 题目一(有关传值调用与非法访问)请问运行Test 函数会有什么样的结果?答 :程序运行会崩溃 ! 且存在内存泄漏 ;原因:1.str传给p的
- 对于config文件,一般情况下都是使用ConfigurationManager加载,然后通过读取相应节点的值来获取想要的数据,但是,有时候
- Spring Data 概述Spring Data用于简化数据库访问,支持NoSQL 和 关系数据存储,其主要目标是使数据库的访问变得方便快