首页 > 其他分享 >JSR303数字校验

JSR303数字校验

时间:2022-09-19 16:13:05浏览次数:74  
标签:return 数字 JSR303 校验 private class public String

天空和我的中间,只剩下倾盆的思念

简单校验

使用示例:

  1. 引入对应的校验依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-validation</artifactId>
   <version>2.3.2.RELEASE</version>
</dependency>
  1. 在需要校验的业务字段上添加相应的注解,如:

@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;

/**
* 品牌id
*/
@TableId
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名必须提交")
private String name;
/**
* 品牌logo地址
*/
@NotEmpty
@URL(message = "logo必须是一个合法的url地址")
private String logo;
/**
* 介绍
*/
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
private Integer showStatus;
/**
* 检索首字母
*/
@NotEmpty
@Pattern(regexp = "/^[a-zA-Z]$/", message = "检索首字母必须是一个字母")
private String firstLetter;
/**
* 排序
*/
@NotNull
@Min(value = 0, message = "排序必须大于等于0")
private Integer sort;

}
  1. 在需要校验的方法上(一般是controller方法)添加@Valid注解,在后面追加BindingResult类,相当于错误结果都追加到这个类中

@RequestMapping("/save")
   //@RequiresPermissions("product:brand:save")
   public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){
       if (result.hasErrors()){
           Map<String, String> map = new HashMap<>();
           //1、获取校验的结果
           result.getFieldErrors().forEach((item)->{
               //获取到错误提示
               String message = item.getDefaultMessage();
               //获取到错误属性的名字
               String field = item.getField();
               map.put(field, message);
          });
           return R.error().put("data", map);
      }else{
           brandService.save(brand);
      }
       return R.ok();
  }

统一异常处理

使用示例:

  1. 定义特定错误的状态码,common模块中单独定义一个常量类,用来存储这些错误状态码

/***
* 错误码和错误信息定义类
* 1. 错误码定义规则为5为数字
* 2. 前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 001:系统未知异常
* 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式
* 错误码列表:
* 10: 通用
*     001:参数格式校验
* 11: 商品
* 12: 订单
* 13: 购物车
* 14: 物流
*/
public enum BizCodeEnum {

   UNKNOW_EXEPTION(10000,"系统未知异常"),

   VALID_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;
  }
}
  1. 在product里面新建异常拦截类GulimallExceptionControllerAdvice,用来集中处理所有异常 @ExceptionHandler

@RestControllerAdvice(basePackages = "com.xmh.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {

   // 处理数据校验异常
   @ExceptionHandler(value = MethodArgumentNotValidException.class)
   public R handleVaildException(MethodArgumentNotValidException e){
       BindingResult bindingResult = e.getBindingResult();
       Map<String, String> errorMap = new HashMap<>();
       bindingResult.getFieldErrors().forEach((fieldError)->{
           errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
      });

       return R.error(BizCodeEnume.VALID_EXCEPTION.getCode(),BizCodeEnume.VALID_EXCEPTION.getMsg()).put("data", errorMap);
  }

   //处理全局异常
   @ExceptionHandler(value = Throwable.class)
   public R handleException(Throwable throwable){
       return R.error(BizCodeEnume.UNKNOW_EXEPTION.getCode(), BizCodeEnume.UNKNOW_EXEPTION.getMsg());
  }

}

思考:这样可以做到单个模块的全局异常拦截,但是每一个模块都要单独定义一个感觉不优雅。

改进:可不可以在common模块定义一个所有模块能共用的,后面要用的话,直接在每一个controller类继承这个公共类即可。如:

public class BaseController 
{

   public static final Logger LOGGER = LoggerFactory.getLogger(BaseController.class);

   /**
    * 统一异常处理
    * @param request
    * @param response
    * @param exception
    */
   @ExceptionHandler
   public R exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception)
  {
       LOGGER.error("统一异常处理:", exception);
       request.setAttribute("ex", exception);
       if (null != request.getHeader("X-Requested-With")
               && request.getHeader("X-Requested-With").equalsIgnoreCase("XMLHttpRequest"))
      {
           request.setAttribute("requestHeader", "ajax");
      }
       // 业务异常捕获
       if (exception instanceof NormalRuntimeException)
      {
           exception.printStackTrace();
           return R.fail("操作失败!" + exception.getMessage());
      }
       // 自定义异常捕获
       if (exception instanceof CustomException)
      {
           exception.printStackTrace();
           return R.fail(exception.getMessage());
      }
       return R.fail("未知异常!请稍后再试或联系管理员!");
  }
}

分组校验

使用示例:

  1. 在common中新建valid包,里面新建两个空接口AddGroup,UpdateGroup用来分组

  1. 在需要分组校验的字段上标注分组,如:

@NotEmpty
@NotBlank(message = "品牌名必须非空",groups = {UpdateGroup.class,AddGroup.class})
private String name;
  1. 校验方法上的@Valid注解换成@Validated注解,并标记好分组

@RequestMapping("/save")
public R save(@Valided({AddGroup.class}) @RequestBody BrandEntity brand){
...
}

自定义校验

使用示例:

  1. 编写一个自定义注解接口,如:

@Documented
@Constraint(validatedBy = { ListValueConstraintValidator.class }) //指定校验器 这里指定我们自定义的ListValueConstraintValidator
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
   // 使用我们自己定义的错误信息 在common模块下的resources中
   // String message() default "{com.atguigu.common.valid.ListValue.message}";
   String message() default "值必须是0或者1";

   Class<?>[] groups() default {};

   Class<? extends Payload>[] payload() default {};

   //预先准备的值 vals={0,1}
   int[] vals() default {};
}
  1. 编写一个自定义注解校验器,如

public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
   private Set<Integer> set=new HashSet<>();
   @Override
   public void initialize(ListValue constraintAnnotation) {
       int[] value = constraintAnnotation.vals();
       for (int i : value) {
           set.add(i);
      }

  }

   @Override
   public boolean isValid(Integer value, ConstraintValidatorContext context) {
       return  set.contains(value);
  }
}
  1. 关联检验接口与校验器

@Constraint(validatedBy = {ListValueConstraintValidator.class})
  1. 在需要的字段上进行添加

@ListValue(vals = {0, 1},groups = {AddGroup.class, UpdateGroup.class})
private Integer showStatus;
 

标签:return,数字,JSR303,校验,private,class,public,String
From: https://www.cnblogs.com/l12138h/p/16707996.html

相关文章

  • 给文件添加数字签名
    使用SignTool官方文档:https://learn.microsoft.com/zh-cn/windows/win32/seccrypto/signtool?redirectedfrom=MSDN签名盖时间戳服务器:http://timestamp.sectigo.com/1.......
  • 将后端返回的数字转为文字显示在页面上
    方式一:页面自定义html<span>{{level[ces.level]}}</span>tslevel={1:'等级1',2:'等级2',3:'等级3',}ces={level:1,name:......
  • MySQL生成数字序列/日期序列
    1.MySQL5.7基于自定义变量的方式生成1-10的连续数字序列:SELECT@v:=@v+1ASnFROM(SELECT1UNIONSELECT2)t1,(SELECT1UNIONSELECT2UNIONSELECT3UN......
  • Problem P18. [算法课贪婪]6和9组成的最大数字
    贪心:把9换成6是不可能的,只有把6换成9,而且要换就换最高位的那个6C++:to_string可以将整数转化为string类型,stoi可以将string转化为int类型,这个好用!#i......
  • 剑指 Offer II 004. 只出现一次的数字 【模拟】【位数统计取余】
    题目给你一个整数数组nums,除某个元素仅出现一次外,其余每个元素都恰出现三次。请你找出并返回那个只出现了一次的元素。难度:中等提示:1<=nums.length<=3*10......
  • 剑指 Offer II 003. 前 n 个数字二进制中 1 的个数【模拟】
    题目给定一个非负整数n,请计算0到n之间的每个数字的二进制表示中1的个数,并输出一个数组。难度:简单说明:0<=n<=105题解按照题意模拟即可classSolutio......
  • 咏南数字化中间件助力工业企业数字化转型
    咏南数字化中间件助力工业企业数字化转型。支持跨平台:LINUX,WINDOWS;支持二种数据库引擎UNIDAC,FIREDAC;支持mormot,crosssocket,diocp,brook,rtc通讯;支持RESTFULAPI和......
  • 数字游戏
    原题链接数位DP题目描述:计算[l,r]区间中的非下降数的个数不降数:从高位到低位上各位数字呈非下降关系:如123,446直接上代码Code#include<iostream>#include<cstri......
  • 罗马数字转阿拉伯数字
    1.罗马数字是位置计数吗?并不是。位置计数中数的值是数位和位值的乘积,而罗马数字的计数方法为:罗马数字有八个字母:IVX LCDM,分别表示1、5、10、50、100、500、1000......
  • 报告分享|益普索Ipsos:2022医疗行业数字化营销蓝皮书
    全文链接:http://tecdat.cn/?p=28492 01 、走到哪:医疗企业进行数字化营销转型的前提条件和发展环境日臻完善,但医疗行业数字化营销目前的能力和现处的阶段尚不足以完全支......