之前leader交给我一个校验controller入参的任务,最终代码不太符合要求,被废弃,特此把代码记录下来,便于以后整理,提高。
先讲一下怎么用,目前版本只需要在需要校验的controller方法上添加@Validate注解,处理类中会自动识别String和bean,bean类型,需要在对应字段上添加@Require,才会对字段进行非空校验。
废话不多说,先贴代码(先写个初版,待有时间整理一下这篇博客):
配置信息:(以@Validate为切点)
<bean id="validateAdvitor" class="com.zw.web.base.validators.ParamValidateAdvisor"/>
<aop:config proxy-target-class="true">
<aop:aspect ref="validateAdvitor">
<aop:pointcut expression="@annotation(com.zw.web.base.validators.annos.Validate)" id="validateCut"/>
<aop:around method="validate" pointcut-ref="validateCut"/>
</aop:aspect>
</aop:config>
自定义注解:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
*自定义校验注解
* @author WJ_wa
* @create 2018/8/21
* @since 1.0.0
*/
@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Validate {
public boolean isValidate() default true;
public boolean isBean() default false;
public boolean isRequest() default false;
}
import org.springframework.beans.factory.annotation.Required;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* bean实体中的〈必须项〉
* @author WJ_wa
* @create 2018/8/21
* @since 1.0.0
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Require {
public boolean isRequired() default true;
}
方法参数类:
import java.lang.annotation.Annotation;
/**
* 〈方法参数类
* @author WJ_wa
* @create 2018/8/21
* @since 1.0.0
*/
public class Param {
/**
* 名字
*/
private String name;
/**
* 类型
*/
private Class<?> type;
/**
* 值
*/
private Object value;
/**
* 注解
*/
private Annotation anno;
public Param() {
super();
}
public Param(String name, Class<?> type, Object value, Annotation anno) {
super();
this.name = name;
this.type = type;
this.value = value;
this.anno = anno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Class<?> getType() {
return type;
}
public void setType(Class<?> type) {
this.type = type;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public Annotation getAnno() {
return anno;
}
public void setAnno(Annotation anno) {
this.anno = anno;
}
@Override
public String toString() {
return "Param [name=" + name + ", type=" + type + ", value=" + value + ", anno=" + anno + "]";
}
}
注解帮助类:
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.zw.web.base.validators.annos.Validate;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import javax.servlet.http.HttpServletRequest;
/**
* 注解帮助类
* @author WJ_wa
* @create 2018/8/21
* @since 1.0.0
*/
public class AnnotationHelper {
/**
* 获取MethodSignature
* @param point
* @return
*/
public static Signature getMethod(ProceedingJoinPoint point){
MethodSignature sign = (MethodSignature) point.getSignature();
return sign;
}
/**
* 获取参数列表
* @param point
* @return
*/
public static Object[] getArgs(ProceedingJoinPoint point){
return point.getArgs();
}
/**
* 获取参数的描述(加Validate注解的)
* @param method
* @param objs
* @return
*/
public static List<Param> getParms(Method method, Object[] objs) throws Exception{
Annotation annotation = null;
Annotation[][] annos = method.getParameterAnnotations();
Annotation[] annosMethod = method.getAnnotations();
for(Annotation ann : annosMethod){
if(ann.annotationType() == Validate.class){
annotation = ann;
break;
}
}
Class<?>[] paramTypes = method.getParameterTypes();
List<Param> params = new ArrayList<Param>();
for(int i=0;i<annos.length;i++){
boolean flag = true;
for(int j=0;j<annos[i].length;j++){
//如果出现指定的注解类型
if(annos[i][j].annotationType() == Validate.class){
Param param = new Param(paramTypes[i].getName(),
paramTypes[i],
objs[i],
annos[i][j]);
params.add(param);
flag = false;
}
}
//参数上无注解,主动加上注解,后面判断逻辑需要
if(flag){
String name = paramTypes[i].getName();
//此处判断是bean类型的
if(name != String.class.getName() && name != HttpServletRequest.class.getName()){
//获取 annotation 这个代理实例所持有的 InvocationHandler
InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);
// 获取 AnnotationInvocationHandler 的 memberValues 字段
Field declaredField = invocationHandler.getClass().getDeclaredField("memberValues");
// 因为这个字段是 private final 修饰,所以要打开权限
declaredField.setAccessible(true);
// 获取 memberValues
Map memberValues = (Map) declaredField.get(invocationHandler);
// 修改 value 属性值
memberValues.put("isBean", true);
Param param = new Param(paramTypes[i].getName(),
paramTypes[i],
objs[i],
annotation);
params.add(param);
continue;
}
//判断是request类型的,暂时无用,目前不处理request
if(name == HttpServletRequest.class.getName()){
//获取 annotation 这个代理实例所持有的 InvocationHandler
InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);
// 获取 AnnotationInvocationHandler 的 memberValues 字段
Field declaredField = invocationHandler.getClass().getDeclaredField("memberValues");
// 因为这个字段是 private final 修饰,所以要打开权限
declaredField.setAccessible(true);
// 获取 memberValues
Map memberValues = (Map) declaredField.get(invocationHandler);
// 修改 value 属性值
memberValues.put("isRequest", true);
Param param = new Param(paramTypes[i].getName(),
paramTypes[i],
objs[i],
annotation);
params.add(param);
continue;
}
}
}
return params;
}
}
切面实现:
import com.base.util.TraceLoggerUtil;
import com.zw.util.ChkUtil;
import com.zw.web.base.validators.annos.Require;
import com.zw.web.base.validators.annos.Validate;
import com.zw.web.base.vo.ResultVO;
import com.zw.web.base.vo.VOConst;
import org.aspectj.lang.ProceedingJoinPoint;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletResponse;
/**
* 〈参数验证〉
*
* @author WJ_wa
* @create 2018/8/21
* @since 1.0.0
*/
public class ParamValidateAdvisor{
/**
* 校验入参
* @param point
* @throws Throwable
*/
public Object validate(ProceedingJoinPoint point) throws Throwable{
TraceLoggerUtil.info("开始拦截接口入参!");
//获取切点处的所有入参
Object[] objs = point.getArgs();
//获取response
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
//获取方法签名
MethodSignature signature = (MethodSignature) point.getSignature();
//获取方法
Method method = signature.getMethod();
/**
* 下面代码是校验参数是否有@Validate注解,现在废弃掉;需求:方法上添加@Validate注解即校验所有入参,有不想校验的,在对应参数前添加@Validate(isValidate=false)
*/
// //获取入参的注解
// Annotation[][] annosParam = method.getParameterAnnotations();
// //校验
// boolean paramFlag = validateParameterAnnotation(annosParam);
// //虽然方法加了注解,但是参数么有注解,pass
// if(!paramFlag){
// return point.proceed(objs);
// }
List<Param> params = AnnotationHelper.getParms(method,objs);
if(!params.isEmpty()){
for(Param param : params){
boolean isSuccess = validateDetail(param);
if(!isSuccess){
TraceLoggerUtil.error("入参校验失败!param{}",param);
try {
PrintWriter out = response.getWriter();
ResultVO resultVO = new ResultVO();
resultVO.setErrorMsg(VOConst.FAIL, "系统繁忙,请您稍后尝试,如多次尝试失败,请联系客服。");
out.write(resultVO.toString());
out.flush();
return null;
}catch (Exception e){
TraceLoggerUtil.error("输出入参校验失败信息到response失败!");
}
}
}
}
TraceLoggerUtil.info("接口入参校验结束,全部通过!");
//没有错误就继续!
return point.proceed(objs);
}
/**
* 验证是否有某个注解,带有@Validate注解的才会校验
* @param annosParam
* @param
* @return
*/
private boolean validateParameterAnnotation(Annotation[][] annosParam){
boolean flag = false;
for(Annotation[] at : annosParam){
for(Annotation a : at){
if(a.annotationType() == Validate.class){
flag = true;
}
}
}
return flag;
}
/**
* 具体的校验逻辑
* @param
* @return
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
private boolean validateDetail(Param param) throws IllegalArgumentException, IllegalAccessException{
Validate val = (Validate)param.getAnno();
boolean isVali = val.isValidate();
boolean result = false;
if(isVali){
if(val.isBean() == true){
result= validateForm(param);
}else if(val.isRequest() == true){
//校验request的未用,暂留,里面未写逻辑代码
result= validateRequest(param);
}else{
result = validateCommon(param);
}
}
return result;
}
/**
* 验证非bean类型、非HttpServletRequest类型参数是否为空
* @param param
* @return
*/
private boolean validateCommon(Param param){
boolean res = false;
if(ChkUtil.isNotEmpty(param.getValue())){
res = true;
}
return res;
}
/**
* 验证HttpServletRequest类型参数是否为空,暂时不可用,待拓展
* @param param
* @return
*/
private boolean validateRequest(Param param){
return true;
}
/**
* 验证bean类型参数是否为空
* @param param
* @return
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
private boolean validateForm(Param param) throws IllegalArgumentException, IllegalAccessException{
Class<?> clazz = param.getValue().getClass();
Field[] fields = clazz.getDeclaredFields();
for(Field f : fields){
Annotation[] annos = f.getAnnotations();
if(annos!=null&&annos.length>0){
Require require = (Require)annos[0];
if(require.isRequired()){
//允许访问私有变量
f.setAccessible(true);
Object obj = f.get(param.getValue());
Class<?> type = f.getType();
//鉴于目前bean类中字段类型全部为String,此处只校验String类型,其他类型数据请自行拓展
if(type == String.class){
if(ChkUtil.isEmpty(obj)){
return false;
}
}
}
}
}
return true;
}
}
版权声明:本文为w1171155814原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。