spring mvc 使用拦截器interceptor和自定义Log类实现持久层记录日志

本文介绍了如何在Spring MVC中利用拦截器Interceptor来记录日志,详细步骤包括配置拦截器、创建自定义日志注解类,并在Controller层使用该注解。虽然目前的拦截器无法捕获所有异常,但提供了基本的日志记录功能。作者开源了一个包含权限管理、搜索引擎、工作流程等模块的OA办公系统,感兴趣者可关注其QQ群和代码仓库。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先spring记录日志我所知道的有两种,一种是通过AOP,另一种是通过拦截器interceptor,我这次选择的是拦截器interceptor:
1.spring-mvc.xml文件中配置拦截器,

 <!-- 装配拦截器 -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**/*.do"/>
            <bean class="com.zhph.sys.interceptors.LogInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

新建一个拦截器,

package com.zhph.sys.interceptors;

import com.zhph.base.utils.Utils;
import com.zhph.sys.entity.LogEntity;
import com.zhph.sys.entity.UserEntity;
import com.zhph.sys.service.LogService;
import com.zhph.sys.utils.JsonUtil;
import com.zhph.sys.utils.UserUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.Map;

/**
 *日志
 * Created by Administrator on 2017/3/16.
 */
public class LogInterceptor implements HandlerInterceptor {//,AfterReturningAdvice
    @Autowired
    LogService logService;
   private Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 请求处理之前进行调用
     * @param request
     * @param httpServletResponse
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse httpServletResponse, Object handler) throws Exception {

        return true;
    }

    /**
     * 当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,
     * 所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。
     * @param request
     * @param httpServletResponse
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse httpServletResponse, Object handler, ModelAndView modelAndView) throws Exception {

    }

    /**
     * 获取Ip地址
     * @param request
     * @return
     */
    public  String getIpAddr(HttpServletRequest request)  {
        String ip  =  request.getHeader( " x-forwarded-for " );
        if (ip  ==   null   ||  ip.length()  ==   0   ||   " unknown " .equalsIgnoreCase(ip))  {
            ip  =  request.getHeader( " Proxy-Client-IP " );
        }
        if (ip  ==   null   ||  ip.length()  ==   0   ||   " unknown " .equalsIgnoreCase(ip))  {
            ip  =  request.getHeader( " WL-Proxy-Client-IP " );
        }
        if (ip  ==   null   ||  ip.length()  ==   0   ||   " unknown " .equalsIgnoreCase(ip))  {
            ip  =  request.getRemoteAddr();
        }
        return  ip;
    }
    /**
     * 将ErrorStack转化为String.
     */
    public static String getStackTraceAsString(Throwable e) {
        if (e == null){
            return "";
        }
        StringWriter stringWriter = new StringWriter();
        e.printStackTrace(new PrintWriter(stringWriter));
        return stringWriter.toString();
    }


    /**
     * 该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。
     * 这个方法的主要作用是用于进行资源清理工作的
     * @param request
     * @param response
     * @param handler
     * @param e
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) throws Exception {
        try {
            HandlerMethod handler2=(HandlerMethod) handler;
            Log log = handler2.getMethod().getAnnotation(Log.class);
            if(null !=log){
                //获取操作系统等信息
                StringBuffer sb=new StringBuffer();
                sb.append("操作系统名称:"+System.getProperty("os.name"));//操作系统名称
                sb.append("操作系统构架"+System.getProperty("os.arch"));//操作系统构架
                sb.append("操作系统版本"+System.getProperty("os.version"));//操作系统版本
                LogEntity logEntity=new LogEntity();
                UserEntity loginUser = UserUtils.getLoginUser();
                Map<String, String[]> map = request.getParameterMap();
                String jsonData = JsonUtil.getJsonByObj(map);
                  logEntity.setId(Utils.uuid());
                logEntity.setCreateBy(loginUser.getId());
                logEntity.setCreateDate(new Date());
                logEntity.setType(log.operation());
                logEntity.setRequestUrl(request.getRequestURI());
                logEntity.setRemoteAddr(getIpAddr(request));
                logEntity.setTitle(log.title());
                logEntity.setUserAgent(sb.toString());
                //logEntity.setRemoteAddr(request.getRemoteAddr());
                logEntity.setMethod(request.getMethod());
                logEntity.setParams(jsonData);
                //如果controller报错,则记录异常错误
                if(e != null){
                    logEntity.setException(getStackTraceAsString(e));
                }
                try {
                    logService.insert(logEntity);
                     logger.info("log create a new log ======",logEntity);
                }catch (Exception e1){
                    logger.info("fail to save operation log ", e1);
                }
            }
        }catch (Exception el){
            el.printStackTrace();
        }

    }

}

3.再新建一个自定义日志注解类,

package com.zhph.sys.interceptors;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    /**
     * 删除
     */
    String OPERA_TYPE_DEL="0";
    /**
     * 新增/修改
     */
    String OPERA_TYPE_EDIT="1";
    /**
     * 查看
     */
    String OPERA_TYPE_SELECT="2";

    public String operation() default Log.OPERA_TYPE_EDIT;

    public String title() ;


    //public String ext() default "";

}

4,现在就可以在controller层使用日志注解类了,
这里写图片描述

总结,现在这个拦截器,还有不足之处就是,如果方法报异常,能捕获到try catch不能捕获的异常

由于平时很少写博客,写的很差,请多见谅。

这里推荐下我的开源项目:
hxyFrame是一个OA办公系统,采用流行的框架springMvc+spring+mybatis+shiro+ehcache开发,还集成了权限管理(菜单权限、数据权限),完善的代码生成器,solr全文搜索引擎,activiti工作流程引擎,cas单点登陆等功能,后期还会考虑改造成Dubbo微服务化,做到模块的相对独立,使用更加灵活,努力做到快速开发OA办公系统。 感兴趣可以Watch、Start持续关注项目最新状态,加入QQ群:210315502
oschina仓库:https://git.oschina.net/huangxianyuan/hxyFrame.git
github仓库:https://github.com/huangxianyuan/hxyFrame.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值