10.从零搭建WebApi接口开发框架-记录请求日志log

在开发中,需要记录接口的请求日志及返回日志,便于回溯原因。这里面请求日志为什么要单独拿出来讲,是因为当前是以post body的方式提交接口请求,body是以stream的方式接收,如果在拦截器中获取该body内容后,真实请求中将捕获不到该参数了,因此需要引入BodyReaderHttpServletRequestWrapper 来实现接口的请求日志记录。

pom.xml增加依赖

<dependency>
    <groupId>org.jodd</groupId>
    <artifactId>jodd-core</artifactId>
    <version>3.9</version>
</dependency>

用于获取当前request中的stream信息

BodyReaderHttpServletRequestWrapper 重新包装request

public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {

    /**
     * 定义字节流
     */
    private final byte[] body;

    /**
     * 把请求的http包装一下
     *
     * @param request request
     * @throws IOException IO异常
     */
    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)
            throws IOException {
        super(request);
        // body = StreamUtil.readBytes(request.getReader(), JoddDefault.encoding);
        // 因为http协议默认传输的编码就是iso-8859-1,如果使用utf-8转码乱码的话,可以尝试使用iso-8859-1
        body = StreamUtil.readBytes(request.getReader(), "UTF-8");
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() throws IOException {
                return bais.read();
            }
        };
    }
}

HttpServletRequestReplacedFilter 新建过滤器替换request的body

public class HttpServletRequestReplacedFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //Do nothing
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if (request instanceof HttpServletRequest) {
            requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
        }
        chain.doFilter(requestWrapper, response);
    }

    @Override
    public void destroy() {
        //Do nothing
    }

}

LogInterceptor利用拦截器来记录日志

public class LogInterceptor implements HandlerInterceptor {
    /**
     * 定义日志
     */
    private static Logger logger = LoggerFactory.getLogger("operationLog");

    /**
     * 记录操作日志
     *
     * @param request  request
     * @param response response
     * @param handler  handler
     * @return 处理是否成功
     * @throws Exception 异常
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //校验权限
        String path = request.getServletPath();
        String contentType = request.getContentType();
        if (contentType != null && contentType.equals("application/json")) {
            // 只有json请求才记录日志,上传文件的不记录
            //参数
            String parameters = StringUtil.getBodyString(request.getReader());
            User user = TokenUtil.getToken(request);
            logOperation(path, parameters, user);
        }
        return true;
    }

    /**
     * 记录文本日志
     *
     * @param path       路径
     * @param parameters 参数值
     * @param user       user
     */
    public void logOperation(String path, String parameters, User user) {
        String log = "";
        if (user == null) {
            user = new User();
        }
        log = "[OPERALOG-操作日志]" + "-[" + user.getUsername() + "]" + "-[" + getSystemTime() + "]-" + "[INFO]-" + "-" + parameters;
        logger.info(log);
    }

    public static String getSystemTime() {
        String strTime = "";
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        strTime = df.format(new Date());
        return strTime;
    }

    /**
     * @param request      request
     * @param response     response
     * @param handler      handler
     * @param modelAndView modelAndView
     * @throws Exception 异常
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    /**
     * @param request  request
     * @param response response
     * @param handler  handler
     * @param ex       异常
     * @throws Exception 异常
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

这里块的代码非常简单,获取当前请求的路径及参数,记录下来,同时如果header中有authorization的话,再取当前的用户信息,这一块可以根据实际需要来修改。

LogConfig 加入需要记录日志的url

@Configuration
public class LogConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //校验是否登录拦截器
        registry.addInterceptor(new LogInterceptor())
                //消息相关
                .addPathPatterns("/news/*")
                .addPathPatterns("/checkLogin");
        super.addInterceptors(registry);
    }
}

这一块和控制权限一样,增加一个InterceptorRegistry,并设置需要拦截的url串

请求的日志结果如下所示:


日志结果.png

如果没有BodyReaderHttpServletRequestWrapper对request的重新包装,直接获取body的参数,后续将会报错。

源码下载

本例子详细源码

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容