Aop增强记录日志

接到一个需求,记录对后台控制系统的所有增、删、改操作,将员工号与ip等相关信息记录下来。

分析下来,可在service层方法上添加切面,通过AOP来拦截记录控制信息。因为后台开发历史太久,经手人太多(屎堆),增删改操作命名不规范,故不适合用切点表达式来做切点。故采用自定义注解方法,在需要记录的操作上添加注解就可以了。

1.切面

LOGGER为公司日志组件,可用合适日志工具替换。

request正常获取的条件是,该切点的方法只能被http请求调用。如果job或者远程服务的方法调用是无法获取request的。



@Aspect
@Component
public class LogServiceAspect {
    private static final SnfLogger LOGGER = SnfLoggerFactory.getLogger(LogServiceAspect.class);
    private static final String SPLIT_STR = ";";
    private static final String JOIN_STR = "#";

    /**
     * 该切面用于service层,获取service的入参、出参等用于打印日志。
     * 注意—当调用非http请求调用方法时,无法获取上下文的request。
     * 所以当该service方法有被非http请求调用时,不宜使用该切面
     * @param joinPoint
     * @return
     */
    @Around(value = "@annotation(com.suning.springaop.LogAnnotation)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        String ip =StringUtils.EMPTY;
        String employeeId =StringUtils.EMPTY;
        String function =StringUtils.EMPTY;//功能说明,通过解析注解信息获取
        String classAndMethod =StringUtils.EMPTY;
        String params =StringUtils.EMPTY;//入参
        try {
            //获取requeset
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            //获取员工号
            employeeId = request.getRemoteUser();
            // 获取ip
            ip = GetClientIPUtil.getClientIP(IpUtils.getIpAddr(request));
            //获取类、方法名
            String className = joinPoint.getSignature().getDeclaringTypeName();
            String methodName = joinPoint.getSignature().getName();
            classAndMethod = className + SPLIT_STR + methodName;
            //获取注解内容
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Method targetMethod = methodSignature.getMethod();
            Method realMethod = joinPoint.getTarget().getClass().getDeclaredMethod(methodName, targetMethod.getParameterTypes());
            LogAnnotation logAnnotation = AnnotationUtils.findAnnotation(realMethod, LogAnnotation.class);
            //注解——功能描述
            String detail = logAnnotation.detail();
            //注解——功能模块
            MoudleEnum moudleEnum = logAnnotation.moudle();
            function = moudleEnum.toString() + SPLIT_STR + detail;
            //获取入参
            List<Object> args = Arrays.asList(joinPoint.getArgs());
            for (int i = 0; i < args.size(); i++) {
                params += JSONObject.toJSONString(args.get(i)) + JOIN_STR;
            }
            params = StringUtils.isBlank(params) ? params : params.substring(params.length() - 1);
        } catch (Exception e) {
            LOGGER.warn("LogAspException:", e);
        } finally {
            result = joinPoint.proceed();
            LOGGER.warn("{};{};{};{};{};{};", new Object[]{ip, employeeId, function, classAndMethod, params, result});
        }
        return result;
    }
}

2. 注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义日志增强注解
 * 在需要进行审计的方法上添加该注解,可在注解内部填写合适的描述信息
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface  LogAnnotation {
    String detail() default "...";
    MoudleEnum moudle() default MoudleEnum.DEFAULT ;
}

3.后台功能枚举类


import org.apache.commons.lang3.StringUtils;
/**
 * @Description 功能模块定义,枚举类。用于注解中描述方法所属功能模块
 *
 */
public enum MoudleEnum {
    MENU("menu","菜单模块"),
    ADDRESS("address","地址管理"),
    DEFAULT("default","未定义");

    private MoudleEnum(String code,String msg) {
        this.code = code;
        this.msg = msg;
    }

    private String msg;

    private String code;

    public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    /**
     * todo 该方法写的较差,后面改掉
     * @param code
     * @return 返回中文模块名称
     */
    public static String getMsgByCode(String code){
        if (StringUtils.isBlank(code)) {
            return StringUtils.EMPTY;
        }
        for (MoudleEnum msiConstellationEnum : MoudleEnum.values()) {
            if (msiConstellationEnum.getCode().equals(code)) {
                return msiConstellationEnum.getMsg();
            }
        }
        return StringUtils.EMPTY;
    }

    @Override
    public String toString() {
        return this.getCode()+";"+this.getMsg();
    }
}

4. aop配置

5.使用

6.效果

懒得截图,后面补

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

单剑撩花猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值