给项目添加用户行为日志


1.场景描述

         项目启动后经常需要去记录用户在项目中的浏览轨迹,收集这些数据去进行用户行为分析。。。。

2.实现方式:

      通过aop+自定义注解实现用户接口调用记录

3.java 代码:

  a:创建自定义注解

package com.along.outboundmanage.aoplog;

import java.lang.annotation.*;

/**
 * 定义系统日志注解
 * @author why
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserLog {
    String value() default "";
}

 b:实现注解方法,通过aop切面获取用户请求数据

package com.along.outboundmanage.aoplog;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.along.outboundmanage.model.OutboundSession;
import com.along.outboundmanage.model.OutboundUserLog;
import com.along.outboundmanage.service.UserLogService;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 系统日志切面
 * @author why
 */
@Aspect  // 使用@Aspect注解声明一个切面
@Component
public class UserLogAspect {

    @Autowired
    private UserLogService userLogService;

    /**
     * 这里我们使用注解的形式
     * 通过注解指定需要拦截的package,需要拦截的class 以及 method
     * @annotation 里填写自定义注解接口路径
     *
     * 切点表达式:   execution(...)
     */
    @Pointcut("@annotation(com.along.outboundmanage.aoplog.UserLog)")
    public void logPointCut() {}

    /**
     * 环绕通知 @Around  , 当然也可以使用 @Before (前置通知)  @After (后置通知)
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        Object result = point.proceed();
        long time = System.currentTimeMillis() - beginTime;
        try {
            saveLog(point, time);
        } catch (Exception e) {
        }
        return result;
    }

    /**
     * 保存日志
     * @param joinPoint
     * @param time
     */
    private void saveLog(ProceedingJoinPoint joinPoint, long time) {
        UserLog sysLogBO = new UserLog();
        try{
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            sysLogBO.setRunTime(time);
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            sysLogBO.setCreateTime(dateFormat.format(new Date()));
            //获取用户ip地址
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                    .getRequest();
            sysLogBO.setIp(IpAdrressUtil.getIpAdrress(request));
            UserLog sysLog = method.getAnnotation(UserLog.class);
            if(sysLog != null){
                //注解上的描述
                sysLogBO.setOperation(sysLog.value());
            }
//获取session里的值 HttpSession session = request.getSession(); MySession mySession = (MySession)session.getAttribute("user"); sysLogBO.setUserId(mySession.getUserId()); sysLogBO.setUserName(mySession.getUserName()); sysLogBO.setRoleId(mySession.getRoleId()); sysLogBO.setAreaId(mySession.getAreaId()); sysLogBO.setAreaName(mySession.getAreaName()); //请求的 类名、方法名 String className = joinPoint.getTarget().getClass().getName(); String methodName = signature.getName(); sysLogBO.setMethodName(className+":"+methodName); //请求的参数 Object[] args = joinPoint.getArgs(); sysLogBO.setParams(JSONObject.toJSONString( converMap(args))); }catch (Exception e){ System.out.println("保存用户日志出错......"); sysLogBO.setErrorDesc(e.getMessage()); }finally { try { // System.out.println(sysLogBO.toString());
//存贮日志。。。 userLogService.insertUserLog(sysLogBO); }catch (Exception e){ System.out.println("保存用户日志出错......"+e.toString()); } } } public Map converMap( Object[] param) { Map rtnMap = new HashMap(); if (param == null ){ return rtnMap; } for (int i = 0; i < param.length; i++) { rtnMap.put(i+"",param[i].toString()); } return rtnMap; } }

c:使用示例

    @UserLog("用户登陆")
    @ResponseBody
    @RequestMapping(value = "logVal",produces = {"application/json;charset=UTF-8"})
    public Result logVal(@RequestBody OutboundUser user, HttpServletRequest request, HttpServletResponse response) {
        Map map=new HashMap<>();
        HttpSession session = request.getSession();
        return ResultGenerator.genSuccessResult(session.getAttribute("user"));

    }

 d:辅助类

package com.along.outboundmanage.aoplog;

import javax.servlet.http.HttpServletRequest;

/**
 * 获取用户真实的ip地址
 * @param request
 * @return
 */
public class IpAdrressUtil {

	public static String getIpAdrress(HttpServletRequest request) {
		String ip = null;

		//X-Forwarded-For:Squid 服务代理
		String ipAddresses = request.getHeader("X-Forwarded-For");
		String unknown = "unknown";
		if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
			//Proxy-Client-IP:apache 服务代理
			ipAddresses = request.getHeader("Proxy-Client-IP");
		}

		if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
			//WL-Proxy-Client-IP:weblogic 服务代理
			ipAddresses = request.getHeader("WL-Proxy-Client-IP");
		}

		if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
			//HTTP_CLIENT_IP:有些代理服务器
			ipAddresses = request.getHeader("HTTP_CLIENT_IP");
		}

		if (ipAddresses == null || ipAddresses.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
			//X-Real-IP:nginx服务代理
			ipAddresses = request.getHeader("X-Real-IP");
		}

		//有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
		if (ipAddresses != null && ipAddresses.length() != 0) {
			ip = ipAddresses.split(",")[0];
		}

		//还是不能获取到,最后再通过request.getRemoteAddr();获取
		if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ipAddresses)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}


}
import java.io.Serializable;
import java.util.Date;

public class UserLog implements Serializable {
	private Integer id;
	private Integer userId;
	private String userName;
	private String operation;
	private Long runTime;
	private String methodName;
	private String params;
	private String ip;
	private String createTime;
	private String errorDesc;
	//用户地域信息
	private Integer roleId;
	private Integer areaId;
	private String areaName;
}

public class MySession {
	//用户信息
	private int userId;
	private String userName;
	private String trueName;
	private String card;
	//用户地域信息
	private int areaId;
	private String areaName;
	private int parId;
	private int type;
	private int level;
	//用户角色信息
	private int roleId;
	private String roleName;

}
session