xml配置
web.xml中配置加载路径 参考spring.xml加载文章,进行配置加载
因为项目是maven引用加载在.pom中加载所以拦截器在底层,父类不能调用子类的方法,新写spring.xml文件拦截器进行加载(如下图)
>
>
>
HandlerInterceptor概述
在SpringMVC 中定义一个Interceptor是比较非常简单,主要有两种方式: 第一种:实现HandlerInterceptor 接口,或者是继承实现了HandlerInterceptor 接口的类,例如HandlerInterceptorAdapter; 第二种:实现Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类。 现在主要结合一个例子说一下第一种方式:实现HandlerInterceptor接口。
HandlerInterceptor接口主要定义了三个方法:
1. boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handle)方法:该方法将在请求处理之前进行调用,只有该方法返回true,才会继续执行后续的Interceptor和Controller,当返回值为true 时就会继续调用下一个Interceptor的preHandle 方法,如果已经是最后一个Interceptor的时候就会是调用当前请求的Controller方法; 2.void postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)方法:该方法将在请求处理之后,DispatcherServlet进行视图返回渲染之前进行调用,可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。 3.void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)方法:该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。用于进行资源清理。
>
方法详情
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } public void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } public void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { }
分别实现预处理、后处理(调用了Service并返回ModelAndView,但未进行页面渲染)、返回处理(已经渲染了页面)
在preHandle中,可以进行编码、安全控制等处理;
在postHandle中,有机会修改ModelAndView;
在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。
>
具体实现
package com.qxwljs.app.origin.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.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import com.qxwljs.app.origin.utils.DateUtils; import com.qxwljs.app.origin.utils.LogUtils; /** * origin门户登陆权限验证拦截器 */ public class OriginLoginInterceptor extends HandlerInterceptorAdapter { /** * 日志对象 */ protected Logger logger = LoggerFactory.getLogger(getClass()); private static final ThreadLocal
startTimeThreadLocal = new NamedThreadLocal ("ThreadLocal StartTime"); @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 { // 保存日志 try { long beginTime = startTimeThreadLocal.get();//得到线程绑定的局部变量(开始时间) long endTime = System.currentTimeMillis(); //2、结束时间 Long timer = endTime - beginTime;//计算耗时 request.setAttribute("timer", timer); LogUtils.saveLog(request, handler, ex, null);//调用保存日志方法(方法在公共方法中) } catch (Exception e) { e.printStackTrace(); } // 打印JVM信息。 if (logger.isDebugEnabled()){ long beginTime = startTimeThreadLocal.get();//得到线程绑定的局部变量(开始时间) long endTime = System.currentTimeMillis(); //2、结束时间 Object[] obj = new Object[10]; obj[0] = new SimpleDateFormat("hh:mm:ss.SSS").format(endTime); obj[1] = DateUtils.formatDateTime(endTime - beginTime); obj[2] = request.getRequestURI(); obj[3] = Runtime.getRuntime().maxMemory()/1024/1024; obj[4] = Runtime.getRuntime().totalMemory()/1024/1024; obj[5] = Runtime.getRuntime().freeMemory()/1024/1024; obj[6] = (Runtime.getRuntime().maxMemory()-Runtime.getRuntime().totalMemory()+Runtime.getRuntime().freeMemory())/1024/1024; logger.debug("计时结束:{} 耗时:{} URI: {} 最大内存: {}m 已分配内存: {}m 已分配内存中的剩余空间: {}m 最大可用内存: {}m",obj); //删除线程变量中的数据,防止内存泄漏 startTimeThreadLocal.remove(); } } }
>
保存日志方法
package com.qxwljs.app.origin.utils; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import javax.servlet.http.HttpServletRequest; import org.springframework.web.method.HandlerMethod; import com.qxwljs.app.origin.annotation.Logger; import com.qxwljs.app.origin.core.sys.model.Log; import com.qxwljs.app.origin.core.sys.model.User; import com.qxwljs.app.origin.core.sys.service.impl.LogService; import com.qxwljs.framework.context.spring.SpringContextHolder; import eu.bitwalker.useragentutils.Browser; import eu.bitwalker.useragentutils.UserAgent; public class LogUtils { //工具类中的service注入不能用注解方式 所以用spring方式载入 private static LogService logService = SpringContextHolder.getBean("logService"); /** * 保存日志 * @throws UnsupportedEncodingException */ public static void saveLog(HttpServletRequest request, Object handler, Exception ex, String title) throws UnsupportedEncodingException{ User user = UserUtils.getSession(User.SESSION_KEY); if (user != null && user.getId() != null){ Log log = new Log(); log.setTitle(title); log.setType(ex == null ? Log.TYPE_ACCESS : Log.TYPE_EXCEPTION);// 类型(1:接入日志;2:错误日志) log.setTimer(Long.parseLong(request.getAttribute("timer")+""));// 耗时 log.setRemoteaddr(StringUtils.getRemoteAddr(request));// 操作用户的IP地址 log.setUseragent(request.getHeader("user-agent"));// 操作用户代理信息 log.setRequesturi(request.getRequestURI());// 操作的URI log.setParams(request.getParameterMap());// 操作提交的数据 log.setMethod(request.getMethod()); // 操作的方式 UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent")); String browser =userAgent.getBrowser().getName();//获取浏览器名称 String windows =userAgent.getOperatingSystem().getName();//获取操作系统 log.setBrowsername(browser);// 浏览器名称 log.setWindows(windows);//操作系统名称 log.setCity(IpAddress.getAddresses("ip="+StringUtils.getRemoteAddr(request), "utf-8"));//ip所在市 User u = UserUtils.getSession(User.SESSION_KEY); if (u != null) { log.setCreateby(u.getId().toString()); log.setUpdateby(u.getId().toString()); } log.setCreatedate(System.currentTimeMillis()); log.setUpdatedate(System.currentTimeMillis()); // 异步保存日志 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 title = null ;
if (handler instanceof HandlerMethod){
Method m = ((HandlerMethod)handler).getMethod();
Logger clazz = m.getDeclaringClass().getAnnotation(Logger.class);//类注解
Logger method = m.getAnnotation(Logger.class);//方法注解
if(clazz != null && method != null) {
String[] s = new String[2];
s[0] = clazz.name();
s[1] = method.name();
title = StringUtils.join(s, "-");
}else {
title = "";
}
}
log.setTitle(title);
}
// 如果有异常,设置异常信息
log.setException(Exceptions.getStackTraceAsString(ex));
// 如果无标题并无异常日志,则不保存信息
if (StringUtils.isBlank(log.getTitle()) && StringUtils.isBlank(log.getException())){
return;
}
// 保存日志信息
logService.save(log);
}
}
}