• aop为系统添加操作日志,注入或配置声明的方式来实现


    最近做项目实现操作记录添加日志,由于aop这两种实现方式各有优缺点,所以都实现了一下以后根据具体业务选择。

    1实现方式一注入:

    1.1首先在xml中开启aop注入,需要引入的包此处省略,可百度自己查找。

    <aop:aspectj-autoproxy />

    1.2添加链接点

    package com.oasis.wyvern.res.service.base.logService;
    
    import java.lang.annotation.*;
    
    @Target({ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public  @interface SysSecureServiceLog {
        String description() default "";
    }

    1.3添加切入点,可以添加多个切入点同理也可添加多个链接点

    package com.oasis.wyvern.res.service.base.logService;
    
    import com.oasis.wyvern.res.common.biz.enums.base.type.ActionType;
    import com.oasis.wyvern.res.common.biz.enums.base.type.ServiceAopType;
    import com.oasis.wyvern.res.common.biz.vo.record.oplog.BizOpLogVo;
    import com.oasis.wyvern.res.dao.biz.record.oplog.SecureOpLogDao;
    import com.oasis.wyvern.res.model.base.context.secure.SecurityContextHolder;
    import com.oasis.wyvern.res.model.biz.record.oplog.SecureOpLog;
    import com.oasis.wyvern.res.service.base.record.oplog.BizOpLogService;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
     
    @Aspect
    @Component
    public class Aop2Log {
        private static final Logger logger = LoggerFactory.getLogger(Aop2Log.class);
        @Resource
        private BizOpLogService bizOpLogVoService;
    
        @Resource
        private SecureOpLogDao secureOpLogDao;
        /**
         *     用户Service层切点
         */
        @Pointcut("@annotation(com.oasis.wyvern.res.service.base.logService.ServiceLog)")
        public  void serviceAspect() {
        }
    
        /**
         * 系统安全层面切入点
         */
        @Pointcut("@annotation(com.oasis.wyvern.res.service.base.logService.SysSecureServiceLog)")
        public  void sysSecureServiceAspect() {
        }
    
        /**
         * 用户service
         * @param point
         */
        @AfterReturning("serviceAspect()")
        public void doAfter2Service(JoinPoint point){
            try {
                String actor ="";
                if(SecurityContextHolder.getContext().getUser()!=null){
                    actor = SecurityContextHolder.getContext().getUser().getLoginName();
                }
                String method = point.getSignature().getName();
                String entity = point.getTarget().getClass().getSimpleName();
                String args =  getAvailableArgs(point.getArgs());
                BizOpLogVo bizOpLogVo = new BizOpLogVo();
                bizOpLogVo.setActor(actor);
                bizOpLogVo.setEntityType(entity.replace("ServiceImpl",""));
                bizOpLogVo.setAction(methodType(method));
                bizOpLogVo.setUdf1(args.length()>200?args.substring(0,200):args);
                bizOpLogVo.setUdf2(method);
                bizOpLogVo.setUdf3(getServiceMthodDescription(point,"ServiceLog"));
                bizOpLogVoService.createBizOpLog(bizOpLogVo);
            } catch (Exception e) {
                logger.error("日志类异常");
                logger.error(e.getMessage());
            }
        }
    
        /**
         * 用户操作异常
         * @param jp
         * @param e
         * @throws Exception
         */
        @AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
        public void afterThrowing2Service(JoinPoint jp,Throwable e) throws Exception{
            logger.error("异常:"+jp.getTarget().getClass().getName()+"."+jp.getSignature().getName());
            logger.error(e.getMessage());
        }
    
        /**
         * 系统服务层操作
         * @param point
         */
        @AfterReturning("sysSecureServiceAspect()")
        public void doAfter2Sys(JoinPoint point){
            try {
                String actor ="";
                if(SecurityContextHolder.getContext().getUser()!=null){
                    actor = SecurityContextHolder.getContext().getUser().getLoginName();
                }
                String method = point.getSignature().getName();
                String entity = point.getTarget().getClass().getSimpleName();
                String args =  getAvailableArgs(point.getArgs());
                SecureOpLog secureOpLog = new SecureOpLog();
                secureOpLog.setActor(actor);
                secureOpLog.setEntityType(entity.replace("ServiceImpl",""));
                secureOpLog.setAction(methodType(method));
                secureOpLog.setUdf1(args.length()>200?args.substring(0,200):args);
                secureOpLog.setUdf2(method);
                secureOpLog.setUdf3(getServiceMthodDescription(point,"SysSecureServiceLog"));
                secureOpLogDao.insert(secureOpLog);
            } catch (Exception e) {
                logger.error("日志类异常");
                logger.error(e.getMessage());
            }
        }
    
        //在方法抛出异常是拦截
        @AfterThrowing(pointcut = "sysSecureServiceAspect()", throwing = "e")
        public void afterThrowing2Sys(JoinPoint jp,Throwable e) throws Exception{
            logger.error("异常:"+jp.getTarget().getClass().getName()+"."+jp.getSignature().getName());
            logger.error(e.getMessage());
        }
    
    
    
        private ActionType methodType(String method){
            method =  method.toLowerCase();
            if(method.contains("create")||method.contains("insert")||method.contains("save")){
                return ActionType.CREATE;
            }else if(method.contains("delete")){
                return ActionType.DELETE;
            }else if(method.contains("edit")||method.contains("update")){
                return ActionType.UPDATE;
            }else if(method.contains("frozen")){
                return ActionType.FROZEN;
            }else if(method.contains("unfrozen")) {
                return ActionType.UNFROZEN;
            }
            else {
                return ActionType.SEARCH;
            }
        }
    
        private String  getAvailableArgs(Object [] args){
           String  strArgs =  Arrays.toString(args);
            String []params= strArgs.split(",");
            String argsStr="";
            for (String arg:params){
                if(arg.contains("[")&&!arg.endsWith(">")){
                    argsStr = arg.substring(arg.lastIndexOf("["));
                }else if(!arg.contains("[")&&!arg.endsWith(">")){
                    argsStr+=","+arg;
                }
            }
            return argsStr;
        }
    
        private   String getServiceMthodDescription(JoinPoint joinPoint ,String which)
                throws Exception {
            String targetName = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            Object[] arguments = joinPoint.getArgs();
            Class targetClass = Class.forName(targetName);
            Method[] methods = targetClass.getMethods();
            String description = "";
            for (Method method : methods) {
                if (method.getName().equals(methodName)) {
                    Class[] clazzs = method.getParameterTypes();
                    if (clazzs.length == arguments.length) {
                        if(which.equals(ServiceAopType.ServiceLog.toString())) {
                            description = method.getAnnotation(ServiceLog.class).description();
                        }else if(which.equals(ServiceAopType.SysSecureServiceLog.toString())){
                            description = method.getAnnotation(SysSecureServiceLog.class).description();
                        }
                        break;
                    }
                }
            }
            return description;
        }
    }

    1.4在具体的方法上需要时添加链接点

        @Override
        @SysSecureServiceLog(description= "delete user")
        public int deleteUser(Long userId){
            int res = userDao.delete(userId);
            associateDao.deleteByAssoc(AssociateTable.ROLE_USER,userId);
            return res;
        }

    2方式二通过xml声明配置实现:

    2.1首先在xml配置如下:因为考虑到日志保存在操作异常或者事务回滚的情况下 操作日志不需要写入数据库,或者也需要回滚,故用了 配置的order顺序来解决。

    <!--添加操作日志-->
        <bean id = "logs" class="com.oasis.wyvern.res.service.base.logService.Aop2Log"/>
        <aop:config >
            <aop:aspect ref="logs" order="3">
                <!-- 定义切入点 -->
                <!-- aop包下的所有以Service结尾的类的方法 -->
                <aop:pointcut id="doMethod"
                              expression="(execution(* com.oasis.wyvern.res.service.biz..*Service.save*(..)) or
                                              execution(* com.oasis.wyvern.res.service.biz..*Service.create*(..)) or
                                              execution(* com.oasis.wyvern.res.service.biz..*Service.insert*(..)) or
                                              execution(* com.oasis.wyvern.res.service.biz..*Service.update*(..)) or
                                              execution(* com.oasis.wyvern.res.service.biz..*Service.change*(..)) or
                                              execution(* com.oasis.wyvern.res.service.biz..*Service.lock*(..)) or
                                              execution(* com.oasis.wyvern.res.service.biz..*Service.unLock*(..)) or
                                              execution(* com.oasis.wyvern.res.service.biz..*Service.reset*(..)) or
                                              execution(* com.oasis.wyvern.res.service.biz..*Service.delete*(..))
    
                                           )" />
                <aop:after-returning method="doAfter" pointcut-ref="doMethod"/>
            </aop:aspect>
        </aop:config>
        <!--异常时-->
        <aop:config>
            <aop:aspect ref="logs" order="1">
                <aop:pointcut id="throwinglog"
                              expression="(execution(* com.oasis.wyvern.res.service.biz..*Service.save*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.create*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.insert*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.update*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.change*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.lock*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.unLock*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.reset*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.delete*(..))
    
                )" />
                <aop:after-throwing pointcut-ref="throwinglog" throwing="e"  method="afterThrowing"/>
            </aop:aspect>
        </aop:config>
    
    
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
                <tx:method name="add*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
                <tx:method name="update*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
                <tx:method name="delete*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
                <tx:method name="*"/>
            </tx:attributes>
        </tx:advice>
        <!--事务回滚-->
        <aop:config>
            <aop:pointcut id="serviceMethods"
                          expression="(execution(* com.oasis.wyvern.res.service.biz..*Service.save*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.create*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.insert*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.update*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.change*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.lock*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.unLock*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.reset*(..)) or
                                            execution(* com.oasis.wyvern.res.service.biz..*Service.delete*(..))
    
                )"
            />
            <aop:advisor advice-ref="txAdvice"
                         pointcut-ref="serviceMethods" order="2"/>
        </aop:config>

    2.2包路径图,别把切入点的类添加到连接点扫描中:execution表达式可百度,根据业务需要配置不同的拦截规则。

    2.3切入点代码

    package com.oasis.wyvern.res.service.base;
    
    import com.oasis.wyvern.res.common.biz.enums.base.type.ActionType;
    import com.oasis.wyvern.res.common.biz.vo.record.oplog.BizOpLogVo;
    import com.oasis.wyvern.res.model.base.context.secure.SecurityContextHolder;
    import com.oasis.wyvern.res.service.base.record.oplog.BizOpLogService;
    import org.aspectj.lang.JoinPoint;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.Arrays;
    
    public class Aop2Log {
        private static final Logger logger = LoggerFactory.getLogger(Aop2Log.class);
        @Autowired
        private BizOpLogService bizOpLogVoService;
        public void doAfter(JoinPoint point){
            String actor ="";
            if(SecurityContextHolder.getContext().getUser()!=null){
                actor = SecurityContextHolder.getContext().getUser().getLoginName();
            }
            String method = point.getSignature().getName();
            String entity = point.getTarget().getClass().getSimpleName();
            String args =  getAvailableArgs(Arrays.toString(point.getArgs()));
            BizOpLogVo bizOpLogVo = new BizOpLogVo();
            bizOpLogVo.setActor(actor);
            bizOpLogVo.setEntityType(entity.replace("ServiceImpl",""));
            bizOpLogVo.setAction(methodType(method));
            bizOpLogVo.setUdf1(args.length()>200?args.substring(0,200):args);
            bizOpLogVo.setUdf2(method);
            bizOpLogVoService.createBizOpLog(bizOpLogVo);
        }
    
        //在方法抛出异常是拦截
        public void afterThrowing(JoinPoint jp,Throwable e) throws Exception{
            logger.error("异常:"+jp.getTarget().getClass().getName()+"."+jp.getSignature().getName());
            logger.error(e.getMessage());
        }
    
        private ActionType methodType(String method){
            method =  method.toLowerCase();
            if(method.contains("create")||method.contains("insert")||method.contains("save")){
                return ActionType.CREATE;
            }else if(method.contains("delete")){
                return ActionType.DELETE;
            }else if(method.contains("edit")||method.contains("update")){
                return ActionType.UPDATE;
            }else if(method.contains("frozen")){
                return ActionType.FROZEN;
            }else if(method.contains("unfrozen")) {
                return ActionType.UNFROZEN;
            }
            else {
                return ActionType.SEARCH;
            }
        }
    
        private String  getAvailableArgs(String args){
            String []params= args.split(",");
            String argsStr="";
            for (String arg:params){
                if(arg.contains("[")&&!arg.endsWith(">")){
                    argsStr = arg.substring(arg.lastIndexOf("["));
                }else if(!arg.contains("[")&&!arg.endsWith(">")){
                    argsStr+=","+arg;
                }
            }
            return argsStr;
        }
    }

    好了,到此为止两种方法完全介绍完整。

  • 相关阅读:
    设计模式学习笔记-观察者模式(转)
    VC++ 遍历文件夹
    VC++文件监控 ReadDirectoryChangesW
    Windows Socket五种I/O模型——代码全攻略(转)
    CentOS 6 安装RabbitMQ
    nginx tomcat负载配置
    Centos6 Nginx安装
    windows 安装MongoDB服务
    跟导师请教后写出的关于C#导出Excel,不导出隐藏列的方法
    linux 常用命令(四)——(centos7-centos6.8)Vim安装
  • 原文地址:https://www.cnblogs.com/likun10579/p/6023248.html
Copyright © 2020-2023  润新知