自定義註解+springAop實現引數的分組驗證
阿新 • • 發佈:2019-02-20
廢話:一個同事寫的,感覺很實用,然後我從中整理出來的一個小demo。
問題引入
在日常開發中免不了對傳入的引數進行校驗,例如更新資料的時候id不能為空,新增資料的時候某個元素不能為空等。我們不得不寫類似於下面的程式碼:
@RequestMapping("/createStudent")
public Object createStudent( Student student) {
String name = student.getName();
if ( StringUtils.isEmpty( name ) ){
return "姓名不能為空";
}
return student;
}
@RequestMapping("/updateStudent")
public Object updateStudent( Student student) {
String id = student.getId();
if ( StringUtils.isEmpty( id ) ){
return "id不能為空";
}
return student;
}
這樣確實有很多重複的程式碼,於是就想著去解決,我把問題簡化為下面的小demo,以供參考。
專案結構
定義註解用於分組
@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validate
{
Class<?>[] groups() default { };
}
定義兩個組
public interface Create { }
public interface Update { }
具體邏輯實現(重點)
@Component // 加入到IoC容器
@Aspect // 指定當前類為切面類
public class Aop {
@Autowired
protected Validator validator;
//@Pointcut("@annotation(springboot.Validate)")
@Pointcut("execution(* springboot.*.*(..))")
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 獲取當前方法
Parameter[] parameters = method.getParameters();
if (parameters != null && parameters.length > 0) {
for (int j = 0; j < parameters.length; j++) {
Parameter parameter = parameters[j];
Validate validate = parameter.getAnnotation(Validate.class);// 獲取引數的註解
if (validate != null) {
Object arg = joinPoint.getArgs()[j];// 獲取到引數
Class<?>[] groups = validate.groups();// 獲取註解引數,驗證組
List<ViolationMessage> violationErrors =groups.length!=0?beanValidator(arg, groups):beanValidator(arg);// 引數有效性驗證
if (violationErrors != null) {
return violationErrors;// 驗證不通過,返回結果
}
}
}
}
return joinPoint.proceed();
}
public List<ViolationMessage> beanValidator(Object object, Class<?>... groups) {
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
if (!constraintViolations.isEmpty()) {
List<ViolationMessage> list = new ArrayList<>();
ViolationMessage vm = new ViolationMessage();
for (ConstraintViolation<Object> cv : constraintViolations) {
vm = new ViolationMessage();
vm.setProperty(cv.getPropertyPath().toString());
vm.setMessage(cv.getMessageTemplate());
list.add(vm);
}
return list;
}
return null;
}
}
原理,利用aop獲取獲取註解上的分組資訊與當前引數,然後用validator進行校驗。
實體類
public class Student {
@NotNull(message="id:不能為空",groups={Update.class})
@Size(min = 3, max = 20, message = "id長度只能在3-20之間", groups = { Update.class})
private String id;
@NotNull(message = "姓名不能為空", groups = {Create.class})
private String name;
private String age;
/**get set省略**/
}
錯誤資訊封裝
public class ViolationMessage implements Serializable{
private static final long serialVersionUID = 1L;
private String property;
private String message;
/**get set省略**/
}
controller類
@RestController
public class TestController {
@RequestMapping("/createChack")
public Object createChack(@Validate(groups={Create.class}) Student student) {
return student;
}
@RequestMapping("/updateChack")
public Object updateChack(@Validate(groups={Update.class}) Student student) {
return student;
}
}
執行SpringbootFirstApplication啟動專案進行測試
具體專案見碼雲:
參考部落格: