使用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;
    }

}

 具體是持久化方法之類的我就不貼了,這裏只是提供一個思路,如果有問題的歡迎指正,謝謝

 

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