SpringBoot 开发秘籍 - 整合参数校验

简介: 对于web服务来说,为防止非法参数对业务造成影响,在Controller层一定要对参数进行校验!本章我们以SpringBoot项目为例,介绍参数校验的基本用法以及一些高级技巧,希望能对你有所帮助。

简单使用


  1. 要在Springboot项目中加入参数校验功能首先得加入spring-boot-starter-validation依赖


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


//

  1. 然后给需要校验的字段添加上约束性注解,如我们对实体类参数进行校验


@DatapublicclassValidEntity{
privateintid;
@NotBlankprivateStringappId;
@NotBlankprivateStringname;
@EmailprivateStringemail;
}


常见约束注解如下:


image.png


注:此表格只是简单的对注解功能的说明,并没有对每一个注解的属性进行说明;可详见源码。


  1. 在Controller层对需要参数校验的方法加上@Validated注解
    参数校验一般分为两类:在Controller使用模型接收数据时, @Validated注解直接放在该模型参数前即可。


@PostMapping(value="test1")
publicStringtest1(@Validated@RequestBodyValidEntityvalidEntity){
return"test1 valid success";
}
@PostMapping(value="test3")
publicStringtest3(@ValidatedValidEntityvalidEntity){
return"test3 valid success";
}


当我们是直接在Controller层中的参数前,使用约束注解时,@Validated要直接放在类上


@PostMapping(value="test2")
publicStringtest2(@EmailStringemail){
return"test2 valid success";
}

此时需要在主类上增加@Validated注解


@Validated@RestController@RequestMapping("/demo/valid")
publicclassValidController {
  ...
}


在参数校验时我们既可以使用@Validated也可以使用@Valid注解,两者功能大部分类似;


主要区别在于:


@Valid属于javax下的,而@Validated属于spring下;


@Valid支持嵌套校验、而@Validated不支持,@Validated支持分组,而@Valid不支持。


统一异常处理


如果参数校验未通过Spring会抛出三种类型的异常


  1. 当对@RequestBody需要的参数进行校验时会出现
org.springframework.web.bind.MethodArgumentNotValidException

5b5d81a828a1d0059bd69d49dc2374ff.png


  1. 当直接校验具体参数时会出现 javax.validation.ConstraintViolationException,也属于ValidationException异常


a81229985ede1ec46a887d7dcb4183b2.png


  1. 当直接校验对象时会出现 org.springframework.validation.BindException

343fa522850d51c914b5b2e7c39700e6.png


在SpringBoot中统一拦截处理只需要在配置类上添加@RestControllerAdvice注解,然后在具体方法中通过@ExceptionHandler指定需要处理的异常,具体

代码如下:


@RestControllerAdvice@Slf4jpublicclassGlobalExceptionHandler {
publicstaticfinalStringERROR_MSG="系统异常,请联系管理员。";
@ExceptionHandler(value= {BindException.class, ValidationException.class, MethodArgumentNotValidException.class})
publicResponseEntity<Result<String>>handleValidatedException(Exceptione) {
Result<String>resp=null;
if (einstanceofMethodArgumentNotValidException) {
// BeanValidation exceptionMethodArgumentNotValidExceptionex= (MethodArgumentNotValidException) e;
resp=newResult<>(Integer.toString(HttpStatus.BAD_REQUEST.value()),
ex.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(", "))
                    , getStackTrace(ex));
        } elseif (einstanceofConstraintViolationException) {
// BeanValidation GET simple paramConstraintViolationExceptionex= (ConstraintViolationException) e;
resp=newResult<>(Integer.toString(HttpStatus.BAD_REQUEST.value()),
ex.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(", "))
                    , getStackTrace(ex));
        } elseif (einstanceofBindException) {
// BeanValidation GET object paramBindExceptionex= (BindException) e;
resp=newResult<>(Integer.toString(HttpStatus.BAD_REQUEST.value()),
ex.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(", "))
                    , getStackTrace(ex));
        }
returnnewResponseEntity<>(resp,HttpStatus.BAD_REQUEST);
    }
privateStringgetStackTrace(Exceptione) {
//打印日志开关,可通过配置读取booleanprintStrackTrace=false;
if(printStrackTrace){
StringWritersw=newStringWriter();
e.printStackTrace(newPrintWriter(sw));
returnsw.toString();
        }else{
returnERROR_MSG;
        }
    }
}


最终实现效果如下:


1216da6bb962a931c865425d22cf87be.png


参数分组


有下面一个实体类,我们需要对其进行参数校验。


@DatapublicclassValidEntity {
privateintid;
@NotBlankprivateStringappId;
@NotBlankprivateStringname;
@EmailprivateStringemail;
}


但是实际业务是在编辑的时候appId才是必填,在新增的时候name必填,这时候可以用groups分组功能来实现:同一个模型在不同场景下,动态区分校验模型中的不同字段。


使用方式


首先我们定义一个分组接口ValidGroup,再在分组接口总定义出多个不同的操作类型,Create,Update,Query,Delete


publicinterfaceValidGroupextendsDefault{
interfaceCrudextendsValidGroup{
interfaceCreateextendsCrud{
        }
interfaceUpdateextendsCrud{
        }
interfaceQueryextendsCrud{
        }
interfaceDeleteextendsCrud{
        }
    }
}


这里的ValidGroup继承了Default,当然也可以不继承,具体区别我们后面再说。


  1. 在模型中给校验参数分配分组


@Data@ApiModel(value="ValidEntity")
publicclassValidEntity {
privateintid;
@NotBlank(groups=ValidGroup.Crud.Update.class)
privateStringappId;
@NotBlank(groups=ValidGroup.Crud.Create.class)
privateStringname;
@EmailprivateStringemail;
}

tips:这里@Email注解未指定分组,默认会属于Default分组,appId和name指定了分组就不会再属于Default分组了。


  1. 在参数校验时通过value属性指定分组

cb3e4867d189ed3c6caef9fd38c58eba.png


这里通过@Validated(value = ValidGroup.Crud.Update.class)指定了具体的分组,上面提到的是否继承Default的区别在于:


如果继承了Default,@Validated标注的注解也会校验未指定分组或者Default分组的参数,比如email

如果不继承Default则不会校验未指定分组的参数,需要加上@Validated(value = {ValidGroup.Crud.Update.class, Default.class}才会校验

快速失败(Fali Fast)

默认情况下在对参数进行校验时Spring Validation会校验完所有字段然后才抛出异常,可以通过配置开启Fali Fast模式,一旦校验失败就立即返回。


@ConfigurationpublicclassValidatedConfig {
@BeanpublicValidatorvalidator() {
ValidatorFactoryvalidatorFactory=Validation.byProvider(HibernateValidator.class)
                .configure()
// 快速失败模式                .failFast(true)
                .buildValidatorFactory();
returnvalidatorFactory.getValidator();
    }
}
目录
相关文章
|
5月前
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
402 7
|
2月前
|
前端开发 Java 数据库连接
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
|
5月前
|
人工智能 Java 数据库
飞算 JavaAI:革新电商订单系统 Spring Boot 微服务开发
在电商订单系统开发中,传统方式耗时约30天,需应对复杂代码、调试与测试。飞算JavaAI作为一款AI代码生成工具,专注于简化Spring Boot微服务开发。它能根据业务需求自动生成RESTful API、数据库交互及事务管理代码,将开发时间缩短至1小时,效率提升80%。通过减少样板代码编写,提供规范且准确的代码,飞算JavaAI显著降低了开发成本,为软件开发带来革新动力。
|
4月前
|
供应链 JavaScript BI
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
这是一款专为小微企业打造的 SaaS ERP 管理系统,基于 SpringBoot+Vue+ElementUI+UniAPP 技术栈开发,帮助企业轻松上云。系统覆盖进销存、采购、销售、生产、财务、品质、OA 办公及 CRM 等核心功能,业务流程清晰且操作简便。支持二次开发与商用,提供自定义界面、审批流配置及灵活报表设计,助力企业高效管理与数字化转型。
423 2
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
|
3月前
|
Java API 微服务
Java 21 与 Spring Boot 3.2 微服务开发从入门到精通实操指南
《Java 21与Spring Boot 3.2微服务开发实践》摘要: 本文基于Java 21和Spring Boot 3.2最新特性,通过完整代码示例展示了微服务开发全流程。主要内容包括:1) 使用Spring Initializr初始化项目,集成Web、JPA、H2等组件;2) 配置虚拟线程支持高并发;3) 采用记录类优化DTO设计;4) 实现JPA Repository与Stream API数据访问;5) 服务层整合虚拟线程异步处理和结构化并发;6) 构建RESTful API并使用Springdoc生成文档。文中特别演示了虚拟线程配置(@Async)和StructuredTaskSco
364 0
|
Java Spring 前端开发
spring 3.2 自定义参数绑定--日期格式转换器
springmvc配置文件 &lt;!-- 代替org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 和org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter --&gt;
2497 0
|
2月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
719 0
|
6月前
|
前端开发 Java 数据库
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
296 0
|
2月前
|
缓存 JSON 前端开发
第07课:Spring Boot集成Thymeleaf模板引擎
第07课:Spring Boot集成Thymeleaf模板引擎
364 0
第07课:Spring Boot集成Thymeleaf模板引擎
|
6月前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
261 0