基于springMVC拦截器实现操作日志统计

1.spring配置文件配置。 

   <!-- 拦截器 -->
	<mvc:interceptors>
		<!-- 日志拦截器 -->
		<bean class="cn.jeeweb.modules.common.interceptor.LogInterceptor" >
		      <property name="openAccessLog" value="${openAccessLog}" />
		</bean>
		<mvc:interceptor>
			<mvc:mapping path="/**" />
			<!-- 需排除拦截的地址 -->
			<mvc:exclude-mapping path="/static/**" />
			<!-- 需排除拦截的地址 -->
			<mvc:exclude-mapping path="/upload/**" />
			<bean class="cn.jeeweb.core.interceptor.EncodingInterceptor" />
		</mvc:interceptor>
	 
	</mvc:interceptors>

2.控制类

package cn.jeeweb.modules.common.interceptor;

import java.text.SimpleDateFormat;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import cn.jeeweb.core.utils.DateUtils;
import cn.jeeweb.modules.sys.utils.LogUtils;

/**
 * 
 * All rights Reserved, Designed By www.zhisuaninfo.com
 * 
 * @title: LogInterceptor.java
 * @package cn.jeeweb.modules.common.interceptor
 * @description: 访问日志拦截器
 * @author: gulf
 * @date: 2018年1月11日 下午12:17:54
 * @version V1.0
 * @copyright: 2017 www.zhisuaninfo.com Inc. All rights reserved.
 *
 */
public class LogInterceptor implements HandlerInterceptor {

	private Boolean openAccessLog = Boolean.FALSE;

	 

	public void setOpenAccessLog(Boolean openAccessLog) {
		this.openAccessLog = openAccessLog;
	}

	private static final ThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<Long>("ThreadLocal StartTime");
	/**
	 * 日志对象
	 */
	protected Logger logger = LoggerFactory.getLogger(getClass());

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		if (logger.isDebugEnabled()) {
			long beginTime = System.currentTimeMillis();// 1、开始时间
			startTimeThreadLocal.set(beginTime); // 线程绑定变量(该数据只有当前请求的线程可见)
			logger.debug("开始计时: {}  URI: {}", new SimpleDateFormat("hh:mm:ss.SSS").format(beginTime),
					request.getRequestURI());
		}
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		if (modelAndView != null) {
			logger.info("ViewName: " + modelAndView.getViewName());
		}
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		if (openAccessLog) {
			// 保存日志
			LogUtils.saveLog(request, handler, ex, null);
			// 打印JVM信息。
			if (logger.isDebugEnabled()) {
				long beginTime = startTimeThreadLocal.get();// 得到线程绑定的局部变量(开始时间)
				long endTime = System.currentTimeMillis(); // 2、结束时间
//				logger.debug("计时结束:{}  耗时:{}  URI: {}  最大内存: {}m  已分配内存: {}m  已分配内存中的剩余空间: {}m  最大可用内存: {}m",
//						new SimpleDateFormat("hh:mm:ss.SSS").format(endTime),
//						DateUtils.formatDateTime(endTime - beginTime), request.getRequestURI(),
//						Runtime.getRuntime().maxMemory() / 1024 / 1024,
//						Runtime.getRuntime().totalMemory() / 1024 / 1024,
//						Runtime.getRuntime().freeMemory() / 1024 / 1024,
//						(Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory()
//								+ Runtime.getRuntime().freeMemory()) / 1024 / 1024);
			}
		}

	}

}

3.工具类

package cn.jeeweb.modules.sys.utils;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.method.HandlerMethod;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import cn.jeeweb.core.utils.CacheUtils;
import cn.jeeweb.core.utils.Exceptions;
import cn.jeeweb.core.utils.IpUtils;
import cn.jeeweb.core.utils.SpringContextHolder;
import cn.jeeweb.core.utils.StringUtils;
import cn.jeeweb.modules.sys.entity.Log;
import cn.jeeweb.modules.sys.entity.Menu;
import cn.jeeweb.modules.sys.entity.User;
import cn.jeeweb.modules.sys.service.ILogService;
import cn.jeeweb.modules.sys.service.IMenuService;
import cn.jeeweb.modules.sys.tags.SysFunctions;

public class LogUtils {

	public static final String CACHE_MENU_NAME_PATH_MAP = "menuNamePathMap";
	private static ILogService logService = SpringContextHolder.getBean(ILogService.class);
	private static IMenuService menuService = SpringContextHolder.getBean(IMenuService.class);

	/**
	 * 保存日志
	 */
	public static void saveLog(HttpServletRequest request, String title) {
		saveLog(request, null, null, title, null);
	}

	/**
	 * 保存日志
	 */
	public static void saveLog(HttpServletRequest request, String title, String content) {
		saveLog(request, null, null, title, content);
	}

	public static void saveLog(HttpServletRequest request, Object handler, Exception ex, String title) {
		saveLog(request, handler, ex, title, null);
	}

	/**
	 * 保存日志
	 */
	public static void saveLog(HttpServletRequest request, Object handler, Exception ex, String title, String content) {
		User user = UserUtils.getUser();
		if (user != null && user.getId() != null) {
			Log log = new Log();
			log.setTitle(title);
			log.setType(ex == null ? Log.TYPE_ACCESS : Log.TYPE_EXCEPTION);
			log.setRemoteAddr(IpUtils.getIpAddr(request));
			log.setUserAgent(request.getHeader("user-agent"));
			log.setRequestUri(request.getRequestURI());
			log.setParams(request.getParameterMap());
			log.setMethod(request.getMethod());
			log.setContent(content);
			// 异步保存日志
			new SaveLogThread(log, handler, ex).start();
		}
	}

	/**
	 * 保存日志线程
	 */
	public static class SaveLogThread extends Thread {

		private Log log;
		private Object handler;
		private Exception ex;

		public SaveLogThread(Log log, Object handler, Exception ex) {
			super(SaveLogThread.class.getSimpleName());
			this.log = log;
			this.handler = handler;
			this.ex = ex;
		}

		@Override
		public void run() {
			// 获取日志标题
			if (StringUtils.isBlank(log.getTitle())) {
				String permission = "";
				if (handler instanceof HandlerMethod) {
					Method m = ((HandlerMethod) handler).getMethod();
					RequiresPermissions rp = m.getAnnotation(RequiresPermissions.class);
					permission = (rp != null ? StringUtils.join(rp.value(), ",") : "");
				}
				log.setTitle(getMenuNamePath(log.getRequestUri(), permission));
			}
			// 如果有异常,设置异常信息
			log.setException(Exceptions.getStackTraceAsString(ex));
			// 如果无标题并无异常日志,则不保存信息
			if (StringUtils.isEmpty(log.getTitle()) && StringUtils.isEmpty(log.getException())) {
				return;
			}
			// 保存日志信息
			logService.insert(log);
		}
	}

	/**
	 * 获取菜单名称路径(如:系统设置-机构用户-用户管理-编辑)
	 */
	public static String getMenuNamePath(String requestUri, String permission) {
		String url = StringUtils.substringAfter(requestUri, SysFunctions.getAdminUrlPrefix() + "/");
		@SuppressWarnings("unchecked")
		Map<String, String> menuMap = (Map<String, String>) CacheUtils.get(CACHE_MENU_NAME_PATH_MAP);
		if (menuMap == null) {
			menuMap = Maps.newHashMap();
			List<Menu> menuList = menuService.selectList(new EntityWrapper<Menu>());
			for (Menu menu : menuList) {
				// 获取菜单名称路径(如:系统设置-机构用户-用户管理-编辑)
				String namePath = "";
				if (menu.getParentIds() != null) {
					List<String> namePathList = Lists.newArrayList();
					for (String id : StringUtils.split(menu.getParentIds(), "/")) {
						/*
						 * if (Menu.getRootId().equals(id)){ continue; // 过滤跟节点
						 * }
						 */
						for (Menu m : menuList) {
							if (m.getId().equals(id)) {
								namePathList.add(m.getName());
								break;
							}
						}
					}
					namePathList.add(menu.getName());
					namePath = StringUtils.join(namePathList, "-");
				}
				// 设置菜单名称路径
				if (StringUtils.isNotBlank(menu.getUrl())) {
					menuMap.put(menu.getUrl(), namePath);
				} else if (StringUtils.isNotBlank(menu.getPermission())) {
					for (String p : StringUtils.split(menu.getPermission())) {
						menuMap.put(p, namePath);
					}
				}

			}
			CacheUtils.put(CACHE_MENU_NAME_PATH_MAP, menuMap);
		}
		String menuNamePath = menuMap.get(url);
		if (menuNamePath == null) {
			for (String p : StringUtils.split(permission)) {
				menuNamePath = menuMap.get(p);
				if (StringUtils.isNotBlank(menuNamePath)) {
					break;
				}
			}
			if (menuNamePath == null) {
				return "";
			}
		}
		return menuNamePath;
	}
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码匠的流水账

聊聊spring cloud的EurekaServerInitializerConfiguration

本文主要研究一下spring cloud的EurekaServerInitializerConfiguration

15820
来自专栏码匠的流水账

聊聊resilience4j的bulkhead

resilience4j-bulkhead-0.13.0-sources.jar!/io/github/resilience4j/bulkhead/Bulkhe...

21310
来自专栏24K纯开源

RegQueryValueEx正确使用方法

      项目中需要读取注册表中的HKEY_CLASSES_ROOT主键下一个子键的值,看了看MSDN的说明,有RegOpenKeyEx和RegQueryVa...

29280
来自专栏技术小黑屋

读懂 Android 中的代码混淆

在Android开发工作中,我们都或多或少接触过代码混淆。比如我们想要集成某个SDK,往往需要做一些排除混淆的操作。

15620
来自专栏码匠的流水账

聊聊spring cloud gateway的PreserveHostHeaderGatewayFilter

本文主要研究下spring cloud gateway的PreserveHostHeaderGatewayFilter

14520
来自专栏算法+

声音变调算法PitchShift(模拟汤姆猫) 附完整C++算法实现代码

上周看到一个变调算法,挺有意思的,原本计划尝试用来润色TTS合成效果的。 实测感觉还需要进一步改进,待有空再思考改进方案。 算法细节原文,移步链接: http:...

633100
来自专栏Java与Android技术栈

Transformer 在RxJava中的使用

Transformer,顾名思义是转换器的意思。早在 RxJava1.x 版本就有了Observable.Transformer、Single.Transfor...

95820
来自专栏码匠的流水账

聊聊pg jdbc的queryTimeout及next方法

本文主要介绍一下pg jdbc statement的queryTimeout及resultSet的next方法

38810
来自专栏非典型技术宅

iOS实践:一步步实现星级评分1. 创建星星2. 优化3. 灵异事件

18740
来自专栏函数式编程语言及工具

Akka(8): 分布式运算:Remoting-远程查找式

  Akka是一种消息驱动运算模式,它实现跨JVM程序运算的方式是通过能跨JVM的消息系统来调动分布在不同JVM上ActorSystem中的Actor进行运算,...

44590

扫码关注云+社区

领取腾讯云代金券