博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringMVC的Controller拦截日志配置
阅读量:6977 次
发布时间:2019-06-27

本文共 6511 字,大约阅读时间需要 21 分钟。

在项目中一直使用SpringMVC做Java后台服务,返回的基本都是JSON。

要求请求参数、返回结果都要打印到log里,方便追踪。
如果处理除了问题,也要返回显示错误的JSON。

如果不用AOP拦截,每个Controller方法都要写成类似如下的样子:

@RequestMapping(value = "/someUrl", produces = { "application/json;charset=UTF-8" })@ResponseBodypublic String someUrl(@ModelAttribute ReqForm reqParams) {    Logger.info(..., "someUrl request: "+JsonUtil.toJson(reqParams));    // form validation ...    try {        ResultObject result = someService.serviceMethod(reqParams);        Logger.info(..., "someUrl response: "+JsonUtil.toJson(result));        return JsonResult.success(result);    } catch (Exception e) {        Logger.error(..., "someUrl: "                + JsonUtil.toJson(reqParams) + " || " + ExceptionUtil.printStackTraceToString(e));        return JsonResult.fail();    }}

很烦,都是重复的东西。用上AOP就方便多了,加一个拦截类,加一点配置,就可以搞定所有。

首先,添加Maven依赖:

org.aspectj
aspectjweaver
1.8.0

然后,实现一个请求拦截处理类(Logger的方法被简化了)

import java.io.PrintWriter;import java.io.StringWriter;import java.lang.reflect.Method;import java.util.Enumeration;import java.util.HashMap;import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;import org.springframework.ui.Model;import org.springframework.ui.ModelMap;import org.springframework.validation.BindingResult;/** * 请求拦截处理类 *  *  */public class ControllerInterceptor implements MethodInterceptor {    @Override    public String invoke(MethodInvocation invocation) {        String result = "";        String paramsStr = "";        Object value = null;        Method md = invocation.getMethod();        try {            Object[] args = invocation.getArguments();            paramsStr = this.logRequest(args);            value = invocation.proceed();        } catch (Throwable e) {            if (e instanceof ServiceException) {                Logger.error(..., ((ServiceException) e).getAlarmId(), md                        .getDeclaringClass().getSimpleName()                        + "."                        + md.getName()                        + " || "                        + paramsStr                        + " || "                        + printStackTraceToString(e));            } else {                Logger.error(..., "some_alarm_id", md                        .getDeclaringClass().getSimpleName()                        + "."                        + md.getName()                        + " || "                        + paramsStr                        + " || "                        + printStackTraceToString(e));            }        }        if (value != null) {            result = value.toString();        } else {            result = JsonResult.SYSERROR;        }        this.logRequestResponse(md, paramsStr, result);        return result;    }    private String logRequest(Object[] args) {        if (args == null) {            return "";        }        // 请求参数日志信息        Map
params = new HashMap
(); int i = 1; for (Object arg : args) { if (!(arg instanceof BindingResult) && !(arg instanceof ModelMap) && !(arg instanceof Model)) { if (arg instanceof HttpServletRequest) { HttpServletRequest httpRequest = (HttpServletRequest) arg; Enumeration
enume = httpRequest.getParameterNames(); if (null != enume) { Map
hpMap = new HashMap
(); while (enume.hasMoreElements()) { Object element = enume.nextElement(); if (null != element) { String paramName = (String) element; String paramValue = httpRequest.getParameter(paramName); hpMap.put(paramName, paramValue); } } params.put("HttpServletRequest", hpMap); } } else { try { params.put("arg" + i, JsonUtil.toJson(arg)); i++; } catch (Throwable e) { Logger.warn(..., "CANNOT trasform to json string:" + arg.getClass().getName()); } } } } String paramsStr = JsonUtil.toJson(params); return paramsStr; } private void logRequestResponse(Method md, String paramsStr, String re) { Map
logMap = new HashMap
(); logMap.put("controller.method", md.getDeclaringClass().getSimpleName() + "." + md.getName()); logMap.put("logReq", paramsStr); logMap.put("logRes", re); Logger.info(..., logMap); } private String printStackTraceToString(Throwable e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); return sw.toString().replace("\n", " ").replace("\r", " ").replace("\t", " "); }}

这里用一个类实现了org.aopalliance.intercept.MethodInterceptor接口,实现invoke方法,达到对Controller方法的进入和返回拦截的效果。

注意要在适当的时机执行invocation.proceed()方法,并返回它的返回值。否则所有Controller方法都没返回了。

还有一点,由于我用的SpringMVC,controller方法的一些参数并不需要打印出来,比如BingdingResult ModelMap Model等等。

如果有HttpServletRequest传进来,也不能直接被JSON序列化,需要特殊处理一下。还有其他不能序列化的东西,直接略掉(代码中的try…catch)。

然后,配置下spring。

spring-mvc.xml文件的<beans>标签中加入aop相应的schema,并且添加刚才写的拦截类bean。

<beans>上主要添加xmlns:aopxsi:schemaLocation两端aop的配置。其他配置根据情况添加。

切面配置的含义是:在your.controller.package下面所有类所有public的,任何参数,任何返回类型的方法进行拦截。

这样的话,开头的代码就可以简化为:

@RequestMapping(value = "/someUrl", produces = { "application/json;charset=UTF-8" })@ResponseBodypublic String someUrl(@ModelAttribute ReqForm reqParams) {    // form validation ...    ResultObject result = someService.serviceMethod(reqParams);    return JsonResult.success(result);}

只管业务就可以了,代码清晰了很多。

最后,要注意在web.xml中springMVC的配置,类似于:

springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:/spring/spring-mvc.xml
1
springmvc
/*

注意跟业务的bean定义分离开。

采用这种方法,实现了对所有controller方法进行统一的日志记录。

包括进入记录:类名方法名,参数。返回记录:返回值。异常处理返回并记录StackTrace。
同时,使用一个简单的ServiceException可以做到统一扔给Interceptor进行处理。

转载地址:http://zfypl.baihongyu.com/

你可能感兴趣的文章
JNDI概述(转载)
查看>>
利用java反射机制 读取配置文件 实现动态类载入以及动态类型转换
查看>>
第 7 章 项目运作
查看>>
PYTHON黑帽编程1.5 使用WIRESHARK练习网络协议分析
查看>>
.NET平台开源项目速览(18)C#平台JSON实体类生成器JSON C# Class Generator
查看>>
C# 格式串(收藏)
查看>>
浅谈SQL Server中统计对于查询的影响
查看>>
WF4 Beta,RC版文章总结
查看>>
WPF 与Surface 2.0 SDK 亲密接触–LibraryContainer 篇
查看>>
C# 对应 Oracle 存储过程 的 SYS_REFCURSOR 应该 传入什么类型的参数?
查看>>
Unity3D移植到自己的Android程序
查看>>
【转】用示例说明索引数据块中出现热块的场景,并给出解决方案
查看>>
HDU 2034 人见人爱A-B
查看>>
【AngularJS】—— 12 独立作用域
查看>>
使用工作集(Working Set)整理项目
查看>>
MailMail、RegeX等程序的云端版
查看>>
[Erlang 0072] Erlang XML处理解决方案
查看>>
从C#到Objective-C,循序渐进学习苹果开发(7)--使用FMDB对Sqlite数据库进行操作
查看>>
mmap学习
查看>>
X3D中Profile如何翻译
查看>>