pig 参数校验及技巧

参数校验简单体验

目前pig系统的common-core核心包支持 JSR-303参数校验,通过 spring-boot-starter-validation实现,底层基于Hibernate Validator。

先来看个简单例子。

Java POJO定义中引入注解。@NotBlank就代表了所注解的元素值为字符串且该字符串不为空。

  1. @Data
  2. @EqualsAndHashCode(callSuper = true)
  3. public class SysDept extends Model<SysDept> {
  4. private static final long serialVersionUID = 1L;
  5. private Integer deptId;
  6. /**
  7. * 部门名称
  8. */
  9. @NotBlank(message = "部门名称不能为空")
  10. private String name;
  11. /**
  12. * 父级部门id
  13. */
  14. private Integer parentId;
  15. // 省略部分代码
  16. }

使用的话在Controller 通过@Valid注解激活校验即可。代码如下:

  1. /**
  2. * 添加
  3. * @param sysDept 实体
  4. * @return success/false
  5. */
  6. @SysLog("添加部门")
  7. @PostMapping
  8. @PreAuthorize("@pms.hasPermission('sys_dept_add')")
  9. public R save(@Valid @RequestBody SysDept sysDept) {
  10. return R.ok(sysDeptService.saveDept(sysDept));
  11. }

为什么要做参数验证?

永远不要相信我们在后端接收到的用户数据。

  1. 防止恶意用户通过精心构造的参数破坏我们的系统
  2. 保证我们的业务有序进行

即使前端已经校验过,因为我们不能保证我们收到的请求都是由我们的前端程序发出,所以,后端必须进行参数校验!

Bean Validation 中内置的 constraint

JSR303 规范默认提供了几种约束注解的定义。具体如下表格:

Constraint 详细信息
AssertFalse 被注解的元素必须是否定值。
支持:
- boolean
- Boolean
- null
AssertTrue 被注解的元素必须是肯定值。支持范围同AssertFalse
DecimalMax 被注解的元素必须是一个数字,其值必须小于或等于指定的最大值。支持:
- BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long及其包装类
- null

由于精度范围限制,不支持double,float及其包装类 | | DecimalMin | 被注解的元素必须是一个数字,其值必须大于或等于指定的最小值。支持范围同
DecimalMax | | Digits
| 被注解的元素必须是可接受范围内的数字。支持范围同
DecimalMax | | Email
� | 被注解的元素必须是字符串,必须是格式正确的电子邮件地址。
支持:
- CharSequence
- null
| | Future
� | 被注解的元素必须是未来的某个时刻、日期或时间。
支持:
- java.util.Date
- java.util.Calendar
- java.time.Instant
- java.time.LocalDate
- java.time.LocalDateTime
- java.time.LocalTime
- java.time.MonthDay
- java.time.OffsetDateTime
- java.time.OffsetTime
- java.time.Year
- java.time.YearMonth
- java.time.ZonedDateTime
- java.time.chrono.HijrahDate
- java.time.chrono.JapaneseDate
- java.time.chrono.MinguoDate
- java.time.chrono.ThaiBuddhistDate
- null
| | FutureOrPresent
| 被注解的元素必须是现在或者未来的某个时刻、日期或时间。
支持范围同Future | | Max
� | 被注解的元素必须是一个数字,其值必须小于或等于指定的最大值。
支持:
- BigDecimal
- BigInteger
- byte, short, int, long及其包装类
- null
由于精度范围限制,不支持double,float及其包装类 | | Min
� | 被注解的元素必须是一个数字,其值必须大于或等于指定的最小值。
支持范围同Max | | Negative
| 被注解的元素必须是严格的负数(即 0 被视为无效值)。
支持范围同Max | | NegativeOrZero
� | 被注解的元素必须是负数或 0。
支持范围同Max | | NotBlank
� | 被注解的元素不能为空,并且必须至少包含一个非空白字符。
支持:
- CharSequence
| | NotEmpty
� | 被注解的元素不得为 null 或为空。
支持:
- CharSequence(评估字符序列的长度)
- Collection(评估集合容量)
- Map(评估Map容量)
- Array(评估数组长度)
| | NotNull
� | 被注解的元素不得为 null。
支持任意类型。 | | Null
� | 被注解的元素必须是 null。
支持任意类型。 | | Past
� | 被注解的元素必须是过去的某个时刻、日期或时间。
支持范围同Future | | PastOrPresent
� | 被注解的元素必须是过去或现在的某个时刻、日期或时间。
支持范围同Future | | Pattern
� | 被注解的元素必须匹配指定的正则表达式。正则表达式遵循 Java 正则表达式约定,请参见 java.util.regex.Pattern。
支持:
- CharSequence
- null
| | Positive
� | 被注解的元素必须是严格的正数(即 0 被视为无效值)。
支持范围同Max | | PositiveOrZero
� | 被注解的元素必须是正数或 0。
支持范围同Max | | Size
� | 被注解的元素必须在指定的边界(包括)之间。
支持:
- CharSequence(评估字符序列的长度)
- Collection(评估集合容量)
- Map(评估Map容量)
- Array(评估数组长度)
- null
|

参数校验分组

在实际开发中经常会遇到这种情况:添加部门时,id是由后端生成的,不需要校验id是否为空,但是修改部门时就需要校验id是否为空。如果在接收参数的SysDept实体类的id属性上添加NotNull,显然无法实现。这时候就可以定义分组,在需要校验id的时候校验,不需要的时候不校验。

定义表示组别的接口类

  1. public interface Insert {
  2. }
  1. public interface Update {
  2. }

在实体类的注解中标记id使用上面定义的组

  1. @Data
  2. @EqualsAndHashCode(callSuper = true)
  3. public class SysDept extends Model<SysDept> {
  4. private static final long serialVersionUID = 1L;
  5. @NotNull(groups = Update.class, message = "id不能为空")
  6. private Integer deptId;
  7. /**
  8. * 部门名称
  9. */
  10. @NotBlank(message = "部门名称不能为空")
  11. private String name;
  12. /**
  13. * 父级部门id
  14. */
  15. @NotNull(groups = {Insert.class,Update.class}, message = "id不能为空")
  16. private Integer parentId;
  17. // 省略部分代码
  18. }

在controller中使用@Validated指定使用哪个组

新增时指定Insert,修改时指定Update,这样就会在新增时不对id进行校验,修改时校验id属性是否为空;新增修改都会校验部门父id是否为空。
注意:如果存在其他校验,那么还得必须添加Default.class,否则不会执行其他的校验(如我们案例中的@NotBlank)

  1. /**
  2. * 添加
  3. * @param sysDept 实体
  4. * @return success/false
  5. */
  6. @SysLog("添加部门")
  7. @PostMapping
  8. @PreAuthorize("@pms.hasPermission('sys_dept_add')")
  9. public R save(@Validated({Insert.class,Default.class}) @RequestBody SysDept sysDept) {
  10. return R.ok(sysDeptService.saveDept(sysDept));
  11. }
  12. /**
  13. * 编辑
  14. * @param sysDept 实体
  15. * @return success/false
  16. */
  17. @SysLog("编辑部门")
  18. @PutMapping
  19. @PreAuthorize("@pms.hasPermission('sys_dept_edit')")
  20. public R update(@Validated({Update.class,Default.class}) @RequestBody SysDept sysDept) {
  21. sysDept.setUpdateTime(LocalDateTime.now());
  22. return R.ok(sysDeptService.updateDeptById(sysDept));
  23. }

1.后端如何使用注解优雅的进行参数校验
####1.1 常用注解

  1. @Null(message = "XXXX不能为空") 被注释的元素必须为 null, message尽量要写不然前端不知道是哪个字段
  2. @NotNull(message = "XXXX不能为空") 被注释的元素必须不为 null, message尽量要写不然前端不知道是哪个字段
  3. @Length 被注释的字符串的大小必须在指定的范围内,注意只能用在String 否则会报错, message尽量要写不然前端不知道是哪个字段
  4. @NotEmpty 被注释的字符串的必须非空,注意只能用在String 否则会报错, message尽量要写不然前端不知道是哪个字段
  5. @AssertTrue(message = "XXXX") 被注释的元素必须为 true, message尽量要写不然前端不知道是哪个字段
  6. @AssertFalse 被注释的元素必须为 false
  7. @Min(value=L,message="XXXX") 被注释的元素必须是一个数字,其值必须大于等于指定的最小值, message尽量要写不然前端不知道是哪个字段
  8. @Max(value=L,message="XXXX") 被注释的元素必须是一个数字,其值必须小于等于指定的最小值, message尽量要写不然前端不知道是哪个字段
  9. @DecimalMin(value=L,message="XXXX") 被注释的元素必须是一个数字,其值必须大于等于指定的最小值, message尽量要写不然前端不知道是哪个字段
  10. @DecimalMax(value=L,message="XXXX") 被注释的元素必须是一个数字,其值必须小于等于指定的最大值, message尽量要写不然前端不知道是哪个字段
  11. @Size(max, min) 被注释的元素的大小必须在指定的范围内, message尽量要写不然前端不知道是哪个字段
  12. @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内, message尽量要写不然前端不知道是哪个字段
  13. @Past 被注释的元素必须是一个过去的日期, message尽量要写不然前端不知道是哪个字段
  14. @Future 被注释的元素必须是一个将来的日期, message尽量要写不然前端不知道是哪个字段
  15. @Pattern(value) 被注释的元素必须符合指定的正则表达式, message尽量要写不然前端不知道是哪个字段
  16. @Email 被注释的元素必须是电子邮箱地址, message尽量要写不然前端不知道是哪个字段
  17. @Range 被注释的元素必须在合适的范围内, message尽量要写不然前端不知道是哪个字段
  18. @NotBlank 验证字符串非null,且长度必须大于0,注意只能用在String 否则会报错

然后需要在controller方法体添加 @Validated @Valid 不加校验会不起作用
pig 参数校验及技巧 - 图1

1.3 如何扩展(如何自定义校验注解)

(1)定义注解,必须包含message、groups、Payload三个属性

  1. /**
  2. * 边界值校验
  3. * @author Lilu
  4. * @date 2021-7-16 16:57
  5. */
  6. import javax.validation.Constraint;
  7. import javax.validation.Payload;
  8. import java.lang.annotation.Documented;
  9. import java.lang.annotation.Retention;
  10. import java.lang.annotation.Target;
  11. import static java.lang.annotation.ElementType.*;
  12. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  13. @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
  14. @Retention(RUNTIME)
  15. @Documented
  16. @Constraint(validatedBy = { IntegerValidImpl.class})
  17. public @interface IntegerValid {
  18. int max();//最大值
  19. int min();//最小值
  20. String message() default "{你不对劲}";
  21. Class<?>[] groups() default { };
  22. Class<? extends Payload>[] payload() default { };
  23. }

(1)实现接口

  1. import org.springframework.stereotype.Component;
  2. import javax.validation.ConstraintValidator;
  3. import javax.validation.ConstraintValidatorContext;
  4. /**
  5. * @author Lilu
  6. * @date 2021-7-16 16:57
  7. */
  8. /**
  9. * 自定义类,用于对校验注解规则的实现
  10. * 实现 ConstraintValidator 接口,泛型,第一个是对什么注解进行实现,第二个是检验的数据的数据类型 ;
  11. */
  12. @Component
  13. public class IntegerValidImpl implements ConstraintValidator<IntegerValid, Integer> {
  14. private int min;
  15. private int max;
  16. /**
  17. * @Description 初始化
  18. * @Date 2021-7-16 17:09
  19. * @Param [constraintAnnotation]
  20. * @return void
  21. **/
  22. @Override
  23. public void initialize(IntegerValid constraintAnnotation) {
  24. min=constraintAnnotation.min();
  25. max=constraintAnnotation.max();
  26. }
  27. @Override
  28. public boolean isValid(Integer value, ConstraintValidatorContext context) {
  29. System.out.println(value);
  30. if(value>min&&value<max){
  31. return true;
  32. }
  33. return false;
  34. }
  35. }

(3)使用

  1. @ApiOperation(value = "测试接口", notes = "测试接口")
  2. @PostMapping("test")
  3. public ResponseEntity test(@Validated @RequestBody TestBean testBean){
  4. return ResponseEntity.ok(testBean);
  5. }
  6. public static class TestBean{
  7. @IntegerValid(min = 1, max = 20)
  8. private Integer aa;
  9. @IntegerValid(min = 1, max = 20)
  10. private Integer bb;
  11. public Integer getAa() {
  12. return aa;
  13. }
  14. public void setAa(Integer aa) {
  15. this.aa = aa;
  16. }
  17. public Integer getBb() {
  18. return bb;
  19. }
  20. public void setBb(Integer bb) {
  21. this.bb = bb;
  22. }
  23. }

1.3 分组如何使用

groups可以指定注解使用的场景,一个实体类可能会在多个场合有使用,如插入,删除等。通过groups可以指定该注解在插入/删除的环境下生效。
payload往往对bean进行使用。

例子

(1)定义group最后可以再定义两个接口作为group,代表两种不同的操作。

  1. /**
  2. * @author Lilu
  3. * @date 2021-7-16 17:45
  4. */
  5. public interface Insert {
  6. }
  1. /**
  2. * @author Lilu
  3. * @date 2021-7-16 17:45
  4. */
  5. public class Update {
  6. }

(2)使用

  1. import com.jc.purchase.annotation.IntegerValid;
  2. import com.jc.purchase.annotation.Update;
  3. import io.swagger.annotations.Api;
  4. import io.swagger.annotations.ApiOperation;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.springframework.http.ResponseEntity;
  8. import org.springframework.validation.annotation.Validated;
  9. import org.springframework.web.bind.annotation.*;
  10. import java.awt.*;
  11. /**
  12. * @author Lilu
  13. * @date 2021-7-16 17:45
  14. */
  15. @Api(tags = "通用接口")
  16. @RestController
  17. @RequestMapping("/api/se/general")
  18. public class GeneralController {
  19. private final Logger log = LoggerFactory.getLogger(GeneralController.class);
  20. @ApiOperation(value = "测试新增")
  21. @PostMapping("testAdd")
  22. public ResponseEntity add(@Validated(Insets.class) @RequestBody TestBean testBean){
  23. return ResponseEntity.ok(testBean);
  24. }
  25. @ApiOperation(value = "测试修改")
  26. @PutMapping("testPut")
  27. public ResponseEntity put(@Validated(Update.class) @RequestBody TestBean testBean){
  28. return ResponseEntity.ok(testBean);
  29. }
  30. public static class TestBean{
  31. @IntegerValid(min = 1, max = 20,groups = Update.class)//修改时验证生效
  32. private Integer aa;
  33. @IntegerValid(min = 1, max = 20,groups = Insets.class)//新建时验证生效
  34. private Integer bb;
  35. public Integer getAa() {
  36. return aa;
  37. }
  38. public void setAa(Integer aa) {
  39. this.aa = aa;
  40. }
  41. public Integer getBb() {
  42. return bb;
  43. }
  44. public void setBb(Integer bb) {
  45. this.bb = bb;
  46. }
  47. }
  48. }

2.全局异常响应码封装

2.1 后端代码

pig 参数校验及技巧 - 图2

2.2 验证未通过请求响应结果

  1. {
  2. status: 400,
  3. code:1,
  4. msg:""
  5. }

❤ 问题咨询

手势点击蓝字求关注简约风动态引导关注__2022-09-07+23_18_38.gif

若有收获,就点个赞吧

0 人点赞

  • 书签
  • 添加书签 移除书签
  • 前言
    • 参与开发
    • 学习资料
    • ❤ 本地部署体验商业版本
    • 低代码数据可视化
    • PIG DIY
  • 部署运行
    • 0️⃣ 开发环境准备
    • 1️⃣ 服务端代码部署
    • 2️⃣ 前端代码部署
    • 3️⃣ 系统账号说明
  • 二次开发
    • ①创建微服务项目骨架
    • ②完成微服务增删改查
    • ③微调微服务配置管理
    • 前端表单设计器使用
  • 网关功能
    • 网关路由配置
    • 网关配置跨域
    • 网关限流使用
    • 网关超时及异常处理
  • 认证授权
    • pig 生成token (认证)详解 ⭐️
    • pig 校验token (鉴权)详解 ⭐️
    • pig token有效期及个性化
    • 接口对外直接暴露 👍
    • 服务中获取当前用户 👍
    • feign调用及服务间鉴权
    • swagger 文档接入使用
    • swagger 接口文档调试
    • knife4j 接口文档调试 👍
    • postman 调用服务接口
    • 前端登录请求加密
    • 短信登录配置短信渠道
    • 验证码配置开关
    • 配置文件加解密
    • pig 客户端模式使用
    • pig 授权码模式使用(开放平台)
    • pig 资源服务器配置
    • Inner注解使用说明
    • 登录用户支持多表存储
  • 功能使用
    • 缓存 redis 相关功能使用
    • pig 字典的使用
    • pig xss 安全过滤插件
    • pig 全局异常处理
    • 后端异常信息国际化
    • pig seata 分布式事务解决方案
    • pig 动态数据源使用
    • pig 开启用户注册
    • pig OSS文件上传
    • pig 参数校验及技巧
    • OAuth 2.0 单元测试扩展使用
    • xxl-job 任务调度模块使用
    • 实时调整服务日志级别
    • 浏览器实时查看服务日志
    • 监控模块安全认证
    • SysLog 注解使用
    • 登录后置处理
    • 时间转换处理及个性化
    • EnablePigFeignClients 注解解析【原理】
  • 整合能力
    • 数据可视化大屏使用
    • Excel 导入导出功能使用
    • 整合 shardingsphere 5.x 分库分表
    • Redisson 实现业务接口幂等
    • pig 整合 websocket 实时通信
    • pig 接口防重放、防篡改
    • pig 实现接口防刷验证码
    • pig 整合 lock4j 实现分布式锁
    • pig 整合多级缓存提高性能
    • 整合UReport2 完成报表设计功能
    • pig 整合邮件发送
    • 整合 RabbitMQ 消息队列
    • 整合 RocketMQ 消息队列
    • 整合MongoDB实现NOSQL功能
    • 整合SkyWalking链路监控
    • 整合轻量级日志链路追踪
    • 整合elk 日志收集
    • pig-ui 省市区级联选择
    • pig整合钉钉/企业微信群机器人实现消息通知中间件
    • [单点案例] jfinal系统接入pig
    • [单点案例] ruoyi系统接入pig (不分离)
    • [单点案例] ruoyi系统接入pig (分离)
    • [单点案例] guns系统接入pig
    • [单点案例] renren系统接入pig
    • [单点案例] jeecg前后端分离系统接入pig
    • [单点案例] jeesite前后端分离系统接入pig
    • pig-register nacos 支持oracle 存储
    • pig-register nacos 支持达梦存储
    • pig-register nacos 支持人大金仓存储
    • pig-register nacos 支持PostgreSQL 存储
  • 开发基础
    • 【白嫖】敏捷开发体系
    • lombok 使用及技巧
    • java8 资料汇总
    • java 工具类使用
    • pig stream 使用及其技巧
    • pig lambda 使用及其技巧
    • token、jwt、oauth2、session
    • nacos 服务注册与发现作用
    • nacos 配置中心作用
    • nacos server 源码运行实现
    • gateway 业务网关作用
    • loadBalancer 负载均衡器作用
    • sentinel 流量保护作用
    • OAuth2.0 核心控制设置
  • 前端开发
    • 前端文档说明
    • 前端图标引入
    • 按钮权限控制
  • 生产部署
    • docker 部署后端
    • docker 部署前端
    • https 部署前端项目
    • 一键部署启动
    • centos 部署整套应用
    • Rainbond 部署整套应用
  • 其他开源
  • 常见问题
    • 群里提问须知
    • 如何修改客户端 pig 信息
    • 登录提示clientId 不合法
    • gateway启动报DocConfiguration空指针
    • 服务启动失败 Failed to configure a DataSource: 'url'
    • pig-register 启动报错失败
    • pig 链接不上数据库
    • 登录提示密码错误
    • 登录页面不显示验证码
    • java -jar 运行yml 报错input length = 1
    • 创建新模块提示资源不存在
    • fastjson 安全漏洞
    • 如何获取免费公网Docker镜像仓库
    • 如何修改 pig-ui 启动端口
    • 如何修改 pig-register 启动端口
    • 升级后无法启动提示sentinel bean 重复
    • 网关机器被挖矿服务不可用
    • 前端项目启动失败
    • nacos-naming 、nacos-config 的源码在哪里
    • 根pom pig-cloud-dependencies-parent 源码
    • pig-auth 报错 Cannot deserialize
    • main方法启动失败,提示 bootstray.yml 语法错误
暂无相关搜索结果!
    展开/收起文章目录

    玻璃钢生产厂家青岛玻璃钢花盆售价贵州玻璃钢雕塑模型厂家北京玻璃钢海洋馆雕塑公司丽水特色玻璃钢雕塑设计出售玻璃钢品牌ip雕塑茂名动物玻璃钢雕塑宣城玻璃钢花盆花器珠海小品玻璃钢雕塑山东商场美陈报价四川人物玻璃钢雕塑市场玻璃钢室外雕塑树脂滁州商场户外美陈玻璃钢雕塑上色怎么进行武威玻璃钢植物雕塑定制宜昌公园玻璃钢雕塑价格湛江玻璃钢雕塑图片郑州商场美陈装饰铜陵人物玻璃钢雕塑多少钱和龙玻璃钢长颈雕塑卢湾区道路景观玻璃钢花盆家用玻璃钢雕塑摆件设计厂家玻璃钢动物雕塑信息玻璃钢雕塑样品艺术商场美陈订购忻州玻璃钢卡通雕塑厂家玻璃钢蔬菜雕塑价格辽宁玻璃钢雕塑设计佛山玻璃钢仿铜浮雕塑淮北公园玻璃钢雕塑定做价格马鞍山玻璃钢雕塑鹿香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

    玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化