1.背景

实际开发中对参数进行检查,是常见

比如如下代码

/**
* 参数检查测试(传统做法)
*
* @param dto
* @return
*/
@GetMapping("/paramCheckOld")
public BaseResponse paramCheckOld(@RequestBody UserDTO dto) {
// 参数检查
if (StrUtil.isEmpty(dto.getWeChat())) {
return ResponseBuilder.failed("微信号为空");
}
if (StrUtil.isEmpty(dto.getName())) {
return ResponseBuilder.failed("姓名为空");
} if (dto.getStatus() != null
|| dto.getStatus() != -1
|| dto.getStatus() != 0
|| dto.getStatus() != 1) {
return ResponseBuilder.failed("状态为-1,0,1或者null");
}
// .....如果参数很多这里必然后崩溃..........
// 调用业务方法
// 响应结果
System.out.println("dto=" + dto);
return ResponseBuilder.success("统一参数检查.....");
}

但是正确的做法应该是,这里其实只使用了一个@Validated注解就搞定了,太方便了.....

 /**
* 统一参数检查(牛逼的做法)
*
* @param dto
* @return
*/
@GetMapping("/paramCheck")
public BaseResponse paramCheck(@RequestBody @Validated UserDTO dto) {
// 参数检查(已检查)
// 调用业务方法
// 响应结果
System.out.println("dto=" + dto);
return ResponseBuilder.success("统一参数检查.....");
}

2.步骤

步骤一:引入jar包

 <!--  统一参数校验-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

若果你的参数校验不生效,请注意如下几点

1. spring-boot-starter-validation 中正在执行的是:

2. 笔者在实验中如果引入了  compile group: 'org.hibernate.validator', name: 'hibernate-validator', version: '7.0.0.Alpha6',上面的包会失效,不要引入这个包

3.字段属性注解上是  javax.validation.constraints.NotBlank 包下的;

4.控制层上的参数注解是这个: import org.springframework.validation.annotation.Validated;

步骤二:参数上贴标签

package com.ldp.user.entity.dto;

import com.ldp.user.common.validation.EnumValue;
import lombok.Data; import javax.validation.constraints.NotBlank; /**
* @author 姿势帝-博客园
* @address https://www.cnblogs.com/newAndHui/
* @WeChat 851298348
* @create 01/01 4:00
* @description
*/
@Data
public class UserDTO {
@NotBlank(message = "微信号不能为空")
private String weChat; @NotBlank(message = "姓名不能为空")
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 状态
* -1:冻结用户 ,0:正常用户, 1:没有实名认证
*/
@EnumValue(intValues = {-1, 0, 1}, message = "状态为-1,0,1或者null")
private Integer status;
/**
* 地址
*/
private String address;
}

步骤三:控制层方法上贴标签(当然在其他方法上也可以用的,只是一般我们用在控制层上)

/**
* 统一参数检查(牛逼的做法)
*
* @param dto
* @return
*/
@GetMapping("/paramCheck")
public BaseResponse paramCheck(@RequestBody @Validated UserDTO dto) {
// 参数检查(已检查)
// 调用业务方法
// 响应结果
System.out.println("dto=" + dto);
return ResponseBuilder.success("统一参数检查.....");
}

步骤四:统一参数检查不通过时提示消息获取,注意修改为自己的包路径

package com.qxnw.unicom.exception;

import com.qxnw.unicom.base.ResponseBuilder;
import com.qxnw.unicom.constant.CodeConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.NoHandlerFoundException; import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set; /**
* @Copyright (C)
* @Author: LI DONG PING
* @Date: 2019/4/3 10:10
* @Description: 接口全局异常处理
*/
@ControllerAdvice(basePackages = "com.XXX")
@Slf4j
public class MsgExceptionAdvice { /**
* 参数异常捕获
*
* @param ex
* @return
*/
@ResponseBody
@ExceptionHandler(value = ConstraintViolationException.class)
public Object constraintViolationExceptionHandler(ConstraintViolationException ex) {
Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();
List<String> msgList = new ArrayList<>();
while (iterator.hasNext()) {
ConstraintViolation<?> cvl = iterator.next();
msgList.add(cvl.getMessageTemplate());
}
return ResponseBuilder.failed(msgList.toString());
} /**
* 参数异常捕获
*
* @param ex
* @return
*/
@ResponseBody
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Object methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException ex) {
List<ObjectError> objectErrors = ex.getBindingResult().getAllErrors();
if (!CollectionUtils.isEmpty(objectErrors)) {
StringBuilder msgBuilder = new StringBuilder();
for (ObjectError objectError : objectErrors) {
msgBuilder.append(objectError.getDefaultMessage()).append(",");
}
String errorMessage = msgBuilder.toString();
if (errorMessage.length() > 1) {
errorMessage = errorMessage.substring(0, errorMessage.length() - 1);
}
return ResponseBuilder.failed(errorMessage);
}
return ResponseBuilder.failed(ex.getMessage());
} @ExceptionHandler(BindException.class)
@ResponseBody
public Object getBindException(BindException ex) {
List<ObjectError> objectErrors = ex.getBindingResult().getAllErrors();
if (!CollectionUtils.isEmpty(objectErrors)) {
StringBuilder msgBuilder = new StringBuilder();
for (ObjectError objectError : objectErrors) {
msgBuilder.append(objectError.getDefaultMessage()).append(",");
}
String errorMessage = msgBuilder.toString();
if (errorMessage.length() > 1) {
errorMessage = errorMessage.substring(0, errorMessage.length() - 1);
}
return ResponseBuilder.failed(errorMessage);
}
return ResponseBuilder.failed(ex.getMessage());
} /**
* 不支持当前媒体类型 参数类型不对
*
* @param e
* @return
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
@ResponseBody
public Object handleHttpMediaTypeNotSupportedException(Exception e) {
log.error("不支持当前媒体类型:", e);
return ResponseBuilder.failed(CodeConstant.RET_CODE_999, "不支持当前媒体类型");
} /**
* @param e
* @return
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(IllegalStateException.class)
@ResponseBody
public Object illegalStateException(IllegalStateException e) {
log.error("参数异常:", e);
return ResponseBuilder.failed(CodeConstant.RET_CODE_102, "参数异常"); } /**
* @param e
* @return
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseBody
public Object NoHandlerFoundException(Exception e) {
log.error("请求接口地址有误:", e);
return ResponseBuilder.failed(CodeConstant.RET_CODE_999, "接口地址有误");
} /**
* ParamException
*
* @param e
* @return
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(ParamException.class)
@ResponseBody
public Object paramException(ParamException e) {
log.error("业务异常:", e);
return ResponseBuilder.failed(CodeConstant.RET_CODE_999, e.getMessage());
} /**
* 系统未分类异常
*
* @param e
* @return
*/
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(Exception.class)
@ResponseBody
public Object exceptionHandler(Exception e) {
log.error("系统异常:", e);
// 默认为 系统异常
return ResponseBuilder.failed(e.getMessage());
} }

步骤五测试

  @Test
void paramCheck() {
String url = urlLocal + "/userOrder/paramCheck";
System.out.println("请求地址:" + url);
HttpRequest request = HttpUtil.createRequest(Method.GET, url);
Map<String, Object> map = new TreeMap<>();
// 业务参数
// map.put("weChat", "851298348");
// map.put("name", "李东平");
map.put("age", "18");
map.put("status", "0");
map.put("address", "四川成都"); // 公用参数
map.put("appid", "1001");
map.put("sequenceId", "seq" + System.currentTimeMillis());
map.put("timeStamp", System.currentTimeMillis());
map.put("sign", signApi(map, "123456"));
String param = JSON.toJSONString(map);
request.body(param);
System.out.println("请求参数:" + param);
request.header("Authorization", token);
request.setConnectionTimeout(60 * 1000);
String response = request.execute().body();
System.out.println("请求结果:" + response);
}

测试结果:

{"message":"微信号不能为空,姓名不能为空","code":900}

3.常用检查规则注解

JSR提供的校验注解:
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式 Hibernate Validator提供的校验注解:
@NotBlank(message =) 验证字符串非null,且trim后长度必须大于0
@Email 被注释的元素必须是电子邮箱地址
@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内

4.自定义检查规则注解

如果这些注解还不能满足我们的需求,那么我么可以自己定义满足自己业务规则的注解

这里以自定义一个枚举值检查的注解,这个在实际生产中用的非常普遍

比如在传入用户状态时,只嗯传入-1,0,1或者null,其都是参数不合法的检查注解

https://www.cnblogs.com/newAndHui/p/14185807.html

完美!

springboot整合validation统一参数检查的更多相关文章

  1. # SpringBoot使用Validation校验参数 ##

    SpringBoot使用Validation校验参数 一.简介 参考 (14条消息) 1. 不吹不擂,第一篇就能提升你对Bean Validation数据校验的认知_@decimalmax和@max_ ...

  2. springboot整合mybatis统一配置bean的别名

    mybatis.type-aliases-package=cn.byzt.bean 只需要将 javaBean 的路径配置到 springboot 的配置文件中,这里如果是多个路径,用英文逗号分隔多个 ...

  3. SpringBoot 整合MyBatis 统一配置bean的别名

    所谓别名, 就是在mappper.xml配置文件中像什么resultType="xxx" 不需要写全限定类名, 只需要写类名即可. 配置方式有两种: 1. 在 applicatio ...

  4. spring-boot 使用hibernate validation对参数进行优雅的校验

    springboot天生支持使用hibernate validation对参数的优雅校验,如果不使用它,只能对参数挨个进行如下方式的手工校验,不仅难看,使用起来还很不方便: if(StringUtil ...

  5. SpringBoot学习笔记(七):SpringBoot使用AOP统一处理请求日志、SpringBoot定时任务@Scheduled、SpringBoot异步调用Async、自定义参数

    SpringBoot使用AOP统一处理请求日志 这里就提到了我们Spring当中的AOP,也就是面向切面编程,今天我们使用AOP去对我们的所有请求进行一个统一处理.首先在pom.xml中引入我们需要的 ...

  6. 补习系列(6)- springboot 整合 shiro 一指禅

    目标 了解ApacheShiro是什么,能做什么: 通过QuickStart 代码领会 Shiro的关键概念: 能基于SpringBoot 整合Shiro 实现URL安全访问: 掌握基于注解的方法,以 ...

  7. 七、springboot整合Spring-data-jpa

    1.Spring Data JPA是什么 由Spring提供的一个用于简化JPA开发的框架.可以在几乎不用写实现的情况下,实现对数据的访问和操作.除了CRUD外,还包括如分页.排序等一些常用的功能 1 ...

  8. SpringBoot 整合Shiro 一指禅

    目标 了解ApacheShiro是什么,能做什么: 通过QuickStart 代码领会 Shiro的关键概念: 能基于SpringBoot 整合Shiro 实现URL安全访问: 掌握基于注解的方法,以 ...

  9. SpringBoot整合开发

    1.SpringBoot分模块 分模块就是将一个项目分成多个模块,即maven项目. 1)首先创建一个springboot的项目: 第一步:选择springboot的项目 第二步:填写项目的相关信息, ...

  10. RabbitMQ入门到进阶(Spring整合RabbitMQ&SpringBoot整合RabbitMQ)

    1.MQ简介 MQ 全称为 Message Queue,是在消息的传输过程中保存消息的容器.多用于分布式系统 之间进行通信. 2.为什么要用 MQ 1.流量消峰 没使用MQ 使用了MQ 2.应用解耦 ...

随机推荐

  1. mybatis sqlmap sql in 查询

    <select id="selectBlogs" parameterType="map"> SELECT * FROM blog WHERE use ...

  2. 以沙箱的方式运行容器:安全容器gvisor

    目录 一.系统环境 二.前言 三.安全容器隔离技术简介 四.Gvisor简介 五.容器runtime简介 六.docker容器缺陷 七.配置docker使用gVisor作为runtime 7.1 安装 ...

  3. 使用Microsoft.SemanticKernel基于本地运行的Ollama大语言模型实现Agent调用函数

    大语言模型的发展日新月异,记得在去年这个时候,函数调用还是gpt-4的专属.到今年本地运行的大模型无论是推理能力还是文本的输出质量都已经非常接近gpt-4了.而在去年gpt-4尚未发布函数调用时,智能 ...

  4. IT运维全面数字化|芯片设计行业领跑打造运维流程闭环

    在当今数字化转型的浪潮中,科技行业正经历着前所未有的变革.随着5G.人工智能.物联网等新兴技术的快速发展,企业对于高效.智能的运营模式的需求日益迫切. 芯片设计公司作为科技产业链中的关键一环,不仅要在 ...

  5. Ubuntu 使用 SVN 管理 项目

    背景 公司的项目需要在 Linux 环境进行开发,而都是使用 SVN 进行管理的.习惯了 SVN-GUI 的我,需要学习 SVN 的命令行. 准备 安装 SVN sudo apt-get apt-ge ...

  6. 2024年,AI驱动测试管理工具会有哪些发展前景呢?

    随着人工智能技术的日新月异,2024年的测试管理工具将迎来全新的发展机遇.AI赋能将助力测试管理工具实现前所未有的智能化升级,为软件研发团队带来革命性的变革. 一.什么是AI? 人工智能(AI)是一种 ...

  7. CosyVoice多语言、音色和情感控制模型,one-shot零样本语音克隆模型本地部署(Win/Mac),通义实验室开源

    近日,阿里通义实验室开源了CosyVoice语音模型,它支持自然语音生成,支持多语言.音色和情感控制,在多语言语音生成.零样本语音生成.跨语言声音合成和指令执行能力方面表现卓越. CosyVoice采 ...

  8. 国内版Unity 6 Preview编辑器无法切换到DX12的解决方案(6000.0.5f1c1已解决)

    先放解决方案的链接:https://www.cnblogs.com/horeaper/p/18200364 6000.0.0f1c1问题依旧,仍然是没有D3D12文件夹: 不仅新文件不加,旧文件(ha ...

  9. TP5 连接多个数据库

    use think\Config; $config = Config::get('database2'); //读取第二个数据库配置 $connect = Db::connect($config); ...

  10. oeasy教您玩转 linux 010212 管道 pipe

    上一部分我们都讲了什么? 牛说cowsay 牛可以有各种表情 可以自定义眼睛 可以变成各种别的小动物 可以说也可以想cowthink 我们也想让牛说出字符画的感觉 回顾字符画 下载figlet和toi ...