基于springMVC拦截器实现操作日志统计
时间:2022-04-27
本文章向大家介绍基于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;
}
}
- 周末娱乐:讲真,这才是我所说黑客的定义!
- 数据访问函数库的使用方法(一)——添加修改数据
- 数据访问函数库的使用方法(二)—— 获取记录集和使用事务的方法
- “数据访问函数库”(DataAccessLibrary for .net2.0 )源代码下载 09.06.15更新
- 数据访问函数库 for ado.net2.0
- 【问底】静行:FastJSON实现详解
- 分页解决方案 —— GridView + QuickPager + QuickPager_SQL + DataAccessLibrary + 数据库
- 使用接口来统一控件的取值、赋值和初始化
- 【自然框架】之通用权限的Demo(二):添加人员、添加账户、添加角色里面的账户以及列表的权限验证
- 我自己写的一个分页控件(源码和演示代码)PostBack分页版 for vs2003、SQL Server
- 分页控件之分页算法 —— for SQL Server 版。
- 【问底】王帅:深入PHP内核(一)——弱类型变量原理探究
- 一次对个人服务器入侵事件的调查
- BlackHat议题解析:Windows程序的数字签名校验“漏洞”
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 在Laravel中使用GuzzleHttp调用第三方服务的API接口代码
- thinkphp5使html5实现动态跳转的例子
- php 自定义函数实现将数据 以excel 表格形式导出示例
- 解决tp5在nginx下修改配置访问的问题
- 在PHP中实现使用Guzzle执行POST和GET请求
- c 语言函数指针之回调函数
- 解决thinkphp5未定义变量会抛出异常,页面错误,请稍后再试的问题
- php和js实现根据子网掩码和ip计算子网功能示例
- php ZipArchive实现多文件打包下载实例
- PHP 代码简洁之道(小结)
- Thinkphp 在api开发中异常返回依然是html的解决方式
- Laravel 连接(Join)示例
- 解决Laravel自定义类引入和命名空间的问题
- 详解Laravel服务容器的绑定与解析
- 修改Laravel自带的认证系统的User类的命名空间的步骤