如何优雅的做参数校验-JSR330
前言:
本文不是讲@Validate、@Valid是如何使用的、区别是什么,想看这些内容的请换篇文章。
背景:
当前端传过来的参数是进行对称性加密、base64加密等处理后过的参数时,在controller接口使用@Validae、@Valid 主键是没用的。
接口收到加密参数后,第一步应该是解密,然后再转换为实际的参数。那么判断参数字段是否符合条件又要写代码去判断了,不够优雅。
那么我是怎么做的呢?看下文...
假设我们现在有一个登录接口,大概是下面这样↓↓↓↓↓↓↓↓↓↓↓
原本的登录逻辑
@PostMapping(value = "/login")
public R login(@RequestParam(value = "param") String param){
// 1:将参数解密出来拿到解密后的字符串(对称性解密)
String realParam = rsa.decryptStr(encryptParamsVO.getParams(), KeyType.PrivateKey, StandardCharsets.UTF_8);
// 2:将解密后的字符串转换为dto
LoginDto dto = JSON.parseObject(realParam , UserDto.class);
// 3:靠代码进行字段规则判断
if(StringUtils.isBlank(dto.getUsername)){
throw new ServiceException("password不能为空");
}
if(StringUtils.isBlank(dto.getPassword)){
throw new ServiceException("password不能为空");
}
// 4:校验通过后登陆
userService.login(dto);
return R.success();
}
可以看到第三步有这明显的缺陷,如果 LoginDto 参数一多,那么就要写很多 if 语句代码来进行判断,这样势必是不优雅的写法。
参数类
@Data
public class LoginDto {
@NotBlank(message = "用户名不能为空")
@Size(min = 6, max = 16, message = "用户名格式不正确")
private String username;
@NotBlank(message = "密码不能为空")
@Size(min = 8, max = 16, message = "密码格式不正确")
private String password;
}
这个类其实才是接口中实际用到的参数类。而它本身的字段其实是用了@NotNull、@Size注解修饰过的,只不过没有起到作用。
那么参数在解密后转换为 LoginDto 后如何让这些注解起到原本的作用呢?
自己写个工具类
@Slf4j
public class JSRValidatorUtil {
private final static Validator VALIDATOR = Validation.byProvider(HibernateValidator.class)
.configure()
.buildValidatorFactory().getValidator();
public static <T> void validate(T param) {
Set<ConstraintViolation<T>> validate = VALIDATOR.validate(param);
validate.forEach(v -> {
log.error("JSR校验异常,property:{},message:{}", v.getPropertyPath(), v.getMessage());
throw new ServiceException(v.getMessage());
});
}
}
看看测试效果:
@Test
public void validateTest() {
LoginDto loginDto = new LoginDto();
loginDto.setUsername("123456");
loginDto.setPassword("123456");
JSRValidatorUtil.validate(loginDto);
}

利用Spring自带的Validator、SpringValidatorAdapter
@Resource
private SpringValidatorAdapter adapter;
@Resource
private Validator validator;
@Test
public void validate() {
LoginDto loginDto = new LoginDto();
loginDto.setUsername("123456");
loginDto.setPassword("123456");
Set<ConstraintViolation<LoginDto>> validate1 = adapter.validate(loginDto);
Set<ConstraintViolation<LoginDto>> validate2 = validator.validate(loginDto);
validate1.forEach(v -> logger.error("JSR校验异常,property:{},message:{}", v.getPropertyPath(), v.getMessage()));
validate2.forEach(v -> logger.error("JSR校验异常,property:{},message:{}", v.getPropertyPath(), v.getMessage()));
}

自定义符合JSR330规范的注解
很多场景下需要自定义注解实现的,比如字段属性为 性别、密码、身份证 等等。
自定义一个密码格式校验注解:
@Constraint(validatedBy = PasswordValidation.class)
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Password {
String message() default "密码必须包含大小写英文字符、数字、特殊字符";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
规则实现类:
public class PasswordValidation implements ConstraintValidator<Password, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
boolean haveDigit = false;
boolean uppercase = false;
boolean lowercase = false;
boolean special = false;
char v;
for (int i = 0; i < value.length(); i++) {
v = value.charAt(i);
if (Character.isDigit(v))
haveDigit = true;
else if (Character.isUpperCase(v))
uppercase = true;
else if (Character.isLowerCase(v))
lowercase = true;
}
if (Pattern.compile("[ _`~!@#$%^&*()+=|{}':;,\\[\\].<>/?!¥…()—【】‘;:”“’。,、?]|\n|\r|\t").matcher(value).find())
special = true;
return haveDigit && uppercase && lowercase && special;
}
}
使用@Password 注解修饰
@Password
private String password;
看效果:

如何优雅的做参数校验-JSR330的更多相关文章
- 使用hibernate validate做参数校验
1.为什么使用hibernate validate 在开发http接口的时候,参数校验是必须有的一个环节,当参数校验较少的时候,一般是直接按照校验条件做校验,校验不通过,返回错误信息.比如以下校验 ...
- 寻找写代码感觉(十六)之 集成Validation做参数校验
写在前面 今天是大年初五了... 不知不觉,又要上班了,美好的假期只剩一天了,有点不舍呢! 也不知道为什么,总感觉像在做梦一样,像没睡醒一样,并不是因为眼睛小,更多应该是自寻烦恼,想得多罢了. 参数校 ...
- SpringBoot Validation优雅的全局参数校验
前言 我们都知道在平时写controller时候,都需要对请求参数进行后端校验,一般我们可能会这样写 public String add(UserVO userVO) { if(userVO.getA ...
- 如何在 Spring/Spring Boot 中做参数校验?你需要了解的都在这里!
本文为作者原创,如需转载请在文首著名地址,公众号转载请申请开白. springboot-guide : 适合新手入门以及有经验的开发人员查阅的 Spring Boot 教程(业余时间维护中,欢迎一起维 ...
- 如何在 Spring/Spring Boot 中做参数校验
数据的校验的重要性就不用说了,即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据. 本文结合自己在项目 ...
- spring mvc +@Valid +@RequestBody 来做参数校验返回400,并且不显示具体message 如何解决
参考文档: https://www.oschina.net/question/115867_2282711 谢谢原作者
- 全栈项目|小书架|服务器开发-Koa2 参数校验处理
为什么需要做参数校验 在开发中,无论是App开发还是服务器接口开发, 我们无法去预测用户传入的数据,因此参数(数据)校验是开发中不可或缺的一环. 例如像App的注册登录表单提交页面,就要做好多层的判断 ...
- SpringBoot中通过实现WebMvcConfigurer完成参数校验
在Spring5.0和SpringBoot2.0中废弃了WebMvcConfigurerAdapter类. 现有两种解决方案 1 直接实现WebMvcConfigurer (官方推荐)2 直接继承We ...
- 为List<T>中的T进行参数校验
1.现在前端发送了一个POST请求,他的Data是一个数组,而不是对象(jsonObj的值两侧是中括号). var jsonObj = [{'id':11, 'name':'叵'}, {'id':12 ...
随机推荐
- 构建基于表单配置的 Jenkins 测试项目(接口、UI、APP、Jmeter)
1. 第一个 hello world 项目 2. 构建自动触发的项目(接口测试) 1)新建测试项目(执行测试脚本) 2)新建 Maven 打包项目 3)手动执行构建 4)修改 Web 工程代码并 pu ...
- 软件调研——GoodNotes 5与Notability
项目 内容 这个作业属于哪个课程 2021春季软件工程(罗杰 任健) 这个作业的要求在哪里 作业要求 我在这个课程的目标是 积累软件开发经验,提高工程能力 这个作业在哪个具体方面帮助我实现目标 深入调 ...
- 1036 Boys vs Girls
This time you are asked to tell the difference between the lowest grade of all the male students and ...
- 07- Linux常用命令
cat命令 作用:将文件内容作为标准输出打印到终端. 格式:cat 文件名1 文件名2 例如: cat more命令: 作用:分页显示文本文件的内容 格式:more 文件名 实例:more he ...
- UVA11375火柴(递推+大数)
题意: 给你n根火柴,问你能组成多少种数字,比如3根可以组成1或者7,组成的数字中不能有前导0, 思路: 我们开一个数组,d[i]记录用i跟火柴可以组成多少种数字,则更新状态是 ...
- [CTF]ROT5/13/18/47位移密码
[CTF]ROT5/13/18/47位移密码 ---------------转换网站 https://www.qqxiuzi.cn/bianma/ROT5-13-18-47.php ROT5:只对数字 ...
- 『动善时』JMeter基础 — 8、JMeter主要元件介绍
目录 1.测试计划(Test Plan) 2.线程组 3.取样器(sampler) 4.逻辑控制器(Logic Controller) 5.配置元件(Config Element) 6.定时器(Tim ...
- 【js】Leetcode每日一题-完成所有工作的最短时间
[js]Leetcode每日一题-完成所有工作的最短时间 [题目描述] 给你一个整数数组 jobs ,其中 jobs[i] 是完成第 i 项工作要花费的时间. 请你将这些工作分配给 k 位工人.所有工 ...
- Java中volatile关键字你真的理解了吗?
面:你怎样理解volatile关键字时? 我:不加思索的说出,volatile修饰的成员变量,可保证线程可见性.不保证原子性和禁止指令重排. 面:你能谈谈什么是线程可见性吗? 我:各个线程对主内存中共 ...
- Handle详解
首先通过一个函数启动一个服务器,只提供一个方法并返回Hello World!,当你在浏览器输入http://127.0.0.1:8080,就会看到Hello World. 对于http.ListenA ...