beat365体育登陆网址

网站访问日志记录的两种方式

网站访问日志记录的两种方式

网站访问记录日志能方便的帮助我们开发人员准确的定位到问题,能帮助我们进行错误重现,快速的解决问题,节省时间。这里我将项目中用到的两种记录方式简单总结一下,希望能帮助有需要的人

本文代码需要对Spring拦截器、AOP有一定的了解,可以先百度了解下Spring拦截器、AOP的概念及用途

一、使用Spring拦截器来记录

首先创建拦截器LoggerFilter,继承HandlerInterceptorAdapter类

package com.os.common.intercepter;

import com.os.core.utils.web.ObjectUtils;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.web.servlet.ModelAndView;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.net.InetAddress;

import java.net.UnknownHostException;

import java.util.Arrays;

import java.util.Enumeration;

/**

* 访问日志

*

* @author Peng

*/

public class LoggerFilter extends HandlerInterceptorAdapter {

private static Logger logger = LoggerFactory.getLogger(LoggerFilter.class);

public LoggerFilter() {

}

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

super.afterCompletion(request, response, handler, ex);

}

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

super.postHandle(request, response, handler, modelAndView);

}

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

//获取用户登录ip

String ip = this.getIpAddr(request);

String path = request.getContextPath() + request.getServletPath();

StringBuilder params = new StringBuilder();

String key;

String[] values;

Enumeration parameterNames = request.getParameterNames();

while (parameterNames.hasMoreElements()) {

key = (String) parameterNames.nextElement();

values = request.getParameterValues(key);

params.append(key).append("=").append(Arrays.toString(values)).append("&");

}

if (params.length() > 0) {

params.deleteCharAt(params.length() - 1);

}

logger.info("访问者信息:ip地址=" + ip + ",访问地址=" + path + ",参数:(" + params.toString().replaceAll("[\\[\\]]", "") + ")");

return true;

}

/**

* 获取请求IP地址

*

* @param request request请求

* @return ip地址

*/

private String getIpAddr(HttpServletRequest request) {

String ipAddress;

ipAddress = request.getHeader("x-forwarded-for");

if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {

ipAddress = request.getHeader("Proxy-Client-IP");

}

if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {

ipAddress = request.getHeader("WL-Proxy-Client-IP");

}

if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {

ipAddress = request.getRemoteAddr();

if (ipAddress.equals("127.0.0.1")) {

InetAddress inet = null;

try {

inet = InetAddress.getLocalHost();

} catch (UnknownHostException var4) {

var4.printStackTrace();

}

ipAddress = ObjectUtils.isNotNull(inet) ? inet.getHostAddress() : "";

}

}

if (ipAddress != null && ipAddress.length() > 15 && ipAddress.indexOf(",") > 0) {

ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));

}

return ipAddress;

}

}

HandlerInterceptorAdapter中afterCompletion、postHandle、preHandle这三个方法就不介绍作用了,直接百度java拦截器就行了

现在将LoggerFilter添加到springmvc配置中

本文代码配置方法采用的是javaconfig方式,先贴出代码

/**

* 拦截器配置

*/

@Override

public void addInterceptors(InterceptorRegistry registry) {

//日志记录拦截器

registry.addInterceptor(new LoggerFilter())

// 拦截请求

.addPathPatterns("/**/*")

// 剔除静态文件访问

.excludePathPatterns("/static/**/*");

super.addInterceptors(registry);

}

这样就OK了

xml方式配置

class="com.os.common.intercepter.LoggerFilter"/>

第一种方式就介绍完了,需要注意的是拦截器配置顺序,如果只是记录日志的话,建议将代码写在最上面,保证拦截器一定执行

二、使用Spring AOP来记录

因为项目只需记录能访问进方法的日志,所以对不能访问的日志就不需要记录

项目采用注解的方式来记录日志,就是说如果只有controller中方法使用了注解才会记录

所以先创建自定义注解Log

/**

* 自定义日志注解

*

* @author Peng

*/

@Documented

@Inherited

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Log {

}

然后创建LogAspect切面

package com.os.common.aspect;

import com.os.core.utils.json.FastJsonUtils;

import com.os.core.utils.web.ObjectUtils;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.reflect.MethodSignature;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

import org.springframework.stereotype.Component;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.context.request.RequestContextHolder;

import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

import java.lang.reflect.Method;

import java.net.InetAddress;

import java.net.UnknownHostException;

import java.util.*;

/**

* 日志aop切面

*

* @author Peng

*/

@Configuration

// 开启aop 相当于

@EnableAspectJAutoProxy

// 切面

@Aspect

// 把普通pojo实例化到spring容器中,相当于配置文件中的

@Component

public class LogAspect {

/**

* 日志输出

*/

private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);

/**

* 日志记录AOP

* 使用 @Around环绕通知,切点使用@annotation(xxxxx)进行定义

* 即 使用@Log自定义注解的方法进入此方法

*/

@Around("@annotation(com.os.common.aspect.Log)")

public Object aroundCacheAble(ProceedingJoinPoint joinPoint) throws Throwable {

try {

long startTime = System.currentTimeMillis();

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

String method = request.getMethod();

String uri = request.getRequestURI();

String ip = this.getIpAddr(request);

StringBuilder params = new StringBuilder();

String key;

String[] values;

Enumeration parameterNames = request.getParameterNames();

while (parameterNames.hasMoreElements()) {

key = (String) parameterNames.nextElement();

values = request.getParameterValues(key);

params.append(key).append("=").append(Arrays.toString(values)).append("&");

}

if (params.length() > 0) {

params.deleteCharAt(params.length() - 1);

}

UUID uuid = UUID.randomUUID();

String id = uuid.toString().replaceAll("-", "");

// 获取token

logger.info("↓↓↓↓↓↓↓↓↓ id:" + id + ",访问地址=" + uri + ",ip地址=" + ip + ",参数:(" + params.toString().replaceAll("[\\[\\]]", "") + "),提交方式:" + method);

// 环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的

Object result = joinPoint.proceed();

logger.info("返回数据" + FastJsonUtils.toJSONString(result));

return result;

} catch (Exception e) {

// 异常捕获

// 获取类型、方法名

String className = joinPoint.getTarget().getClass().getSimpleName();

String methodName = joinPoint.getSignature().getName();

String errInfo = className + "." + methodName + "--error";

// 异常日志输出

LoggerFactory.getLogger(joinPoint.getTarget().getClass()).error(errInfo, e);

if (isJson(joinPoint)) {

// 返回错误json

Map json = new HashMap<>(4);

json.put("message", "这是json错误页");

return json;

} else {

// 返回错误页面

return "pages/error";

}

}

}

/**

* 获取请求IP地址

*

* @param request request请求

* @return ip地址

*/

private String getIpAddr(HttpServletRequest request) {

String ipAddress;

ipAddress = request.getHeader("x-forwarded-for");

if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {

ipAddress = request.getHeader("Proxy-Client-IP");

}

if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {

ipAddress = request.getHeader("WL-Proxy-Client-IP");

}

if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {

ipAddress = request.getRemoteAddr();

if (ipAddress.equals("127.0.0.1")) {

InetAddress inet = null;

try {

inet = InetAddress.getLocalHost();

} catch (UnknownHostException var4) {

var4.printStackTrace();

}

ipAddress = ObjectUtils.isNotNull(inet) ? inet.getHostAddress() : "";

}

}

if (ipAddress != null && ipAddress.length() > 15 && ipAddress.indexOf(",") > 0) {

ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));

}

return ipAddress;

}

/**

* 判断是否是ajax返回

*

* @param joinPoint 连接点

* @return true ajax请求 false 页面请求

*/

private Boolean isJson(ProceedingJoinPoint joinPoint) {

Class classTarget = joinPoint.getTarget().getClass();

Class[] par = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();

try {

// 带@ResponseBody注册的方法为ajax方法,所以判断是否带@ResponseBody即可

Method objMethod = classTarget.getMethod(joinPoint.getSignature().getName(), par);

ResponseBody annotation = objMethod.getAnnotation(ResponseBody.class);

if (annotation != null) {

return true;

}

} catch (NoSuchMethodException e) {

e.printStackTrace();

}

return false;

}

}

至此,两种方式就总结完了,本人倾向于第二种,可以使用aop环绕通知方法统计出代码耗时等,当然拦截器也可以做出这种效果就是麻烦些。