如何实现 Java SpringBoot 自动验证入参数据的有效性
Java SpringBoot 通过javax.validation.constraints下的注解,实现入参数据自动验证
如果碰到 @NotEmpty 否则不生效,注意看下 @RequestBody 前面是否加上了@Valid
Validation常用注解汇总
| Constraint | 详细信息 |
|---|---|
| @Null | 被注释的元素必须为 null |
| @NotNull | 被注释的元素必须不为 null |
| @NotBlank | 被注释的元素不能为空(空格视为空) |
| @NotEmpty | 被注释的元素不能为空 (允许有空格) |
| @Size(max, min) | 被注释的元素的大小必须在指定的范围内 |
| @Min(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
| @Max(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
| @Pattern(value) | 被注释的元素必须符合指定的正则表达式 |
| @DecimalMin(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
| @DecimalMax(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
| @AssertTrue | 被注释的元素必须为 true |
| @AssertFalse | 被注释的元素必须为 false |
| @Digits (integer, fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 |
| @Past | 被注释的元素必须是一个过去的日期 |
| @Future | 被注释的元素必须是一个将来的日期 |
示例
/*** 用户名*/@NotBlank(message = "用户名不能为空")private String username;/*** 用户真实姓名*/@NotBlank(message = "用户真实姓名不能为空")private String name;/*** 密码*/@Pattern(regexp = "^(?:(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[^A-Za-z0-9]))(?=^[^\\u4e00-\\u9fa5]{0,}$).{8,20}$", message = "密码过于简单有被盗风险,请保证密码大于8位,并且由大小写字母、数字,特殊符号组成") private String password;/*** 邮箱*/@NotBlank(message = "邮箱不能为空")@Email(message = "邮箱格式不正确")private String email;/*** 手机号*/@NotBlank(message = "手机号不能为空")@Pattern(regexp = "^(1[0-9])\\d{9}$", message = "手机号格式不正确")private String mobile;
Demo
入参对象上,添加注解及说明
package com.vipsoft.web.entity;import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.io.Serializable;/*** 定时任务调度*/
public class QuartzJob implements Serializable {private static final long serialVersionUID = 1L;/*** 任务序号*/private long jobId;/*** 任务名称*/@NotBlank(message = "任务名称不能为空")@Size(max = 10, message = "任务名称不能超过10个字符")private String jobName;/*** 任务组名*/@NotBlank(message = "任务组名不能为空")@Size(max = 10, message = "任务组名不能超过10个字符")private String jobGroup;/*** 调用目标字符串*/private String invokeTarget;/*** 执行表达式*/private String cronExpression;/*** cron计划策略 0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行*/private String misfirePolicy = "0";/*** 并发执行 0=允许,1=禁止*/private String concurrent;/*** 任务状态(0正常 1暂停)*/private String status;/*** 备注*/private String remark;
}
Controller @RequestBody 前面必须加上 @Valid 否则不生效
import javax.validation.Valid;@RestController
@RequestMapping("schedule")
public class ScheduleController {private Logger logger = LoggerFactory.getLogger(ScheduleController.class);@RequestMapping("/add")public ApiResult addTask(@Valid @RequestBody QuartzJob param) throws Exception {logger.info("添加调度任务 => {} ", JSONUtil.toJsonStr(param));return new ApiResult("添加成功");}
}
异常处理,统一返回对象,方便前端解析
GlobalExceptionHandler
package com.vipsoft.web.exception;import cn.hutool.core.util.StrUtil;
import com.vipsoft.web.utils.ApiResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.List;/*** 全局异常处理器*/
@RestControllerAdvice
public class GlobalExceptionHandler {private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);/*** 处理自定义异常*/@ExceptionHandler(CustomException.class)public ApiResult handleException(CustomException e) {// 打印异常信息logger.error("### 异常信息:{} ###", e.getMessage());return new ApiResult(e.getCode(), e.getMessage());}/*** 参数错误异常*/@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})public ApiResult handleException(Exception e) {if (e instanceof MethodArgumentNotValidException) {MethodArgumentNotValidException validException = (MethodArgumentNotValidException) e;BindingResult result = validException.getBindingResult();StringBuffer errorMsg = new StringBuffer();if (result.hasErrors()) {List<ObjectError> errors = result.getAllErrors();errors.forEach(p -> {FieldError fieldError = (FieldError) p;errorMsg.append(fieldError.getDefaultMessage()).append(",");logger.error("### 请求参数错误:{" + fieldError.getObjectName() + "},field{" + fieldError.getField() + "},errorMessage{" + fieldError.getDefaultMessage() + "}");});return new ApiResult(6001, errorMsg.toString());}} else if (e instanceof BindException) {BindException bindException = (BindException) e;if (bindException.hasErrors()) {logger.error("### 请求参数错误: {}", bindException.getAllErrors());}}return new ApiResult(6001, "参数无效");}/*** 处理HttpRequestMethodNotSupporte异常* @param e* @return*/@ExceptionHandler(HttpRequestMethodNotSupportedException.class)public Object methodHandler(HttpRequestMethodNotSupportedException e) {// 打印异常信息logger.error("### 异常信息:{} ###", e.getMessage());return new ApiResult(6000, e.getMessage());}/*** 处理所有不可知的异常*/@ExceptionHandler(Exception.class)public ApiResult handleOtherException(Exception e) {// 打印异常信息logger.error("### 系统内部错误:{} ###", e.getMessage(), e);String warnMsg = StrUtil.isEmpty(e.getMessage()) ? "### 系统内部错误 ###" : e.getMessage();return new ApiResult(6000, "系统内部错误", e.getMessage());}}
统一返回对像 ApiResult
package com.vipsoft.web.utils;//import com.github.pagehelper.PageInfo;import java.io.Serializable;public class ApiResult implements Serializable {/*** 返回编码 0:失败、1:成功*/private int code;/*** 返回消息*/private String message;/*** 返回对象*/private Object data;/*** 分页对象*/private Page page;public ApiResult() {this.code = 1;this.message = "请求成功";}public ApiResult(Integer code, String message) {this.code = code;this.message = message;}public ApiResult(Integer code, String message, Object data) {this.code = code;this.message = message;this.setData(data);}public ApiResult(Object data) {this.code = 1;this.message = "请求成功";this.setData(data);}// public ApiResult(PageInfo pageInfo) {
// this.code = 1;
// this.message = "请求成功";
// this.setData(pageInfo.getList());
// this.setPage(convertToPage(pageInfo));
// }
//
// public Page convertToPage(PageInfo pageInfo) {
// Page result = new Page();
// result.setTotalCount(pageInfo.getTotal());
// result.setPageNum(pageInfo.getPageNum());
// result.setPageCount(pageInfo.getPages());
// result.setPageSize(pageInfo.getPageSize());
// result.setPrePage(pageInfo.getPrePage());
// result.setNextPage(pageInfo.getNextPage());
// return result;
// }public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}public Page getPage() {return page;}public void setPage(Page page) {this.page = page;}
}
运行结果如下

相关文章:
如何实现 Java SpringBoot 自动验证入参数据的有效性
Java SpringBoot 通过javax.validation.constraints下的注解,实现入参数据自动验证 如果碰到 NotEmpty 否则不生效,注意看下 RequestBody 前面是否加上了Valid Validation常用注解汇总 Constraint详细信息Null被注释的元素必须为 nullNotNull被注释的元…...
golang学习随记
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 go学习快捷键及快速生成代码片段go基础循环流程控制关键字切片,拷贝函数闭包 defer语句格式化输出go语言随机数rand.seed() 包管理并发编程goroutinecha…...
【PCL-6】PCL基于凹凸型的分割算法(LCCP)
凹凸型分割算法适用于颜色类似、棱角分明的物体场景分割。LCCP方法不依赖点云颜色,只使用空间信息和法线信息。 算法流程: 1、基于超体聚类的过分割; 2、在超体聚类的基础上再聚类。 算法思路: 1、基于CC和SC判断凹凸性&…...
多进程并发服务器
文章目录 思路问题多进程并发回环服务器代码客户端代码 思路 每当一个客户端连接服务器后,创建一个子进程负责与该客户端通信,客户端断开连接之后,服务器回收子进程资源。 问题 问题1:父进程阻塞在等待连接(accept())处…...
2021秋招总结
2021 秋招总结 作为星球第一批准备秋招的人,经过这几个月的面试之后,感觉也算是有一些小小的经验了吧,就做一个简单的记录,希望能够为星球中准备秋招的伙伴们提供一些参考吧~ 序 4月初加入星球,到9月底,一…...
Linux6.34 Kubernetes yaml文件详解
文章目录 计算机系统5G云计算第三章 LINUX Kubernetes yaml文件详解一、yaml文件概述1.查看 api 资源版本标签2.写一个yaml文件demo 计算机系统 5G云计算 第三章 LINUX Kubernetes yaml文件详解 一、yaml文件概述 Kubernetes 支持 YAML 和 JSON 格式管理资源对象 JSON 格式…...
防火墙笔记
什么是防火墙 在计算机网络中是指设置在可信任的内部网络和不可信任的外部网络之间的屏障,通过强化边界控制保障内容安全,同时不妨碍内部对外部的访问。 20世纪80年代,最早的防火墙几乎与路由器同时出现,第一代防火墙主要基于包过…...
使用代码下载开源的大模型文件示例以及中文微调llama资源汇总:
一、下载示例 from huggingface_hub import snapshot_downloadrepo_id "THUDM/chatglm2-6b" local_dir ./chatglm2-6b/ cache_dir local_dir "/cache" while True:try:snapshot_download(cache_dircache_dir,local_dirlocal_dir,repo_idrepo_id,loca…...
Wav2vec2 论文阅读看到的一些问题
Wav2vec2 论文阅读看到的一些问题 这里只是简单的思考一下论文的一些问题,不是论文解读。 Q1. 为什么wav2vec依旧需要Transformer来做推理,而不直接使用VQ生成的内容? A1. Transformer在更长的序列上有更好的编码效果,例如论文也写…...
爬虫学习记录(持续更新)
一、问题记录 1.使用webdriver报错AttributeError: str object has no attribute capabilities 解决:目前使用的selenium版本是4.11.2,可以不必设置driver.exe的路径,selenium可以自己处理浏览器和驱动程序,因此,使用…...
libevent源码学习1---创建event
libevent源码学习1—创建event Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的非阻塞网络库。安装请参考ubuntu下载安装libevent event_base 使用 libevent 函数之前需要分配一个或者多个 event_base 结构体。每个 event_base 结构体持有一个…...
Python类的设计
Python类的设计 # 定义一个闹钟类 class Clock:__cureen_keyNone # 私有成员不能改变和使用def __init__(self, id, price): # 类对象是立即自动执行self.id idself.price pricedef ring(self):import winsound # 内置声音方法winsound.Beep(2000,3000)clock1 Clock(…...
微信小程序的项目解构
视频链接 黑马程序员前端微信小程序开发教程,微信小程序从基础到发布全流程_企业级商城实战(含uni-app项目多端部署)_哔哩哔哩_bilibili 接口文档 https://www.escook.cn/docs-uni-shop/mds/1.start.html 1:微信小程序宿主环境 1:常见的宿…...
【Archaius技术专题】「Netflix原生态」动态化配置服务之微服务配置组件变色龙
前提介绍 如果要设计开发一套微服务基础架构,参数化配置是一个非常重要的点,而Netflix也开源了一个叫变色龙Archaius的配置中心客户端,而且Archaius可以说是比其他客户端具备更多生产级特性,也更灵活。*在NetflixOSS微服务技术栈…...
python条件分支和循环语句
python中没有{}的写法,一般时通过缩进的方式来确定分支和循环需要执行的代码块。 if 需要判断的条件表达式:条件成立时的动作 elif 需要判断的条件表达式:条件成立时的动作 else:动作for 变量 in 迭代对象:动作 示例: while 退出条件:动作...
工具推荐:Wireshark网络协议分析工具(对比tcpdump)
文章首发地址 Wireshark是一款开源的网络协议分析工具,可以捕获网络数据包并对其进行详细的分析和解释。下面是Wireshark的详细介绍: Wireshark 工作原理 Wireshark通过捕获网络接口上的数据包,将其转换为可读的格式,并在界面…...
[OnWork.Tools]系列 04-快捷启动
简介 主要功能是将常用的软件拖动到软件中,实现快速点击启动,结合软件设置中的设置的快捷键,可以快速呼出对应的面板,使用快捷键快速启动应用 拖拽内容 拖拽快捷方式到面板,双击快速打开 拖拽文件方式到面板,双击快速打开 拖拽文件夹到面板双击快速打开 拖拽项目调整顺序 右…...
如何将项目挂后台运行?【nohup和tmux】
挂后台运行,防止霸屏。 线上的程序不会将日志输出到控制台,而是输出到日志文件,方便运维查阅信息。 一.nohup--挂后台运行的命令 //nohup--英文全称no hang up,可以后台运行指定命令 //hello.log是指将日志输出到hello.log文件 …...
什么是进程、线程、协程
什么是进程? 我们都知道计算机的核心是CPU,它承担了所有的计算任务;而操作系统是计算机的管理者,它负责任务的调度、资源的分配和管理,统领整个计算机硬件;应用程序则是具有某种功能的程序,程序…...
Python爬虫——selenium_访问元素信息
from selenium import webdriver# 创建浏览器对象 path files/chromedriver.exe browser webdriver.Chrome(path)# 访问地址 url https://www.baidu.com browser.get(url)input browser.find_element_by_id(su)获取元素属性 .get_attribute(class)print(input.get_attribu…...
基于Qt的LongCat-Image-Editn V2桌面应用开发
基于Qt的LongCat-Image-Editn V2桌面应用开发 1. 引言 在日常工作中,我们经常需要对图片进行各种编辑操作,比如修改文字、调整风格、替换背景等。传统的图片编辑工具往往操作复杂,需要专业的设计技能,而且处理中文文字时效果总是…...
组合专机-丝杠车床改光杠键槽铣专机进给系统设计
在机械加工领域,传统丝杠车床的功能相对单一,面对光杠键槽铣削这类特殊加工需求时,往往力不从心。组合专机——丝杠车床改光杠键槽铣专机进给系统的设计,正是为了突破这一局限。它通过巧妙的改造,将原本仅用于丝杠加工…...
Dips实战指南:极坐标投影在结构面分析中的关键应用
1. 极坐标投影在结构面分析中的核心价值 第一次接触Dips软件时,我被它处理结构面数据的独特方式震撼了。传统直角坐标系下杂乱无章的测量数据,转换到极坐标系后突然呈现出清晰的规律性。这种转变就像把一堆散落的拼图块重新排列,瞬间显现出完…...
GLM-4.1V-9B-Base实战案例:短视频封面图内容审核与敏感要素识别
GLM-4.1V-9B-Base实战案例:短视频封面图内容审核与敏感要素识别 1. 短视频封面审核的行业痛点 在短视频内容爆炸式增长的今天,封面图作为吸引用户点击的第一道门面,其内容质量直接影响平台生态和用户体验。然而,人工审核海量封面…...
手把手教你用Ozone调试FreeRTOS项目(含J-Link配置避坑指南)
手把手教你用Ozone高效调试FreeRTOS项目(附J-Link实战避坑指南) 在嵌入式开发中,调试FreeRTOS系统往往面临诸多挑战——线程状态难以追踪、任务堆栈分析复杂、实时性问题定位困难。SEGGER Ozone作为专为J-Link设计的跨平台调试器,…...
Claude参数曝光,AI模型竞争格局再掀波澜
马斯克“手滑”,Claude参数浮出水面 马斯克在分享xAI的Colossus 2超算训练计划时,意外透露了Claude系列模型的参数规模。他表示Grok 4.2参数量为5000亿,是xAI目前在训最大10万亿参数模型的5%,同时指出Grok参数量是Sonnet的一半、O…...
BERT中文模型实战指南:从零开始搭建智能文本分类系统
BERT中文模型实战指南:从零开始搭建智能文本分类系统 1. 项目概述与准备工作 1.1 BERT模型简介 BERT(Bidirectional Encoder Representations from Transformers)是Google在2018年提出的预训练语言模型,它通过双向Transformer架…...
深度解析:macOS逆向工程如何突破百度网盘SVIP限制的技术实现
深度解析:macOS逆向工程如何突破百度网盘SVIP限制的技术实现 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 在macOS平台上,Bai…...
DeepSeek-OCR-2参数详解:--max_pages --batch_size --conf_threshold 高级调优指南
DeepSeek-OCR-2参数详解:--max_pages --batch_size --conf_threshold 高级调优指南 1. 引言:为什么需要调优参数? 如果你用过DeepSeek-OCR-2,可能已经体验过它强大的文档解析能力。但你是否遇到过这样的情况:处理多页…...
Nuxt v4.x 应用创建中的常见问题与解决方案
Nuxt v4.x 应用创建中的常见问题与解决方案 在构建现代Web应用时,Nuxt.js以其出色的开发体验和强大的功能集赢得了众多开发者的青睐。随着v4.x版本的发布,这个基于Vue.js的框架带来了更多令人兴奋的特性,但同时也伴随着一些新的挑战。本文将深…...
