使用aop(切面)实现日志请求参数日志持久化操作

需求:

 针对不同的action 方法中有修改删除的敏感操作的接口,需要记录对应的参数,ip地址,员工的id名称等信息,方便追责定位问题

分析:

  1.使用注解将对应方法打上标记

  2.每次调用完该方法的时候才开始记录日志

  3.需要记录用户请求的ip地址,参数,用户名称等等

①定义注解


import java.lang.annotation.*;

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodLog {

	//对标记接口的补充说明
	String content() default ""; 

	String operType() default "0";
	
	int operLevel() default 0; //操作等级
}

②定义切面

 


/**
 * 操作日志切面配置
 */
@Aspect
@Component("operateLogAspect")
public class OperateLogAspect {
    private Logger logger = LoggerFactory.getLogger(getClass());
    
    //注入持久化该日志信息的service
    @Autowired
    private OperateService operateService;
    //注入根据request获取登录用户信息的service
    @Autowired
    private SysUserService sysUserService;

    @After(value = "execution (* com.web.controller..*.*(..))") //指定切点,使用after 让该切面在方法执行完成后切入
    public void after(JoinPoint point) throws Throwable {
        try {
            // 拦截的action方法上面的标记是否包含 MethodLog 的注解
            Map<String, Object> map = getMthodRemark(point);
            if (map.isEmpty()) {
                // 没有MethodLog 注解标记 ,无此配置,直接返回
                return;
            }
            //获取requestBody 参数信息,过滤掉 ServletRequest 和 ServletResponse 类型的参数
            Object object = Arrays.stream(point.getArgs()).filter(t ->!( t instanceof ServletRequest) && !( t instanceof ServletResponse) ).collect(Collectors.toList());
            //请求参数转成jsonString 
            String requestBody = JSONObject.toJSONString(object);

            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            if (null == request) {
                logger.info("获取request失败.直接返回");
                return;
            }
            //根据request获取用户ID
            Long userId = this.getSysUserId(request);
            if (userId == null) {
                logger.error("未从request中获取到员工信息,直接返回");
                return;
            }
           //获取用户数使用客户端信息
            String userAgent = request.getHeader("user-agent");
            //根据用户ID调用service获取用户信息 
            SystemUser myUser = sysUserService.queryOne(userId);
            //获取该方法的名称
            String requestMethod = request.getMethod();
            StringBuffer params = new StringBuffer();
            // action方法名称
            String actionName = point.getSignature().getName();
            String pms = requestBody;
           
            // 构建操作日志对象
            OperateLog log = new OperateLog();
            log.setUserId(Integer.parseInt("" + myUser.getUserId()));
            log.setUserName(myUser.getUserName());
            log.setOperContent(null == map.get("content") ? "" : map.get("content").toString());
            log.setOperLevel(null == map.get("operLevel") ? 0 : Integer.parseInt(map.get("operLevel").toString()));
            log.setOpParams(pms);
            log.setOperUserAgent(userAgent);
            log.setOpIp(getIpAdrress(request));
            log.setOpSysType(null == map.get("operType") ? 0 : Integer.parseInt(map.get("operType").toString()));
            log.setOperMethod(actionName);
            log.setOpDisplayMode("");
            operateLogService.insertOperateLog(log);
        }catch (JSONException je){
            logger.error("记录操作日志参数异常,json转型异常:{}", je.getMessage());
        } catch (Exception e) {
            logger.error("记录操作日志出错:{}", StackTraceLogUtil.getStackTraceAsString(e));
        }
        return;
    }

    /**
     * 计算两天是否同一天
     *
     * @param day1
     * @param day2
     * @return
     */
    public boolean isSameDay(Date day1, Date day2) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String ds1 = sdf.format(day1);
        String ds2 = sdf.format(day2);
        return ds1.equals(ds2) ? true : false;
    }

    /**
     * @param request
     * @return 当前登陆员工Id
     * @desc 获取当前登陆用户Id
     */
    protected Long getSysUserId(HttpServletRequest request) {
        Object object = request.getAttribute(CommonConstant.UID);

        if (object == null)
            object = request.getHeader(CommonConstant.UID);
        return Optional.ofNullable(object).isPresent() ? Long.valueOf(String.valueOf(object)) : null;
    }

    /**
     * 是否相差time
     *
     * @param d1
     * @param d2
     * @param time
     * @return
     */
    public boolean isDifferTime(Date d1, Date d2, int time) {
        if ((d2.getTime() - d1.getTime()) / 1000 / 60 > time)
            return true;
        else
            return false;
    }

    /**
     * 获取Ip地址
     * @param request
     * @return
     */
    private static String getIpAdrress(HttpServletRequest request) {
        String Xip = request.getHeader("X-Real-IP");
        String XFor = request.getHeader("X-Forwarded-For");
        if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
            //多次反向代理后会有多个ip值,第一个ip才是真实ip
            int index = XFor.indexOf(",");
            if(index != -1){
                return XFor.substring(0,index);
            }else{
                return XFor;
            }
        }
        XFor = Xip;
        if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
            return XFor;
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("Proxy-Client-IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("HTTP_CLIENT_IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getRemoteAddr();
        }
        return XFor;
    }

    // 获取方法的中文备注____用于记录用户的操作日志描述
    @SuppressWarnings("rawtypes")
    public static Map<String, Object> getMthodRemark(JoinPoint joinPoint)
            throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Map<String, Object> map = Maps.newHashMap();
        Class targetClass = Class.forName(targetName);
        Method[] method = targetClass.getMethods();
        String methode = "";
        for (Method m : method) {
            if (m.getName().equals(methodName)) {
                Class[] tmpCs = m.getParameterTypes();
                if (tmpCs.length == arguments.length) {
                    MethodLog methodCache = m.getAnnotation(MethodLog.class);
                    if (methodCache != null) {
                        methode = methodCache.content();
                        String operType = methodCache.operType();
                        int level = methodCache.operLevel();
                        map.put("content", methode);
                        map.put("operLevel", level);
                        map.put("operType", operType);
                    }
                    break;
                }
            }
        }
        return map;
    }

}

 具体是持久化方法之类的我就不贴了,这里只是提供一个思路,如果有问题的欢迎指正,谢谢

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章