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();
    }
}
目录
相关文章
|
25天前
|
JSON 前端开发 Java
Spring MVC——获取参数和响应
本文介绍了如何在Spring框架中通过不同的注解和方法获取URL参数、上传文件、处理cookie和session、以及响应不同类型的数据。具体内容包括使用`@PathVariable`获取URL中的参数,使用`MultipartFile`上传文件,通过`HttpServletRequest`和`@CookieValue`获取cookie,通过`HttpSession`和`@SessionAttribute`获取session,以及如何返回静态页面、HTML代码片段、JSON数据,并设置HTTP状态码和响应头。
42 1
Spring MVC——获取参数和响应
|
1天前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
8 0
|
29天前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
24 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
12天前
|
JavaScript 前端开发 Java
SpringBoot_web开发-webjars&静态资源映射规则
https://www.91chuli.com/ 举例:jquery前端框架
12 0
|
28天前
|
监控 Java Maven
springboot学习二:springboot 初创建 web 项目、修改banner、热部署插件、切换运行环境、springboot参数配置,打包项目并测试成功
这篇文章介绍了如何快速创建Spring Boot项目,包括项目的初始化、结构、打包部署、修改启动Banner、热部署、环境切换和参数配置等基础操作。
111 0
|
29天前
|
开发框架 Java API
「SpringBrick快速入门指南」:一款基于Spring Boot的高级插件化开发框架
「SpringBrick快速入门指南」:一款基于Spring Boot的高级插件化开发框架
46 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;
2438 0
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
30天前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
149 2
|
2天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
11 2
 SpringBoot入门(7)- 配置热部署devtools工具
下一篇
无影云桌面