通过拦截器拦截访问url获取接口中数据进行日志保存

xml配置
web.xml中配置加载路径 参考spring.xml加载文章,进行配置加载
因为项目是maven引用加载在.pom中加载所以拦截器在底层,父类不能调用子类的方法,新写spring.xml文件拦截器进行加载(如下图)

>
>

通过拦截器拦截访问url获取接口中数据进行日志保存_第1张图片

>

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);
    }
}
}

你可能感兴趣的:(拦截器)