【超实用攻略】SpringBoot + validator 轻松实现全注解式的参数校验
一、故事背景
关于参数合法性验证的重要性就不多说了,即使前端对参数做了基本验证,后端依然也需要进行验证,以防不合规的数据直接进入服务器,如果不对其进行拦截,严重的甚至会造成系统直接崩溃!
本文结合自己在项目中的实际使用经验,主要以实用为主,对数据合法性验证做一次总结,不了解的朋友可以学习一下,同时可以立马实践到项目上去。
下面我们通过几个示例来演示如何判断参数是否合法,废话不多说,直接撸起来!
二、断言验证
对于参数的合法性验证,最初的做法比较简单,自定义一个异常类。
public class CommonException extends RuntimeException {
private Integer code;
public Integer getCode() {
return code;
}
public CommonException(String message) {
super(message);
this.code = 500;
}
public CommonException(Integer code, String message) {
super(message);
this.code = code;
}
}
当检查到某个参数不合法的时候,直接抛异常!
@RestController
public class HelloController {
@RequestMapping("/upload")
public void upload(MultipartFile file) {
if (file == null) {
throw new CommonException("请选择上传文件!");
}
//.....
}
}
最后写一个统一异常拦截器,对抛异常的逻辑进行兜底处理。
这种做法比较简单直观,如果当前参数既要判断是否为空,又要判断长度是否超过最大限制的时候,代码就会显得很臃肿,而且复用性很差!
于是,程序界的大佬想到了一个更加优雅又能节省代码的方式,创建一个断言类工具类,专门用来判断参数的是否合法,如果不合法就抛异常,示例如下:
/**
* 断言工具类
*/
public abstract class LocalAssert {
public static void isTrue(boolean expression, String message) throws CommonException {
if (!expression) {
throw new CommonException(message);
}
}
public static void isStringEmpty(String param, String message) throws CommonException{
if(StringUtils.isEmpty(param)) {
throw new CommonException(message);
}
}
public static void isObjectEmpty(Object object, String message) throws CommonException {
if (object == null) {
throw new CommonException(message);
}
}
public static void isCollectionEmpty(Collection coll, String message) throws CommonException {
if (coll == null || (coll.size() == 0)) {
throw new CommonException(message);
}
}
}
当我们需要对参数进行验证的时候,直接通过这个类就可以完成,示例如下:
@RestController
public class HelloController {
@RequestMapping("/save")
public void save(String name, String email) {
LocalAssert.isStringEmpty(name, "用户名不能为空!");
LocalAssert.isStringEmpty(email, "邮箱不能为空!");
//.....
}
}
相比上面的实现方式,这种处理逻辑,代码明显要简洁的多!
类似这样的工具类还很多,比如spring也提供了一个名为Assert的断言工具类,在开发的时候,可以直接使用!
三、注解验证
下面我们要介绍的是另一种更简洁的参数验证逻辑,使用注解来对数据进行合法性验证,不仅代码会变得很简洁,阅读起来也十分令人赏心悦目!
以 Spring Boot 工程为例,下面我们一起来看看具体的实践方式。
3.1、添加依赖包
首先在pom.xml中引入spring-boot-starter-web依赖包即可,它会自动将注解验证相关的依赖包打入工程!
<!-- spring boot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3.2、编写注解校验请求对象
接着创建一个实体User,用于封装用户注册时的请求参数,并在参数属性上添加对应的注解验证规则!
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
public class User {
@NotBlank(message = "用户名不能为空!")
private String userName;
@Email(message = "邮箱格式不正确")
@NotBlank(message = "邮箱不能为空!")
private String email;
@NotBlank(message = "密码不能为空!")
@Size(min = 8, max = 16,message = "请输入长度在8~16位的密码")
private String userPwd;
@NotBlank(message = "确认密码不能为空!")
private String confirmPwd;
// set、get方法等...
}
3.3、编写请求接口
在web层创建一个register()注册接口方法,同时在请求参数上添加@Valid注解,示例如下:
import javax.validation.Valid;
@RestController
public class UserController {
@RequestMapping("/register")
public ResultMsg register(@RequestBody @Valid User user){
if(!user.getUserPwd().equals(user.getConfirmPwd())){
throw new CommonException(4001, "确认密码与密码不相同,请确认!");
}
//业务处理...
return ResultMsg.success();
}
}
3.4、编写全局异常处理器
最后自定义一个异常全局处理器,用于处理异常逻辑,如下:
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 拦截Controller层的异常
* @param e
* @return
*/
@ExceptionHandler(value = {Exception.class})
@ResponseBody
public Object exceptionHandler(HttpServletRequest request, Exception e){
LOGGER.error("【统一异常拦截】请求地址:{}, 错误信息:{}", request.getRequestURI(), e.getMessage());
// 注解验证抛出的异常
if(e instanceof MethodArgumentNotValidException){
// 获取错误信息
String error = ((MethodArgumentNotValidException) e).getBindingResult().getFieldError().getDefaultMessage();
return ResultMsg.fail(500, error);
}
// 自定义抛出的异常
if(e instanceof CommonException){
return ResultMsg.fail(((CommonException) e).getCode(), e.getMessage());
}
return ResultMsg.fail(999, e.getMessage());
}
}
统一响应对象ResultMsg,如下:
public class ResultMsg<T> {
/**状态码**/
private int code;
/**结果描述**/
private String message;
/**结果集**/
private T data;
/**时间戳**/
private long timestamp;
// set、get方法等...
}
3.5、服务测试
启动项目,使用postman来验证一下代码的正确性,看看效果如何?
- 测试字段是否为空

- 测试邮箱是否合法

- 测试密码长度是否符合要求

- 测试密码与确认密码是否相同

可以看到,验证结果与预期一致!
四、自定义注解验证
事实上,熟悉 SpringMVC 源码的同学可能知道,Spring Boot 内置了一个hibernate-validator校验组件,上文就是利用它来完成对请求时入参上的注解验证。
默认的情况下,依赖包已经给我们提供了非常多的校验注解,如下!
- JSR 提供的校验注解!

- Hibernate Validator 提供的校验注解

但是某些情况,例如性别这个参数,可能需要我们自己去手动验证。
针对这种情况,我们也可以自定义一个注解来完成参数的校验,也便于进一步了解注解验证的原理。
自定义注解验证,实现方式如下!
首先,创建一个Sex注解。
@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = SexValidator.class)
@Documented
public @interface Sex {
String message() default "性别值不在可选范围内";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
然后,创建一个SexValidator类,实现自ConstraintValidator接口
public class SexValidator implements ConstraintValidator<Sex, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
Set<String> sexSet = new HashSet<String>();
sexSet.add("男");
sexSet.add("女");
return sexSet.contains(value);
}
}
最后,在User实体类上加入一个性别参数,使用自定义注解进行校验!
public class User {
@NotBlank(message = "用户名不能为空!")
private String userName;
@Email(message = "邮箱格式不正确")
@NotBlank(message = "邮箱不能为空!")
private String email;
@NotBlank(message = "密码不能为空!")
@Size(min = 8, max = 16,message = "请输入长度在8~16位的密码")
private String userPwd;
/**
* 自定义注解校验
*/
@Sex(message = "性别输入有误!")
private String sex;
// set、get方法等...
}
启动服务,重新请求,运行结果如下:

结果与预期一致!
五、总结
参数验证,在开发中使用非常频繁,如何优雅的进行验证,让代码变得更加可读,是业界大佬一直在追求的目标!
本文主要围绕在 Spring Boot 中实现参数统一验证进行相关的知识总结和介绍,如果有描述不对的地方,欢迎留言支持。
示例代码:spring-boot-example-valid
【超实用攻略】SpringBoot + validator 轻松实现全注解式的参数校验的更多相关文章
- 重学SpringBoot. step1 全注解的SpringBoot
参考:<深入浅出SpringBoot 2.x> 全注解的SpringBoot 用户可以通过注解将所需要的对象,存放到IOC容器中,然后SpringBoot可以根据这些需要使用的情况,自动注 ...
- SpringBoot 参数校验的方法
Introduction 有参数传递的地方都少不了参数校验.在web开发中,前端的参数校验是为了用户体验,后端的参数校验是为了安全.试想一下,如果在controller层中没有经过任何校验的参数通过s ...
- Spring MVC 3.0.5+Spring 3.0.5+MyBatis3.0.4全注解实例详解(一)
Spring更新到3.0之后,其MVC框架加入了一个非常不错的东西——那就是REST.它的开放式特性,与Spring的无缝集成,以及Spring框架的优秀表现,使得现在很多公司将其作为新的系统开发框架 ...
- Hibernate Validator参数校验
日常开发中经常会遇到需要参数校验的情况,比如某个字段不能为空.长度不能超过5等都属于参数校验的范围.对于简单的参数校验通过写几个if-else判断语句就搞定,但是对于复杂的多个参数校验的情况,就不是那 ...
- 【转】轻松搞定FTP之FlashFxp全攻略
转载网址:http://www.newhua.com/2008/0603/39163.shtml 轻松搞定FTP之FlashFxp全攻略 导读: FlashFXP是一款功能强大的FXP/FTP软件,融 ...
- Hibernate Validator校验参数全攻略
1. 前言 数据字段一般都要遵循业务要求和数据库设计,所以后端的参数校验是必须的,应用程序必须通过某种手段来确保输入进来的数据从语义上来讲是正确的. 2. 数据校验的痛点 为了保证数据语义的正确,我们 ...
- 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法
若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...
- 从小工到专家 ——读《Java程序员职场全攻略》有感
从小工到专家 ——读<Java程序员职场全攻略>有感 <Java程序员职场全攻略>是以故事的形式,向读者介绍Java程序员的职场经验.作者牛开复在北京从事软件开发,已经是一 ...
- 用C#制作PDF文件全攻略
用C#制作PDF文件全攻略 目 录 前 言... 3 第一部分 iText的简单应用... 4 第一章 创建一个Document 4 第一步 创建一个Document实例:... 5 第二步 ...
- Android使用XML全攻略(2)
Android使用XML全攻略(2) Android 是针对移动设备的一种新兴的开源操作系统和 SDK.借助它,您可以创建功能强大的移动应用程序.当您的应用程序可以访问 Web 服务时,其吸引力会 ...
随机推荐
- 透过 Go 语言探索 Linux 网络通信的本质
前言 各种编程语言百花齐放.百家争鸣,但是 "万变不离其中".对于网络通信而言,每一种编程语言的实现方式都不一样:但其实,调用的底层逻辑都是一样的.linux 系统底层向上提供了统 ...
- Vue cli之组件的嵌套
前面显示Home.vue页面组件的内容时,我们是在App.vue通过import导入使用的.这个过程就是组件的嵌套使用.那么我们除了App.vue可以导入其他页面以外,也可以通过在Home.vue中导 ...
- 探索Semantic Plugins:开启大模型的技能之门
前言 在之前的章节中我们或多或少的已经接触到了 Semantic Kernel 的 Plugins,本章我们讲详细介绍如何使用插件. Semantic Kernel 的一大特点是拥有强大的插件,通过结 ...
- 视图结构 wxml 列表渲染 for
WXML是框架设计的一套标签语言,结合基础组件.事件系统,可以构建出页面的结构. wxml是一个严格的标记性语言,有开始就必须有结束,单标签就一个有结束符 5.1.数据绑定 在js逻辑层中定义数据源, ...
- 自定义动画 jquery的结束动画
<button name="width">改变宽</button> <button name="height"> ...
- vm ware cent os 共享文件夹
1.VM中安装vm-tools 2.在VM 虚拟机设置中添加共享文件夹. 3.重启虚拟机 4.在/mnt/ 里新建一个名为"win"的文件夹 5.在cent os 中执行: vmw ...
- JVM性能分析与故障排查
引言 JVM调优 程序在上线前的测试或运行中有时会出现一些大大小小的JVM问题,比如cpu load过高.请求延迟.tps降低等,甚至出现内存泄漏(每次垃圾收集使用的时间越来越长,垃圾收集频率越来越高 ...
- java rabbitmq模拟生产者,消费者demo
1.exchange类型,rabbitmq交换机类型 exchange类型fanout 扇形交换机,它会把所有发送到该交换机的消息路由到所有与该交换机绑定的队列中.direct 直连交换机,它会把消息 ...
- 如何使用JavaScript实现在线Excel附件的上传与下载?
前言 在本地使用Excel时,经常会有需要在Excel中添加一些附件文件的需求,例如在Excel中附带一些Word,CAD图等等.同样的,类比到Web端,现在很多人用的在线Excel是否也可以像本地一 ...
- Python做点击率数据预测
点击率(Click-Through Rate, CTR)预测是推荐系统.广告系统和搜索引擎中非常重要的一个环节.在这个场景中,我们通常需要根据用户的历史行为.物品的特征.上下文信息等因素来预测用户点击 ...