基于SpringAop 的统一验证

背景

    在我们的项目实际开发中,由于使用dubbo框架,项目的所有的接口都是按照一定的规范来开发的,项目接口层的接口如下:

 102017_5gNT_100018.png

 系统按照功能分包,所有的功能下面,都会有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();
    }
}

使用:

103601_tR3j_100018.png

系统只需要配置对应的aop 然后在对应的接口实现类上标注lsxmethod 注解即可,方法可以根据相应的需要设置是否需要验证

是否需要打印日志,是否需要验证是否登录,未来可以增加如方法执行的时间等等统计信息

103712_sNT0_100018.png

打印的日志,对应的日志,直接通过Socket 发送到日志收集系统中,方便进行统一查看

104338_Tzf8_100018.png

是不是感觉世界又美好了点呢,(*^__^*) 嘻嘻

转载于:https://my.oschina.net/guzhixiong/blog/703197

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值