给项目添加用户行为日志
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 MapconverMap( 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