个人客户管理app免费,东莞短视频seo优化,高德地图能否上传vr全景图片,互联网保险乱象一、故事背景
关于参数合法性验证的重要性就不多说了#xff0c;即使前端对参数做了基本验证#xff0c;后端依然也需要进行验证#xff0c;以防不合规的数据直接进入服务器#xff0c;如果不对其进行拦截#xff0c;严重的甚至会造成系统直接崩溃#xff01;
本文结合…一、故事背景
关于参数合法性验证的重要性就不多说了即使前端对参数做了基本验证后端依然也需要进行验证以防不合规的数据直接进入服务器如果不对其进行拦截严重的甚至会造成系统直接崩溃
本文结合自己在项目中的实际使用经验主要以实用为主对数据合法性验证做一次总结不了解的朋友可以学习一下同时可以立马实践到项目上去。
下面我们通过几个示例来演示如何判断参数是否合法废话不多说直接撸起来
二、断言验证
对于参数的合法性验证最初的做法比较简单自定义一个异常类。
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 --
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependency3.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 请输入长度在816位的密码)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})ResponseBodypublic 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 ResultMsgT {/**状态码**/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 ConstraintValidatorSex, String {Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {SetString sexSet new HashSetString();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 请输入长度在816位的密码)private String userPwd;/*** 自定义注解校验*/Sex(message 性别输入有误)private String sex;// set、get方法等...
}启动服务重新请求运行结果如下 结果与预期一致
五、总结
参数验证在开发中使用非常频繁如何优雅的进行验证让代码变得更加可读是业界大佬一直在追求的目标
本文主要围绕在 Spring Boot 中实现参数统一验证进行相关的知识总结和介绍如果有描述不对的地方欢迎留言支持。
示例代码spring-boot-example-valid