引子
數據驗證是每個系統都經常要做的,大多數情況下,我們是直接在方法裏面使用if語句判斷是否爲空,判斷是否是數字類型,判斷是否滿足條件,如果不滿足,就返回客戶端錯誤信息,這樣的話,就會顯得麻煩,可能同樣的判斷,在每個方法裏面都有寫一遍,代碼顯得臃腫,而且冗餘。其實我們有另一種方法進行判斷,使用AOP進行攔截,在方法執行前,先把不滿足條件的字段進行驗證。
準備
我們使用AOP進行判斷,主要的實現思路是結合註解實現,使用註解判斷標註要驗證的方法,然後使用AOP進行方法參數攔截,在dto對象上標註每個字段需要滿足的條件。需要使用如下JAR包validation-api.jar, spring-aop.jar
示例
我們創建一個項目, 首先創建攔截器,攔截器的作用是對方法進行攔截,對方法參數進行校驗,這裏使用MethodInterceptor環繞通知
package org.supersoft.erp.validation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class ValidationMethodInterceptor implements MethodInterceptor {
/**
* 環繞通知
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
Object[] arguments = invocation.getArguments();
//判斷是否開啓校驗,凡是標註有@Validatable纔開啓校驗
boolean validation = method.isAnnotationPresent(Validatable.class);
if(!validation) {
//沒有開啓校驗的直接執行
return invocation.proceed();
}
try {
//開啓校驗後,並且有參數的進行判斷
if(arguments != null && arguments.length > 0){
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Validatable validatable = method.getAnnotation(Validatable.class);
Class<?>[] groups = validatable.groups();
for(Object argument : arguments){
Set<ConstraintViolation<Object>> constraintViolations = new HashSet<ConstraintViolation<Object>>();
System.out.println(argument+"-------");
if(groups != null && groups.length > 0)
{
constraintViolations = validator.validate(argument, groups);
} else
{
constraintViolations = validator.validate(argument);
}
if(constraintViolations != null && !constraintViolations.isEmpty())
{
for(Iterator<ConstraintViolation<Object>> iterator = constraintViolations.iterator(); iterator.hasNext();)
{
String msgKey = iterator.next().getMessage();
Class<?> clazz = method.getReturnType();
return clazz.getConstructor(String.class).newInstance(msgKey);
}
}
}
}
} catch(NoSuchMethodException e){
System.out.println(method.getReturnType()+ "缺少僅包含一個String變量的構建方法");
} catch (Exception e) {
System.out.println(method.getName()+ "方法參數校驗失敗!");
}
return invocation.proceed();
}
}
添加一個註解,用於標註攔截哪些方法
package org.supersoft.erp.validation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({ METHOD})
@Retention(RUNTIME)
public @interface Validatable {
Class<?>[] groups() default {};
}
接下來建立幾個接口,用於操作分組,標註某個字段在執行什麼操作的時候進行判斷,比如同一個字段,有的時候需要在創建的時候進行判斷,有點需要在更新的時候進行判斷,
package org.supersoft.erp.validation;
public interface Create {
}
package org.supersoft.erp.validation;
public interface Retrieve {
}
package org.supersoft.erp.validation;
public interface Delete {
}
package org.supersoft.erp.validation;
public interface Update {
}
驗證規則
org.hibernate.validator.constraints包下面有許多定義好的驗證註解規則,可以直接標註在字段上,@NotBlank判斷是否爲空,@NotNull判斷是否爲null,引入hibernate-validator-5.3.0.Final.jar
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.0.Final</version>
</dependency>
創建一個dto對象
package org.supersoft.erp.rest.dto;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;
import org.supersoft.erp.validation.Create;
import org.supersoft.erp.validation.Delete;
import org.supersoft.erp.validation.Retrieve;
import org.supersoft.erp.validation.Update;
public class ProductDto {
public final static String CODE_REQUIRED = "code-required";
public final static String SCOPE_REQUIRED = "scope-required";
public final static String SCOPE_LENGTH = "scope-length-30";
public final static String CODE_LENGTH = "code-length-30";
public final static String NAME_REQUIRED = "name-required";
public final static String NAME_LENGTH = "name-length-30";
//編碼不能爲空,並且長度最大30
@NotBlank(message = CODE_REQUIRED, groups = { Update.class, Retrieve.class, Delete.class })
@Length(message = SCOPE_LENGTH, max = 30)
private String code;
//名稱不能爲空
@NotNull(message = NAME_REQUIRED, groups = { Create.class, Update.class })
private String name;
private String color;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
使用驗證註解,將驗證註解標註在方法上,並配置spring.aop
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="validationMethodInterceptor" class="org.supersoft.erp.validation.ValidationMethodInterceptor">
</bean>
<aop:config proxy-target-class="true">
<aop:pointcut id="restMethodPointcut" expression="execution(* org.supersoft.erp.rest..*.*(..))" />
<aop:advisor pointcut-ref="restMethodPointcut" advice-ref="validationMethodInterceptor" />
</aop:config>
</beans>
標註方法
* 修改
*/
@RequestMapping(value = "update", method = RequestMethod.POST)
@ResponseBody
@Validatable(groups = { Update.class })
public CommonResponse<?> updateProduct(@RequestBody ProductDto product) {
try
{
Product p=new Product();
BeanUtils.copyProperties(product, p);
productService.updateProduct(p);
return CommonResponse.result();
}
catch(Throwable t)
{
return CommonResponse.error();
}
}
然後,我們啓動程序,就可以進行驗證了
demo下載 http://download.csdn.net/detail/zx13525079024/9677511