背景
在我们的项目实际开发中,由于使用dubbo框架,项目的所有的接口都是按照一定的规范来开发的,项目接口层的接口如下:
系统按照功能分包,所有的功能下面,都会有domain(VO数据),request(请求数据),response(返回数据),service(接口),所有的后台数据验证(使用jsr303注解验证),我们需要在对应的接口实现类上验证请求数据的合法性,以前的验证写法如下:
public class ArticleCreateRequest extends BaseRequest {
/**
* 标题
*/
@Length(min = 1, max = 1000, message = "标题长度不合法")
private String title;
/**
* 是否原创
*/
private Boolean isOriginal;
/**
* 作者
*/
@Length(min = 0, max = 50, message = "作者长度不合法")
private String authorName;
service 实现类上需要使用ValidationUtil.validate(request, response); 验证是否有非法信息
/**
* 高级查询文章类别
*
* @param request 高级查询文章类别请求
* @param passport 用户护照
* @return
*/
@Override
public CategoryFindResponse findCategory(CategoryFindRequest request, Passport passport) {
CategoryFindResponse response = new CategoryFindResponse();
ValidationUtil.validate(request, response);
if (response.hasError()) {
return response;
}
return categoryManager.find(request, passport);
}
这样的写法未尝不可,但是写多了这种重复劳动的代码,大家都会比较烦,且如果需要对接口打印日志数据的话,又需要在所有的类上增加日志信息,繁琐的很,因此针对此问题,设计了基于AOP的接口验证,不多说,直接上代码
AOP版本的接口验证:
package com.lsxin.framework.annotation;
import java.lang.annotation.*;
/**
* ***************************************************************
* <pre>
* Copyright (c) 2016 –苏州利盛欣信息科技有限公司
* Title: com.lsxin.framwork.annotation
* Description:
* History:
* <p> 2016/3/21 init</p>
* ***************************************************************
* 2016/3/21 V1.0 guzhixiong New Files for framework
* </pre>
*/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LsxMethod {
/**
* 是否需要Session 验证
* @return
*/
boolean needSession() default true;
/**
* 是否需要验证
* @return
*/
boolean needValidate() default true;
/**
* 是否需要打印日志
* @return
*/
boolean needLog() default true;
}
package com.lsxin.framework.support.spring;
import com.alibaba.fastjson.JSON;
import com.lsxin.framework.annotation.LsxMethod;
import com.lsxin.framework.business.request.BaseRequest;
import com.lsxin.framework.business.response.BaseResponse;
import com.lsxin.framework.exception.ErrorType;
import com.lsxin.framework.log.LsxLog;
import com.lsxin.framework.support.security.Passport;
import org.apache.commons.beanutils.BeanUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
/**
* ***************************************************************
* <pre>
* Copyright (c) 2016 –苏州利盛欣信息科技有限公司
* Title: com.lsxin.framework.support.spring
* Description:
* History:
* <p> 2016/3/23 init</p>
* ***************************************************************
* 2016/3/23 V1.0 guzhixiong New Files for framework
* </pre>
*/
@Aspect
public class MethodAop {
private LsxLog log = LsxLog.getInstance(MethodAop.class,"framework");
@Pointcut("@annotation(com.lsxin.framework.annotation.LsxMethod)")
public void methodPointcut() {
}
@Around("methodPointcut()&& @annotation(lsxMethod)")
public Object aroundMethod(ProceedingJoinPoint joinPoint,LsxMethod lsxMethod)throws Throwable {
String targetName = joinPoint.getTarget().getClass().getName();
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Class returnType = methodSignature.getReturnType();
String methodName = methodSignature.getName();
Object[] arguments = joinPoint.getArgs();
//判断是否有日志
if(lsxMethod!=null&&lsxMethod.needLog()){
StringBuffer sb = new StringBuffer();
if ((arguments != null) && (arguments.length != 0)) {
for (int i = 0; i < arguments.length; i++) {
if(i>0){
sb.append(",").append(JSON.toJSONString(arguments[i]));
}else {
sb.append(JSON.toJSONString(arguments[i]));
}
}
}
log.i("execute {}.{} \n parameters:{}", targetName , methodName,sb);
}
if(lsxMethod!=null&&lsxMethod.needSession()){
//验证登录情况,判断标准passport 不为null
boolean haslogin = false;
for (int i = 0; i < arguments.length; i++) {
if(arguments[i]!=null&&arguments[i] instanceof Passport){
haslogin = true;
break;
}
}
if(!haslogin){
BaseResponse baseResponse = new BaseResponse();
baseResponse.addError(ErrorType.BUSINESS_ERROR,"您无权操作,请登录后操作..");
return JSON.parseObject(JSON.toJSONString(baseResponse),returnType);
}
}
if(lsxMethod!=null&&lsxMethod.needValidate()){
//判断参数是否需要验证
BaseResponse response = new BaseResponse();
for (int i = 0; i < arguments.length; i++) {
if(arguments[i]!=null&&arguments[i] instanceof BaseRequest){
if(((BaseRequest) arguments[i]).vlidate()!=null){
response.addErrors(((BaseRequest) arguments[i]).vlidate());
}
}
}
if(response.hasError()){
return JSON.parseObject(JSON.toJSONString(response),returnType);
}
}
return joinPoint.proceed();
}
}
使用:
系统只需要配置对应的aop 然后在对应的接口实现类上标注lsxmethod 注解即可,方法可以根据相应的需要设置是否需要验证
是否需要打印日志,是否需要验证是否登录,未来可以增加如方法执行的时间等等统计信息
打印的日志,对应的日志,直接通过Socket 发送到日志收集系统中,方便进行统一查看
是不是感觉世界又美好了点呢,(*^__^*) 嘻嘻