大家好,我是二哥。最近在开发一个知识库学习网站编程猫。需要对请求参数进行校验,比如非空、长度限制等。有两种可选的解决方案:一种是使用HibernateValidator来处理一种处理全局异常的方式,有两种。让我们一一练习体验。一、HibernateValidatorSpringBoot内置了HibernateValidator验证框架,可以通过SpringBoot官网查看确认。第一步,进入SpringBoot官网,点击学习面板,点击参考文档。第二步是在参考文档页面点击“DependentVersions”。第三步,可以在依赖版本页面查看所有依赖,包括版本号。PS:如果发现不行,可能是依赖版本冲突。您可以手动将HibernateValidator依赖项添加到pom.xml文件中。<依赖>org.hibernate.validatorhibernate-validator6.0.17.Finaljavax.validationvalidation-api2.0.1.Final通过HibernateValidator验证框架,我们可以直接在请求参数的字段中添加注解完成检查。具体怎么做呢?第一步是在需要验证的字段上添加HibernateValidator提供的验证注解。比如我现在有一个用户名和密码登录请求参数UsersLoginParamclass:@Data@ApiModel(value="UserLogin",description="UserTable")publicclassUsersLoginParamimplementsSerializable{privatestaticfinallongserialVersionUID=1L;@ApiModelProperty(value="登录名")@NotBlank(message="登录名不能为空")privateStringuserLogin;@ApiModelProperty(value="password")@NotBlank(message="passwordcannotbeempty")privateStringuserPass;}您可以使用@NotBlank注解来检查用户名和密码是否为空。除了@NotBlank注解,HibernateValidator还提供了以下常用注解:@NotNull:被注解的字段不能为null;@NotEmpty:注解字段不能为空;@Min:被注解的字段必须大于等于它的值;@Max:被注解的字段必须小于等于它的值;@Size:被注解的字段必须在其最小值和最大值之间;@Pattern:被注解的字段必须符合定义的正则表达式;@Email:注解字段必须符合邮箱格式。第二步,在对应的请求接口(UsersController.login())中添加@Validated注解,并注入一个BindingResult参数。@Controller@Api(tags="User")@RequestMapping("/users")publicclassUsersController{@AutowiredprivateIUsersServiceusersService;@ApiOperation(value="登录后返回token")@RequestMapping(value="/login",method=RequestMethod.POST)@ResponseBodypublicResultObjectlogin(@ValidatedUsersLoginParamusers,BindingResultresult){Stringtoken=usersService.login(users.getUserLogin(),users.getUserPass());if(token==null){returnResultObject.validateFailed("用户名或密码错误");}MaptokenMap=newHashMap<>();tokenMap.put("令牌",令牌);tokenMap.put("tokenHead",tokenHead);返回ResultObject.success(tokenMap);}}第三步,为控制层(UsersController)创建切面,将通知注入到BindingResult对象中,然后判断是否有验证错误,如果有错误信息则返回验证提示,否则释放.@Aspect@Component@Order(2)publicclassBindingResultAspect{@Pointcut("执行(public*com.codingmore.controller.*.*(..))")publicvoidBindingResult(){}@Around("BindingResult()")publicObjectdoAround(ProceedingJoinPointjoinPoint)throwsThrowable{Object[]args=joinPoint.getArgs();for(Objectarg:args){if(arginstanceofBindingResult){BindingResult结果=(BindingResult)arg;如果(结果.hasErrors()){FieldErrorfieldError=result.getFieldError();if(fieldError!=null){返回ResultObject.validateFailed(fieldError.getDefaultMessage());}else{返回ResultObject.validateFailed();}}}}返回joinPoint.proceed();}}这里涉及到SpringBootAOP的知识。我在上一篇文章中已经解释过了。点击此链接可直接进入:SpringBootAOP扫盲之Step4,访问登录界面如果用户名和密码均未传入,将返回“用户名不能为空”的提示信息。通过调试的形式,体验整个工作流程。可以看出,HibernateValidator带来的优势有:验证逻辑与业务逻辑分离,降低了程序耦合度;统一规范的验证方式,无需再次编写重复的验证码。但是,它也带来了一些缺点,例如:需要在请求接口的方法中注入BindingResult对象,只能验证一些很简单的逻辑,在数据查询时无能为力。2.全局异常处理使用全局异常处理的好处是更灵活,可以处理更复杂的逻辑验证。当验证失败时,直接抛出异常,然后捕获处理就可以了。第一步是创建自定义异常类ApiException。publicclassApiExceptionextendsRuntimeException{privateIErrorCodeerrorCode;publicApiException(IErrorCodeerrorCode){super(errorCode.getMessage());this.errorCode=errorCode;}publicApiException(Stringmessage){super(message);原因){超级(原因);}publicApiException(Stringmessage,Throwablecause){super(message,cause);}publicIErrorCodegetErrorCode(){返回错误代码;}}第二步是新建一个断言处理类Asserts来简化抛出ApiException的步骤。公共类断言{publicstaticvoidfail(Stringmessage){thrownewApiException(message);}publicstaticvoidfail(IErrorCodeerrorCode){thrownewApiException(errorCode);}}第三步,新建一个全局异常处理类GlobalExceptionHandler,解析异常信息并封装到统一的返回对象ResultObject中。@ControllerAdvice公共类GlobalExceptionHandler{@ResponseBody@ExceptionHandler(value=ApiException.class)publicResultObjecthandle(ApiExceptione){if(e.getErrorCode()!=null){returnResultObject.failed(e.getErrorCode());}返回ResultObject.failed(e.getMessage());}}全局异常处理类使用了两个注解,@ControllerAdvice和@ExceptionHandler。@ControllerAdvice是一个特殊的@Component(通过源码可以看出),用于标识一个类,由以下三个注解标识:@ExceptionHandler、@InitBinder、@ModelAttribute,它会作用于所有的@Controller类在界面上。@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic@interfaceControllerAdvice{}@ExceptionHandler注解用于标识统一的异常处理,可以指定统一处理的异常类型,例如,我们自己定义的ApiException。第四步,在需要验证的地方通过Asserts类抛出异常ApiException。还拿用户登录界面来说明。@Controller@Api(tags="User")@RequestMapping("/users")publicclassUsersController{@ApiOperation(value="登录后返回token")@RequestMapping(value="/login",method=RequestMethod.POST)@ResponseBodypublicResultObjectlogin(@ValidatedUsersLoginParamusers,BindingResult结果){Stringtoken=usersService.login(users.getUserLogin(),users.getUserPass());MaptokenMap=newHashMap<>();tokenMap.put("令牌",令牌);tokenMap.put("tokenHead",tokenHead);返回ResultObject.success(tokenMap);}}该接口需要查询数据库验证密码是否正确,如果密码不正确则抛出验证信息“Passwordisincorrect”。@ServicepublicclassUsersServiceImplextendsServiceImplimplementsIUsersService{publicStringlogin(Stringusername,Stringpassword){Stringtoken=null;//密码需要客户端加密后传给UserDetailsuserDetails=loadUserByUsername(username);if(!passwordEncoder.matches(password,userDetails.getPassword())){Asserts.fail("密码不正确");}//其他代码省略返回标记;}}第五步,通过ApiPost测试接口,故意把密码打错了。您还可以通过调试的形式体验整个工作流程。3.总结在实际开发中,两者结合可以弥补彼此的不足。简单的验证使用HibernateValidator,比较复杂的逻辑验证,比如数据库查询,需要全局异常处理来实现。源码地址:https://github.com/itwanger/coding-more参考链接:http://www.macrozheng.com本文转载自微信公众号《沉默之王2》,可通过以下关注二维码。转载本文请联系沉默王二公众号。