打赏
Fork me on GitHub

系统审计日志开发

基于注解的Aop日志记录

项目安全送检前需要做个审计日志,做完后在这记录下实现过程

1.Log实体类

package com.ideal.manage.guest.bean.log;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;

/**
 * @apiNote 日志
 * @author lcoil
 * @since 2020-05-24
 */
@Data
public class Log {

    private Long id;

    private String content;

    private String description;

    private String ip;

    private String module;

    private String username;

    private Date createAt;

    private Date updateAt;

    private Integer able;
    
}
View Code

2.定义注解

package com.ideal.manage.guest.annotation;

import java.lang.annotation.*;

/**
 * @author lcoil
 * @create 2020-05-24
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    /**模块*/
    String module() default "";

    /**描述*/
    String description() default "";
}

3.定义切面

package com.ideal.manage.guest.aop;


import com.ideal.manage.guest.annotation.Log;
import com.ideal.manage.guest.service.log.LogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

/**
 * 日志切面处理类
 *
 * @author lcoil
 * @create 2020-05-24
 */
@Aspect
@Component
public class LogAspect {

    @Autowired
    private LogService logService;

    /**
     * 日志切入点
     */
    @Pointcut("@annotation(com.ideal.manage.guest.annotation.Log)")
    public void logPointCut(){}

    /**
     * 前置通知
     * @param joinPoint
     */
    @Before(value ="execute()")
    public void Before(JoinPoint joinPoint) {
         /**
         * 解析Log注解
         */
        String methodName = joinPoint.getSignature().getName();
        Method method = currentMethod(joinPoint,methodName);
        Log log = method.getAnnotation(Log.class);
        logService.put(joinPoint,methodName,log.module(),log.description());
    }
    
     /**
     * 环绕通知
     * @param proceedingJoinPoint
     * @return
     */
    @Around(value ="execute()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("环绕通知开始");
        try {
            System.out.println("执行方法:" + proceedingJoinPoint.getSignature().getName());
            
            MethodSignature signature =(MethodSignature) proceedingJoinPoint.getSignature();
            Action action = signature.getMethod().getAnnotation(Action.class);
            
            System.out.println("菜单="+action.description());
            
            Object object =  proceedingJoinPoint.proceed();
            System.out.println("环绕通知结束,方法返回:" + object);
            return object;
        } catch (Throwable e) {
            System.out.println("执行方法异常:" + e.getClass().getName());
            return null;
        }
    }

    /**
     * 后置通知
     * @param joinPoint
     */
    @After(value ="execute()")
    public void After(JoinPoint joinPoint) {
        System.out.println("执行方法之后");
    }
    
    /**
     * 后置通知,带返回值
     * @param obj
     */
    @AfterReturning(pointcut = "execute()",returning = "obj")
    public void doAfter(Object obj){
       System.out.println("执行方法之后获取返回值:"+obj);
    }
    
    /**
     * 后置通知,异常时执行
     * @param e
     */
    @AfterThrowing(throwing = "e",pointcut = "execute()")
    public void doAfterThrowing(Exception e) {
        System.out.println("执行方法异常:"+e.getClass().getName());
    }
    
    /**
     * 获取当前执行的方法
     *
     * @param joinPoint  连接点
     * @param methodName 方法名称
     * @return 方法
     */
    private Method currentMethod(JoinPoint joinPoint, String methodName) {
        /**
         * 获取目标类的所有方法,找到当前要执行的方法
         */
        Method[] methods = joinPoint.getTarget().getClass().getMethods();
        Method resultMethod = null;
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                resultMethod = method;
                break;
            }
        }
        return resultMethod;
    }

}
LogAspect

4.业务处理:LogService

package com.ideal.manage.guest.service.log;

import com.alibaba.fastjson.JSONObject;


import com.ideal.manage.guest.bean.DTO.PageDto;
import com.ideal.manage.guest.bean.log.Log;

import com.ideal.manage.guest.config.shiro.MyShiroRealm;
import com.ideal.manage.guest.repository.framework.MySpecification;
import com.ideal.manage.guest.repository.framework.SpecificationOperator;
import com.ideal.manage.guest.repository.log.LogRepository;
import com.ideal.manage.guest.util.Const;
import com.ideal.manage.guest.util.HttpRequests;
import com.ideal.manage.guest.util.IPUtils;

/*import org.apache.ibatis.javassist.*;
import org.apache.ibatis.javassist.bytecode.CodeAttribute;
import org.apache.ibatis.javassist.bytecode.LocalVariableAttribute;
import org.apache.ibatis.javassist.bytecode.MethodInfo;*/
import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 *  服务实现类
 *
 * @author lcoil
 * @since 2020-05-24
 */
@Service
public class LogService{

    private static final String LOG_CONTENT = "[类名]:%s,[方法]:%s,[参数]:%s,[IP]:%s";

    private String username;

    @Autowired
    private LogRepository logRepository;

    public String initUsername(String username) {
        if(!StringUtils.isEmpty(username)){
            this.username = username;
        }
        return this.username;
    }


    public void put(JoinPoint joinPoint, String methodName, String module, String description) {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            Log log = new Log();
            //username = ((JwtClient) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
            // 获取当前登录用户
            MyShiroRealm.ShiroUser shiroUser = (MyShiroRealm.ShiroUser) SecurityUtils.getSubject().getPrincipal();
            username = shiroUser.getUsername();
            if (StringUtils.isEmpty(username)) {
                username = Const.USERNAME_IN_CONTEXT != null ? Const.USERNAME_IN_CONTEXT : "未知用户";
            }

            String ip = IPUtils.getIpAddr(request);
            log.setUsername(username);
            log.setModule(module);
            log.setDescription(description);
            log.setIp(ip);
            log.setContent(operateContent(joinPoint, methodName, ip, request));
            log.setAble(1);
            logRepository.save(log);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*public Page<Log> page(LogRequest request, Page<Log> page) {
        if(request == null){
            request = new LogRequest();
        }
        request.setIsDeleted(Config.ABLE_CONFIG.ABLE);
        List<Log> logs = baseMapper.page(request,page);
        page.setRecords(logs);
        return page;
    }*/

    /**
     * 查询所有日志
     * @param pageNum
     * @param request
     * @return
     */
    public PageDto findAll(int pageNum, HttpServletRequest request) {
        Sort sort = new Sort(Sort.Direction.DESC, "updateAt");
        List<SpecificationOperator> operators = HttpRequests.getParametersStartingWith(request, "Q_");
        //增加删除标识的过滤
        SpecificationOperator isValid = new SpecificationOperator("able", "1", "EQ");
        operators.add(isValid);
        MySpecification<Log> mySpecifications = new MySpecification<>(operators);
        Pageable pageable = new PageRequest(pageNum, 10, sort);
        Page<Log> page = logRepository.findAll(mySpecifications, pageable);
        //设置PageDto
        List<Log> parameters = page.getContent();
        long total = page.getTotalElements();
        PageDto pageDto = new PageDto();
        pageDto.setRows(parameters);
        pageDto.setTotal(total);
        return pageDto;
    }


    public String operateContent(JoinPoint joinPoint, String methodName, String ip, HttpServletRequest request) throws ClassNotFoundException, NotFoundException {
        String className = joinPoint.getTarget().getClass().getName();
        Object[] params = joinPoint.getArgs();
        String classType = joinPoint.getTarget().getClass().getName();
        Class<?> clazz = Class.forName(classType);
        String clazzName = clazz.getName();
        Map<String,Object > nameAndArgs = getFieldsName(this.getClass(), clazzName, methodName,params);
        StringBuffer bf = new StringBuffer();
        if (!CollectionUtils.isEmpty(nameAndArgs)){
            Iterator it = nameAndArgs.entrySet().iterator();
            while (it.hasNext()){
                Map.Entry entry = (Map.Entry) it.next();
                String key = (String) entry.getKey();
                String value = JSONObject.toJSONString(entry.getValue());
                bf.append(key).append("=");
                bf.append(value).append("&");
            }
        }
        if (StringUtils.isEmpty(bf.toString())){
            bf.append(request.getQueryString());
        }
        return String.format(LOG_CONTENT, className, methodName, bf.toString(), ip);
    }

    private Map<String,Object> getFieldsName(Class cls, String clazzName, String methodName, Object[] args) throws NotFoundException {
        Map<String,Object > map=new HashMap<String,Object>();

        ClassPool pool = ClassPool.getDefault();
        ClassClassPath classPath = new ClassClassPath(cls);
        pool.insertClassPath(classPath);

        CtClass cc = pool.get(clazzName);
        CtMethod cm = cc.getDeclaredMethod(methodName);
        MethodInfo methodInfo = cm.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        if (attr == null) {
            return map;
        }
        int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
        for (int i = 0; i < cm.getParameterTypes().length; i++){
            map.put( attr.variableName(i + pos),args[i]);//paramNames即参数名
        }
        return map;
    }
}
LogService

5.使用注解在需要的地方记录日志

@Log(module = "设备管理",description = "添加设备")
    public Integer saveEquipment(Equipment equipment) {
        equipment.setAble(1);
        Equipment resultEquipment = equipmentRepository.save(equipment);
        if(resultEquipment == null){
            return StateUtil.RESULT_FAILED;
        }
        return StateUtil.RESULT_SUCCESS;
    }

 

posted @ 2020-05-30 20:47  l-coil  阅读(448)  评论(0编辑  收藏  举报