广州建外贸网站公司,500元建站,广东商城网站建设报价,站群网站源码最近正在开发一个校园管理系统#xff0c;需要对请求参数进行校验#xff0c;比如说非空啊、长度限制啊等等#xff0c;可选的解决方案有两种#xff1a;
一种是用 Hibernate Validator 来处理一种是用全局异常来处理
两种方式#xff0c;我们一一来实践体验一下。 一、…最近正在开发一个校园管理系统需要对请求参数进行校验比如说非空啊、长度限制啊等等可选的解决方案有两种
一种是用 Hibernate Validator 来处理一种是用全局异常来处理
两种方式我们一一来实践体验一下。 一、Hibernate Validator Spring Boot 已经内置了 Hibernate Validator 校验框架这个可以通过 Spring Boot 官网查看和确认。
第一步进入 Spring Boot 官网点击 learn 这个面板点击参考文档。 第二步在参考文档页点击「依赖的版本」。 第三步在依赖版本页就可以查看到所有的依赖了包括版本号。 PS如果发现没有起效可能是依赖版本冲突了手动把 Hibernate Validator 依赖添加到 pom.xml 文件就可以了。 dependencygroupIdorg.hibernate.validator/groupIdartifactIdhibernate-validator/artifactIdversion6.0.17.Final/version
/dependency
dependencygroupIdjavax.validation/groupIdartifactIdvalidation-api/artifactIdversion2.0.1.Final/version
/dependency
通过 Hibernate Validator 校验框架我们可以直接在请求参数的字段上加入注解来完成校验。
具体该怎么做呢 第一步在需要验证的字段上加上 Hibernate Validator 提供的校验注解。 比如说我现在有一个用户名和密码登录的请求参数 LoginForm类
Data
ApiModel(value 用户·登录 , description 用户表)
public class LoginForm {ApiModelProperty(value 登录名)NotBlank(message 登录名不能为空)private String username;ApiModelProperty(value 密码)NotBlank(message 密码不能为空)private String password;private String verifiCode;private Integer userType;}
就可以通过 NotBlank 注解来对用户名和密码进行判空校验。除了 NotBlank 注解Hibernate Validator 还提供了以下常用注解 NotNull被注解的字段不能为 nullNotEmpty被注解的字段不能为空Min被注解的字段必须大于等于其value值Max被注解的字段必须小于等于其value值Size被注解的字段必须在其min和max值之间Pattern被注解的字段必须符合所定义的正则表达式Email被注解的字段必须符合邮箱格式。
第二步在对应的请求接口SystemController.login()中添加 Validated 注解并注入一个 BindingResult 参数。 ApiOperation(登录的方法)PostMapping(/login)public Result login(ApiParam(登录提交信息的form表单)RequestBodyValidated LoginForm loginForm, HttpServletRequest request , BindingResult result){//loginForm中此时有客户端传进来的 private String username;// private String password;// private String verifiCode;// private Integer userType;// 验证码校验HttpSession session request.getSession();String sessionVerifiCode (String)session.getAttribute(verifiCode);String loginVerifiCode loginForm.getVerifiCode();if(.equals(sessionVerifiCode) || null sessionVerifiCode){return Result.fail().message(验证码失效,请刷新后重试);}if (!sessionVerifiCode.equalsIgnoreCase(loginVerifiCode)){return Result.fail().message(验证码有误,请小心输入后重试);}// 从session域中移除现有验证码session.removeAttribute(verifiCode);// 分用户类型进行校验// 准备一个map用户存放响应的数据MapString,Object mapnew LinkedHashMap();switch (loginForm.getUserType()){case 1:try {Admin adminadminService.login(loginForm);if (null ! admin) {// 用户的类型和用户id转换成一个密文,以token的名称向客户端反馈map.put(token,JwtHelper.createToken(admin.getId().longValue(), 1));}else{throw new RuntimeException(用户名或者密码有误);}return Result.ok(map);} catch (RuntimeException e) {e.printStackTrace();return Result.fail().message(e.getMessage());}case 2:try {Student student studentService.login(loginForm);if (null ! student) {// 用户的类型和用户id转换成一个密文,以token的名称向客户端反馈map.put(token,JwtHelper.createToken(student.getId().longValue(), 2));}else{throw new RuntimeException(用户名或者密码有误);}return Result.ok(map);} catch (RuntimeException e) {e.printStackTrace();return Result.fail().message(e.getMessage());}case 3:try {Teacher teahcer teacherService.login(loginForm);if (null ! teahcer) {// 用户的类型和用户id转换成一个密文,以token的名称向客户端反馈map.put(token,JwtHelper.createToken(teahcer.getId().longValue(), 3));}else{throw new RuntimeException(用户名或者密码有误);}return Result.ok(map);} catch (RuntimeException e) {e.printStackTrace();return Result.fail().message(e.getMessage());}}return Result.fail().message(查无此用户);}
第三步为控制层SystemController创建一个切面将通知注入到 BindingResult 对象中然后再判断是否有校验错误有错误的话返回校验提示信息否则放行。
Aspect
Component
Order(2)
Slf4j
public class BindingResultAspect {Pointcut(execution(src* com.atguigu.myzhxy.controller.*.*(..)))public void BindingResult() {}Around(BindingResult())public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {Object[] args joinPoint.getArgs();for (Object arg : args) {if (arg instanceof BindingResult) {BindingResult result (BindingResult) arg;if (result.hasErrors()) {FieldError fieldError result.getFieldError();if(fieldError!null){return Result.validateFailed(fieldError.getDefaultMessage());}else{return Result.validateFailed();}}}}return joinPoint.proceed();}
}第四步访问登录接口用户名和密码都不传入的情况下就会返回“用户名不能为空”的提示信息。 可以看得出Hibernate Validator 带来的优势有这些 验证逻辑与业务逻辑进行了分离降低了程序耦合度统一且规范的验证方式无需再次编写重复的验证代码。 不过也带来一些弊端比如说 需要在请求接口的方法中注入 BindingResult 对象而这个对应在方法体中并没有用到只能校验一些非常简单的逻辑涉及到数据查询就无能为力了。 二、全局异常处理
使用全局异常处理的优点就是比较灵活可以处理比较复杂的逻辑校验在校验失败的时候直接抛出异常然后进行捕获处理就可以了。 第一步新建一个自定义异常类 ApiException。
public class ApiException extends RuntimeException {private IErrorCode errorCode;public ApiException(IErrorCode errorCode) {super(errorCode.getMessage());this.errorCode errorCode;}public ApiException(String message) {super(message);}public ApiException(Throwable cause) {super(cause);}public ApiException(String message, Throwable cause) {super(message, cause);}public IErrorCode getErrorCode() {return errorCode;}
} 第二步新建一个断言处理类 Asserts简化抛出 ApiException 的步骤 public class Asserts {public static void fail(String message) {throw new ApiException(message);}public static void fail(IErrorCode errorCode) {throw new ApiException(errorCode);}
}
第三步新建一全局异常处理类 GlobalExceptionHandler对异常信息进行解析并封装到统一的返回对象 ResultObject 中。 ControllerAdvice
public class GlobalExceptionHandler {ResponseBodyExceptionHandler(value ApiException.class)public ResultObject handle(ApiException e) {if (e.getErrorCode() ! null) {return ResultObject.failed(e.getErrorCode());}return ResultObject.failed(e.getMessage());}
} 全局异常处理类用到了两个注解ControllerAdvice 和 ExceptionHandler。 ControllerAdvice 是一个特殊的 Component可以通过源码看得到用于标识一个类这个类中被以下三种注解标识的方法ExceptionHandlerInitBinderModelAttribute将作用于所有Controller 类的接口上。 Target({ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Documented
Component
public interface ControllerAdvice {
}
ExceptionHandler 注解的作用就是标识统一异常处理它可以指定要统一处理的异常类型比如说我们自定义的 ApiException。 第四步在需要校验的地方通过 Asserts 类抛出异常 ApiException。还拿用户登录这个接口来说明吧。 该接口需要查询数据库验证密码是否正确如果密码不正确就抛出校验信息“密码不正确”。 switch (loginForm.getUserType()){case 1:try {Admin adminadminService.login(loginForm);if (null ! admin) {// 用户的类型和用户id转换成一个密文,以token的名称向客户端反馈map.put(token,JwtHelper.createToken(admin.getId().longValue(), 1));}else{Asserts.fail(用户名或者密码有误);}return Result.ok(map);
也可以通过 debug 的形式体验一下整个工作流程。
三、总结 实际开发中把两者结合在一起用就可以弥补彼此的短板了简单校验用 Hibernate Validator复杂一点的逻辑校验比如说需要数据库