900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 基于SpringBoot参数校验器拓展自定义参数校验

基于SpringBoot参数校验器拓展自定义参数校验

时间:2019-06-09 01:00:47

相关推荐

基于SpringBoot参数校验器拓展自定义参数校验

基于SpringBoot参数校验器拓展自定义参数校验

想必工作中大家为了保证接口的稳定性与安全性都会对入参进行校验。五花八门的校验写法会让我们的代码不够整洁,本文将介绍如何使用SpringBoot为我们提供的参数校验器,并对其进行扩展,让其能够实现自定义校验。当然在一些互联网项目中,为保证接口的高性能,校验都是放在前端做的,但是在阿里开发规约中是这样说的越是简单的接口越不需要进行参数校验,越是复杂的接口越需要参数校验,因为复杂的接口试错成本很高,校验对接口性能的影响微乎其微。

工程中的使用可参照我的开源项目:/zhuhuijie/base-platform

在common-web模块中引入在example-business中使用

SpringBoot 参数校验器的使用

本章通过怎么引入SpringBoot的参数校验器,让大家能够搭建一个简单的Demo,文章的第二部分,自定义扩展才是本文的重头戏。

1 首先,pom文件引入参数校验器的依赖

<!--参数校验--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>

2 入参VO,加入相关的注解

常用注解:

@NotNull 非空验证

@Min(value = 1, message = “年龄不能小于1”)

@Max(value = 25, message = “年龄不能超过25”)

值区间验证

@Email(message = “必须是邮箱格式”) 邮箱格式验证

@Past(message = “生日范围不正确,生日必须是今天以前的”)

验证是否是过去的时间

import com.fasterxml.jackson.annotation.JsonFormat;import com.zhj.business.protocol.validhandler.BirthdayValidHandler;import mon.web.valid.annotation.MyValid;import lombok.Data;import javax.validation.constraints.*;import java.util.Date;/*** @author zhj*/@Datapublic class StudentInput {@NotNull(message = "名字不能为空")private String name;@Min(value = 1, message = "年龄不能小于1")@Max(value = 25, message = "年龄不能超过25")private Integer age;@NotNull(message = "邮箱不能为空")@Email(message = "必须是邮箱格式")private String email;@NotNull(message = "性别不能为空")private Integer sex;@NotNull(message = "生日不能为空")@Past(message = "生日范围不正确,生日必须是今天以前的")@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")private Date birthday;}

3 Controller 中开启校验,切记开启才会生效

import com.zhj.business.protocol.input.StudentInput;import com.zhj.business.service.StudentService;import mon.core.result.Result;import mon.core.util.ResultUtils;import com.zhj.data.entity.example.Student;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.BeanUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import javax.validation.Valid;import java.util.List;@Slf4j@RestController@RequestMapping("/student")public class StudentController {@Autowiredprivate StudentService studentService;@PostMapping("/add")public Result add(@Valid @RequestBody StudentInput studentInput) {log.info("接收到的学生信息:" + studentInput);Student student = new Student();BeanUtils.copyProperties(studentInput, student);boolean result = studentService.save(student);log.info("保存学生的结果" + result);return ResultUtils.createSuccess(student);}}

SpringBoot 参数校验器的扩展

本章将通过实现年龄与生日是否匹配的校验为例,为我们展示如何通过注解实现这类复杂的参数校验

1 首先呢,我们扩展需要参数校验器需要通过自定义注解实现

import mon.web.valid.constraint.MyParameterValid;import mon.web.valid.handler.MyValidHandler;import javax.validation.Constraint;import javax.validation.Payload;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/*** 自定义校验注解* @author zhj*/@Target({ElementType.FIELD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Constraint(validatedBy = MyParameterValid.class) // 对应校验类型public @interface MyValid {/*** 失败提示* @return*/String message() default "校验失败";/*** 校验分组* @return*/Class<?>[] groups() default {};/*** 校验的负载* @return*/Class<? extends Payload>[] payload() default {};/*** 扩展校验方法* @return*/Class<? extends MyValidHandler> handler();}

2 实现对Springboot参数校验器的自定义扩展

通过实现ConstraintValidator<MyValid, Object> 官方为我们提供的扩展接口,完成自定义注解的初始化从新实现校验方法 通过Spring容器获取自定义参数校验处理器MyValidHandler然后将注解与校验对象传入自定义的校验方法执行自定义校验方法,根据返回结果判断是否校验通过

import mon.web.util.ApplicationContextUtils;import mon.web.valid.annotation.MyValid;import mon.web.valid.handler.MyValidHandler;import lombok.extern.slf4j.Slf4j;import javax.validation.ConstraintValidator;import javax.validation.ConstraintValidatorContext;import java.util.Optional;/*** 自定义参数校验类* @author zhj*/@Slf4jpublic class MyParameterValid implements ConstraintValidator<MyValid, Object> {private MyValid myValid;@Overridepublic void initialize(MyValid constraintAnnotation) {this.myValid = constraintAnnotation;}/*** 校验方法* @param o* @param constraintValidatorContext* @return*/@Overridepublic boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {log.info("自定义参数校验触发" + o);if (null != o) {Class<? extends MyValidHandler> handler = myValid.handler();// 交给 MyValidHandler 处理校验MyValidHandler myValidHandler = ApplicationContextUtils.getBean(handler);return Optional.ofNullable(myValidHandler).map(myValidHandler1 -> {return myValidHandler.valid(myValid, o);}).orElse(false);}return true;}}

3 自定义处理接口

自定义校验方法通过实现该接口,重写校验方法

通过接口的多实现从而实现各种自定义处理。

import mon.web.valid.annotation.MyValid;/*** 扩展接口,开发者实现该接口,扩展校验方式* @author zhj*/public interface MyValidHandler<T> {/*** 实现校验方法* @param data* @return*/boolean valid(MyValid myValid, T data);}

4 获取Spring容器中对象的工具类

通过Spring上下文根据类名查找对应的实现

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationContext;import org.ponent;import javax.annotation.PostConstruct;/*** Spring 容器工具方法* @author zhj*/@Componentpublic class ApplicationContextUtils {@Autowiredprivate ApplicationContext applicationContext;/*** 静态容器对象*/private static ApplicationContext staticApplicationContext;@PostConstructprivate void init() {ApplicationContextUtils.staticApplicationContext = applicationContext;}public static <T> T getBean(Class<T> cls) {if (staticApplicationContext != null) {return staticApplicationContext.getBean(cls);}return null;}}

5 在入参VO类上添加自定义注解

handler = BirthdayValidHandler.class 将自定义校验方法的类名传入,该类需要实现自定义处理接口

import com.fasterxml.jackson.annotation.JsonFormat;import com.zhj.business.protocol.validhandler.BirthdayValidHandler;import mon.web.valid.annotation.MyValid;import lombok.Data;import javax.validation.constraints.*;import java.util.Date;/*** @author zhj*/@Data@MyValid(message = "年龄和生日不匹配", handler = BirthdayValidHandler.class)public class StudentInput {@NotNull(message = "名字不能为空")private String name;@Min(value = 1, message = "年龄不能小于1")@Max(value = 25, message = "年龄不能超过25")private Integer age;@NotNull(message = "邮箱不能为空")@Email(message = "必须是邮箱格式")private String email;@NotNull(message = "性别不能为空")private Integer sex;@NotNull(message = "生日不能为空")@Past(message = "生日范围不正确,生日必须是今天以前的")@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")private Date birthday;}

6 创建注解所写类名,实现自定义校验

切记需要将该对象注册进Spring容器中,否则扩展方式无法获取到该实例

本示例是实现,年龄与生日关系的校验,年龄和生日必须匹配才会校验成功

import com.zhj.business.protocol.input.StudentInput;import mon.web.valid.annotation.MyValid;import mon.web.valid.handler.MyValidHandler;import org.ponent;import java.util.Calendar;import java.util.Date;/*** @author zhj*/@Componentpublic class BirthdayValidHandler implements MyValidHandler<StudentInput> {@Overridepublic boolean valid(MyValid myValid, StudentInput data) {Integer age = data.getAge();Date birthday = data.getBirthday();if (age == null || birthday == null) return true;Calendar calendar = Calendar.getInstance();calendar.setTime(new Date());int currYear = calendar.get(Calendar.YEAR);calendar.setTime(birthday);int birYear = calendar.get(Calendar.YEAR);return currYear - birYear == age;}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。