当前位置: 首页 > news >正文

Springboot——@valid 做字段校验和自定义注解

文章目录

  • 前言
  • 注意实现
  • 测试环境
  • 验证自带的注解
  • 自定义valid注解
    • 自定义注解和处理类
    • 创建参数接收类,并增加字段注解
    • 接口中使用
  • 自测环节
    • 正常测试
    • 异常测试
  • 自定义全局异常监听
  • 扩展
    • 递归参数下valid不识别的坑

前言

再项目开发中,针对前端传递的参数信息,有些接口中需要写大量的if判断,导致代码臃肿,不够优雅。

此时,可以使用@Valid实现基本的字段校验。

注意实现

  • springboot 2.3之前 ,直接进行开发即可,无需引用额外的依赖
    集成在spring-boot-starter-web中。
  • springboot 2.3之后 需要额外引入spring-boot-starter-validation依赖信息

测试环境

springboot 2.1.4

如果你的springboot版本高于 2.3,需要额外引入下列依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>

验证自带的注解

验证自带的注解,以及实现原理,可以移步到我的另一篇博客中,本篇博客不做过多的阐述。

做一个优雅的接口

自定义valid注解

官方提供的一些常用的注解,有时候并不能适合所有的开发需求。此时可以采取自定义valid的方式,实现其应有的功能。

自定义注解和处理类

创建一个自定义的注解

检查排序号是否输入,以及是否满足要求。

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Constraint(validatedBy = POrderParse.class) // 注解对应的处理类
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface POrder {// 默认提示语句String message() default "排序号不允许为空,且只允许是1到20的数字!";// 默认校验正则表达式String regexp() default "^([1-9])|([1]\\d)|20$";Class<?>[] groups() default { };Class<? extends Payload>[] payload() default { };}

定义注解后,还需要定义其指定的处理类,如下所示:

import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;@Component
public class POrderParse implements ConstraintValidator<POrder,Object> {@Overridepublic void initialize(POrder constraintAnnotation) {System.out.println("my para order validator init");}@Overridepublic boolean isValid(Object value, ConstraintValidatorContext context) {// 校验逻辑ConstraintValidatorContextImpl con = (ConstraintValidatorContextImpl) context;// 获取注解中的属性值Map<String, Object> maps = con.getConstraintDescriptor().getAttributes();// 获取设置的或者默认的正则表达式String regexp = (String) maps.get("regexp");// 获取数据值String param = String.valueOf(value);// 正则判断Pattern regexpVo = Pattern.compile(regexp);Matcher matcher = regexpVo.matcher(param);return matcher.matches();}
}

创建参数接收类,并增加字段注解

import cn.xj.bi.volid.MyPhone;
import cn.xj.bi.volid.POrder;
import lombok.Data;@Data
public class User {@POrderprivate Integer order;
}

接口中使用

创建一个测试接口,进行应用测试。

需要使用到@Valid注解标识

@RestController
@RequestMapping("/test1")
@Api(tags = "测试")
public class TestController {@PostMapping("/demo4")@ApiOperation(value = "demo4")public CommonResult<String> test4(@RequestBody @Valid User user){return CommonResult.success("6666");}
)

自测环节

启动项目,进入swagger进行请求测试。

正常测试

传递满足正则要求的值,查看返回结果信息。

{"order": 10
}

在这里插入图片描述

异常测试

参数中传递一个不满足正则表达式的值,观察返回信息。

{"order": 0
}

在这里插入图片描述

自定义全局异常监听

每次返回这样的报错信息不够直观,此时可以自定义全局异常监听,如下所示:

import cn.xj.bi.vo.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Objects;@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(MethodArgumentNotValidException.class)public CommonResult handleScopeFiledException(MethodArgumentNotValidException e) {log.error("字段合法性校验异常:[{}]", e.getMessage());// getFieldError() 和 getDefaultMessage() 的区别return CommonResult.error( Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage(), null);}
}

重启项目,再次异常测试:
在这里插入图片描述

扩展

递归参数下valid不识别的坑

递归参数的意思就是接收对象是一个类,假设是DataScope,但是在这个接收类中,还有一个List<User>这个参数变量,并且User中依旧还含有需要valid校验的字段属性。

再自定义一个valid注解,如下所示:

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Constraint(validatedBy = {MyPhoneValidtor.class})
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyPhone {String message();Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};}

valid注解具体处理类:

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;public class MyPhoneValidtor implements ConstraintValidator<MyPhone,Object> {@Overridepublic boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {System.out.println("校验");// 故意返回false,触发异常return false;}
}

然后再请求参数接收对象中,定义如下格式:

import cn.xj.bi.volid.POrder;
import lombok.Data;@Data
public class User {@POrderprivate Integer order;private Address address;
}
import cn.xj.bi.volid.MyPhone;
import lombok.Data;
import java.io.Serializable;@Data
public class Address implements Serializable {@MyPhone(message = "这只是一个测试")private String phoneNum;
}

重启项目,传递正常的 order 值,观察Address 类中的 phoneNum 是否触发valid校验。

{"order": 10,"address":{"phoneNum":""}
}

在这里插入图片描述
发现并未触发对应的valid校验。

解决方式很简单,没有触发说明注解无效,接口中定义@Valid User 是对user对象进行valid处理,但对象类型的并不在列,只需要在对象类型的变量上增加@Valid注解即可。

import cn.xj.bi.volid.POrder;
import lombok.Data;import javax.validation.Valid;@Data
public class User {@POrderprivate Integer order;@Valid  // 迭代validprivate Address address;
}

重启项目,继续按照上面的传参,观察响应信息。
在这里插入图片描述

相关文章:

Springboot——@valid 做字段校验和自定义注解

文章目录前言注意实现测试环境验证自带的注解自定义valid注解自定义注解和处理类创建参数接收类&#xff0c;并增加字段注解接口中使用自测环节正常测试异常测试自定义全局异常监听扩展递归参数下valid不识别的坑前言 再项目开发中&#xff0c;针对前端传递的参数信息&#xf…...

c语言基础练习题详解

&#x1f49e;&#x1f49e; 1.C语言程序的基本单位是&#xff08;C&#xff09;。 A&#xff0e;程序行 B&#xff0e; 语句 C&#xff0e; 函数 D&#xff0e;字符 &#x1f49e;&#x1f49e; 2.已知各变量的类型说明如下&#xff1a; int m6,n,a,b; unsigned long w8;…...

C语言设计模式:实现简单工厂模式和工程创建

目录 一&#xff0c;设计模式概念引入 ① 什么是设计模式 ② 什么是类和对象 ③ 什么是工厂模式 二&#xff0c;C语言工厂模式的实现 ① 普通类和对象的代码实现 ② 工厂模式代码实现 ● cat.c ● dog.c ● person.c ● animal.h ● mainpro.c ● 完善mainpro.c …...

3.6日报

今天进行3.0信号整理工作 做官网后台技术文档 了解grpc gRPC是rpc框架中的一种&#xff0c;是rpc中的大哥 是一个高性能&#xff0c;开源和通用的RPC框架&#xff0c;基于Protobuf序列化协议开发&#xff0c;且支持众多开发语言。 面向服务端和协议端&#xff0c;基于http…...

中文代码88

PK 嘚釦 docProps/PK 嘚釦|,g z docProps/app.xml漅AN??駠(髂v诖m岼侸 魣,g踃$秂D廋Qvf漶x莗笳w?:瘜^?俍欶辇2}?睧汎 t#:?效7治XtA鏊?羄鈋嫿饄攗Tv契"D桷撵vJ鉂?闌 Jg??浱?樱沲gic鋹峡?sū窛葻?]迾?9卑{艏 rk\?洺萹啰N?W??2&quo…...

ElasticSearch 基础(五)之 映射

目录前言一、映射&#xff08;Mapping&#xff09;简介二、动态映射&#xff08;Dynamic mapping&#xff09;1、动态字段映射1.1、日期检测1.1.1、禁用日期检测1.1.2、自定义检测到的日期格式1.2、数值检测2、动态模板三、显示映射&#xff08;Explicit mapping&#xff09;1、…...

【C语言督学训练营 第二天】C语言中的数据类型及标准输入输出

文章目录一、前言二、数据类型1.基本数据类型①.整形②.浮点型③.字符型2.高级数据类型3.数据分类①.常量②.变量三、标准输入输出1.scanf2.printf四、进制转换1.进制转换简介2.十进制转其他进制3.其他进制转换五、OJ网站的使用一、前言 王道2024考研408C语言督学营第二天&…...

重资产模式和物流网络将推动京东第四季度利润率增长

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 强劲的2022年第三季度财务业绩 2022年11月18日&#xff0c;京东&#xff08;JD&#xff09;公布了2022年第三季度财务业绩&#xff0c;净收入为2435亿元人民币&#xff0c;增长了11.4%。净服务收入为465亿元人民币&#xf…...

【新】EOS至MES的假捻报工数据导入-V2.0版本

假捻自动线的数据和MES没有进行对接,直接入库至EOS。 因此可信平台上缺少这部分的报工数据,需要把EOS的入库数据导出,整理成报工数据,导入到MES,然后通过定时任务集成到可信平台。 MES这边的报工数据整理,主要是添加订单明细ID,和完工单号。 订单明细ID(根据批次号和…...

python甜橙歌曲音乐网站平台源码

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;python音乐 获取完整源码源文件说明文档配置教程等 在虚拟环境下输入命令“python manage.py runserver”启动项目&#xff0c;启动成功后&#xff0c;访问“http://127.0.0.1:5000”进入甜橙音乐网首页&#xff0c;如图1所…...

docker imageID计算

Image ID是在本地由Docker根据镜像的描述文件计算的&#xff0c;并用于imagedb的目录名称 docker镜像id都保存在/var/lib/docker/image/overlay2/imagedb/content/sha256下面&#xff0c;都是一些以sha256sum计算文件内容得出的哈希值的文件。 #ls /var/lib/docker/image/ove…...

借助媛如意让ROS机器人turtlesim画出美丽的曲线-云课版本

首先安装并打开猿如意其次打开蓝桥云课ROS并加入课程在猿如意输入问题得到答案在蓝桥云课ROS验证如何通过turtlesim入门ROS机器人您可以通过以下步骤入门ROS机器人&#xff1a;安装ROS&#xff1a;您需要安装ROS&#xff0c;可以在ROS官网上找到安装指南。安装turtlesim&#x…...

小区业主入户安检小程序开发

小区业主入户安检小程序开发 可针对不同行业自定义安检项目&#xff0c;线下安检&#xff0c;线上留存&#xff08;安检拍照/录像&#xff09;&#xff0c;提高安检人员安检效率 功能特性&#xff0c;为你介绍小区入户安检系统的功能特性。 小区管理;后台可添加需要安检的小区…...

【C++知识点】异常处理

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4da;专栏地址&#xff1a;C/C知识点 &#x1f4e3;专栏定位&#xff1a;整理一下 C 相关的知识点&#xff0c;供大家学习参考~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;…...

【FATE联邦学习debug】 No module named ‘federatedml‘

直接pip install federatedml是无法找得到这个库的。 这个的原因是环境变量的事情&#xff0c;因为在部署文档中&#xff0c;本身提示我们要更新一些环境变量&#xff0c;如果不export那些变量&#xff0c;下面的fate_test其实也是无法测试成功的。 打开bin/init_env.sh&#x…...

【Git】P1 Git 基础

Git 基础Git 基本概念集中式版本控制工具 与 分布式版本控制工具Git 下载与安装Bash 初始设置创建本地仓库Git 三区概念一个简单的提交流程更改文件后再次提交git 实现版本切换查看提交日志设置 git 快捷键版本切换&#xff08;一&#xff09;版本切换&#xff08;二&#xff0…...

智能交通数据集Rope3D(仅限科研使用)

Rope3D Dataset 官网&#xff1a;https://thudair.baai.ac.cn/index &#xff01;&#xff01;&#xff01;如想要使用Rope3D数据集进行2D检测&#xff0c;最后有我们处理完的数据集链接。 &#xff01;&#xff01;&#xff01; 介绍&#xff1a; DAIR-V2X数据集是首个用于…...

Java虚拟机JVM-面试题

1、Java 虚拟机是如何捕获异常的&#xff1f; 答&#xff1a; 在编译生成的字节码中&#xff0c;每个方法都附带一个异常表。异常表中的每一个条目代表一个异常处理器&#xff0c;并且由 from 指针、to 指针、target 指针以及所捕获的异常类型构成。这些指针的值是字节码索引…...

详细的说说Redis的数据类型

Redis是一个开源的内存数据库&#xff0c;它可以用作缓存、消息代理、实时数据处理和许多其他用途。Redis是一个key-value存储系统&#xff0c;其中数据存储在内存中&#xff0c;并通过网络进行访问。与传统的关系型数据库不同&#xff0c;Redis支持多种数据结构&#xff0c;包…...

798.差分矩阵

输入一个 n行 m列的整数矩阵&#xff0c;再输入 q个操作&#xff0c;每个操作包含五个整数 x1,y1,x2,y2,c&#xff0c;其中 (x1,y1)和 (x2,y2) 表示一个子矩阵的左上角坐标和右下角坐标。每个操作都要将选中的子矩阵中的每个元素的值加上 c。 请你将进行完所有操作后的矩阵输出…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...