使用JSR303做后台数据校验是有效确保非法数据绕过前端提交数据,必须确保数据的有效性和准确性。方法步骤如下:
一、引入依赖
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-validation</artifactId>
- <version>2.6.6</version>
- </dependency>
二、在实体类上加入注解
1.@NotNull:不能为null,但可以为empty (“”,”“,”“)
2.@NotEmpty:不能为null,而且长度必须大于0 (”“,”“)
3.@NotBlank:只能作用在String上,不能为null,而且调用trim()后,长度必须大于0
- /**
- * 品牌名
- */
- @NotBlank(message = "品牌名不能为空")
- private String name;
- /**
- * 品牌logo地址
- */
- @NotBlank(message = "品牌logo不能为空")
- @URL(message = "品牌logo必须是合格的http地址")
- private String logo;
- /**
- * 介绍
- */
- @NotBlank(message = "品牌介绍不能为空")
- private String descript;
- /**
- * 显示状态[0-不显示;1-显示]
- */
- private Integer showStatus;
- /**
- * 检索首字母
- */
- @NotBlank(message = "检索首字母不能为空")
- @Pattern(regexp = "/^[a-zA-Z]$/", message = "检索首字母必须是英文字母")
- private String firstLetter;
- /**
- * 排序
- */
- @NotNull
- @Min(value = 0, message = "排序必须大于等于0")
- private Integer sort;
三、后台 controller 中验证提交的信息
提交参数中加入@Valid注解,并通过BindingResult收集验证错误信息。
- public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){
- if(result.hasErrors()){
- Map<String, String> map = new HashMap<>();
- result.getFieldErrors().forEach(item -> {
- // 获取验证不通过字段名
- String field = item.getField();
- // 获取验证不通过字段信息
- String message = item.getDefaultMessage();
- map.put(field, message);
- });
- return R.error(400, "提交数据不合法").put("data", map);
- }else{
- brandService.save(brand);
- return R.ok();
- }
- }
四、通过postman绕过前端测试

五、为了方便在每个controller中使用校验方法,通过AOP切面将校验异常及其他异常整合成一个类。
- /**
- * 集中处理 controller中的异常
- */
- @Slf4j
- @RestControllerAdvice(basePackages = "com.javahorse.gmall.product.controller")
- public class gmallExceptionControllerAdvice {
-
- /**
- * 处理验证异常
- * @param e
- * @return
- */
- @ExceptionHandler(value = MethodArgumentNotValidException.class)
- public R handValidException(MethodArgumentNotValidException e) {
- log.error("数据校验异常:{},异常类型:{}", e.getMessage(), e.getClass());
- BindingResult bindingResult = e.getBindingResult();
- Map<String, String> errorMap = new HashMap<>();
- bindingResult.getFieldErrors().forEach(item -> {
- // 获取验证不通过字段名
- String field = item.getField();
- // 获取验证不通过字段信息
- String message = item.getDefaultMessage();
- errorMap.put(field, message);
- });
- return R.error(BizCodeEnum.VAILD_EXCEPTION.getCode(), BizCodeEnum.VAILD_EXCEPTION.getMsg()).put("data", errorMap);
- }
-
- /**
- * 处理不能精确匹配的其他异常
- * @param throwable
- * @return
- */
- @ExceptionHandler(value = Throwable.class)
- public R handValidException(Throwable throwable) {
-
- return R.error(BizCodeEnum.UNKNOW_EXCEPTION.getCode(), BizCodeEnum.UNKNOW_EXCEPTION.getMsg());
- }
- }
六、设置通用的错误代码及信息枚举类
- /**
- * @desc: 通用错误代码及信息类
- */
- public enum BizCodeEnum {
- UNKNOW_EXCEPTION(10000, "系统未知异常"),
- VAILD_EXCEPTION(10001,"数据校验异常");
-
- private int code;
- private String msg;
-
- BizCodeEnum(int code, String msg) {
- this.code = code;
- this.msg = msg;
- }
-
- public int getCode() {
- return code;
- }
-
- public String getMsg() {
- return msg;
- }
- }
七、修改原先的controller,由于通过AOP切面方式校验,所以不需要在controller中 BindingResult,只需要@Valid 注解就可以通过切面类捕获抛出的异常来达到校验的结果,代码修改如下:
- @RequestMapping("/save")
- public R save(@Valid @RequestBody BrandEntity brand){
- brandService.save(brand);
- return R.ok();
- }
八、测试

msg和code已经变成切面类定义的错误信息了。