给项目添加用户行为日志
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) { Mapmap=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