美文网首页springbootSpring Boot 核心技术SpringBoot极简教程 · Spring Boot
第八章:使用拦截器记录你的SpringBoot的请求日志

第八章:使用拦截器记录你的SpringBoot的请求日志

作者: 恒宇少年 | 来源:发表于2017-04-10 22:09 被阅读13553次

请求日志几乎是所有大型企业级项目的必要的模块,请求日志对于我们来说后期在项目运行上线一段时间用于排除异常、请求分流处理、限制流量等。请求日志一般都会记录请求参数、请求地址、请求状态(Status Code)、SessionId、请求方法方式(Method)、请求时间、客户端IP地址、请求返回内容、耗时等等。如果你得系统还有其他个性化的配置,也可以完成记录。

本章目标

通过SpringBoot整合与拦截器整合完成请求日志的记录,本章节日志记录使用SpringDataJPA与MySQL数据库记录。

构建项目

我们使用InteiiJ IDEA创建一个SpringBoot项目,预先依赖模块有Web、JPA、MySQL、Druid等。项目结构如下图1所示:

图1

配置数据源

我们直接从之前的项目中复制一个application.yml文件到/resource下,application.yml内容如下图2所示:

图2

创建数据表结构

我们把请求日志直接保存到本地的MySQL数据库内,下面我们先来创建一个请求日志表,结构如下图3所示:

图3

我们表结构内的字段比较多,数据结构创建完成后,接下来根据表结构创建实体并配置实体JPA,如下图4所示:

图4

可以看到上图4,我们对应数据库内的表名以及字段名创建实体映射、字段映射,根据实体我们创建一个实现SpringDataJPA接口JpaRepository的子接口,LoggerJPA,如下图5所示:

图5

JpaRepository接口包含了SpringDataJPA内的常用到的CRUD方法,后面章节我们会拿出来分支来专门讲解SpringDataJPA使用。

创建日志拦截器

我们上面的步骤有关请求日志的存储已经编写完成,那么我们接下来需要编写一个请求日志的拦截器,自定义SpringMVC拦截器需要实现HandlerIntercptor接口,并且实现内部的三个方法,如下图6所示拦截器代码详情:

图6

上面的三个方法在前面章节:第六章:如何在SpringBoot项目中使用拦截器已经讲过了,这里就不多做解释了,有需要的请去看下我的第六章讲解。
这里需要注意一点,我们在拦截器内无法通过SpringBean的方式注入LoggerJPA,我只能通过另外一种形式。

WebApplicationContextUtils

这个工具类可以通过HttpServletRequest请求对象的上下文(ServetCotext)获取Spring管理的Bean,具体代码如下图7所示:

图7

可以看到上图7创建了一个getDAO的方法,方法需要传入一个实体的类型,以及一个HttpServetRequest请求对象,通过WebApplicationContextUtils内部的getRequiredWebApplicationContext方法获取到BeanFactory(实体工厂类),从而通过工厂实体的getBean方法就可以拿到SpringDataJPA为我们管理的LoggerJPA持久化数据接口实例。

记录请求日志

我们处理日志请求时需要用到FastJson、HttpServet依赖,所以我们修改pom.xml配置文件加入FastJson开源组件以及HttpServlet的maven依赖,如下图8所示:

图8

接下来我们开始编写请求日志的创建,首先我们在preHandle方法内创建LoggerEntity实体,并记录一些必要参数后将实体写入到当前请求对象HttpServletRequest内,如下图9、图10所示:

图9 图10

可以看到我们上面记录了我们日志实体内的大部分参数,当用户发送请求时在进入SpringMVC的控制器之前会进入preHandle方法,然后记录下我们的请求日志内容,并将请求日志的实体写入到请求对象内,下面就会进入对应springMVC控制器方法的方法,在最后渲染视图即将返回前台的时候开始执行我们下面需要边写的afterCompletion方法,代码如下图11所示:

图11

我们在afterCompletion方法内记录了请求相应码、请求时间戳、请求返回值等。其中请求返回值我们是在哪里设置的呢?那么我们接下来开始编写测试请求控制器IndexController。你就会明白了。

编写测试控制器

我们在controller包下创建一个IndexController并且添加@RestController注解来标明IndexController是一个restful风格的控制器。如下图12所示:

图12

我们在IndexControll控制器内简单添加了一个测试方法login,可以看到我们在拦截器内的疑问得到的解释,LOGGER_RETURN是从我们的请求方法传入到LoggerInterceptor拦截器内afterCompletion方法中的。

配置拦截器

上述我们的代码基本已经编写完成,不要忘记最重要的一步,我们需要将LoggerInterceptor拦截器添加到我们的SpringBoot项目内,让SpringBoot项目可以识别拦截。我们需要创建一个LoggerConfguration配置类,如下图13所示:

图13

我们的项目编码已经完成,下面我们来尝试运行项目看看效果。

初尝试运行项目

运行日志如下图14所示,如果没有出现异常证明项目运行成功了,如果出现异常请根据对应异常检查错误。

图14

我们项目已经运行成功,那么我们接下来测试我们的请求日志是否可以记录成功,我们先来访问地址:http://127.0.0.1:8080/index/login?name=yuqiyu(简书插入链接无法带参数,请复制到地址栏访问),效果如下图15所示:

图15

可以看到我们成功的返回了在IndexControll的login方法配置的json信息,那么我的请求日志是否已经记录到数据库呢?我们先来看下InteiiJ IDEA工具的控制器是否已经打印了SQL,如下图16所示:

图16

可以看到已经正常打印了,我们打开表查看下数据,如下图17所示:

图17

我们已经将请求日志成功的写入到数据库。

总结

上述内容就是本章的全部讲解,本章主要讲解了SpringBoot项目如何配置日志拦截器,将用户的请求参数写入到数据库内,使用SpringDataJPA以及Druid连接池完成数据的持久化操作。当前如果要在企业级大型项目使用,还请定期清理请求日志。如果你有记录错误日志发送邮件的需求,可以通过判断HttpServertReponse对象的statusCode来完成,具体的错误堆栈信息记录,需要我们后续章节讲解。

本章内容已经更新到码云

SpringBoot配套源码地址:https://gitee.com/hengboy/spring-boot-chapter

SpringCloud配套源码地址:https://gitee.com/hengboy/spring-cloud-chapter

SpringBoot相关系列文章请访问:目录:SpringBoot学习目录

QueryDSL相关系列文章请访问:QueryDSL通用查询框架学习目录

SpringDataJPA相关系列文章请访问:目录:SpringDataJPA学习目录

SpringBoot相关文章请访问:目录:SpringBoot学习目录,感谢阅读!

欢迎加入QQ技术交流群,共同进步。

QQ技术交流群

相关文章

网友评论

  • 揍妲己的小鲁班:楼主,你好!怎么获取响应的内容,并把响应也记录下来呢
  • f264b7674876:不知道我这个情况是不是个例:SpringBoot2.0.4+MySQL8.0.12下,运行会出现o.hibernate.id.enhanced.TableStructure : could not read a hi value的问题;需要在实体类里面将注解@GeneratedValue改成@GeneratedValue(strategy = GenerationType.IDENTITY)即可正常运行
  • 1fffae5528fe:WebApplicationContextUtils.getRequiredWebApplicationContext() 这个方法不能获取到BeanFactory,为什么
    恒宇少年:@原_点 使用我文章的方式进行获取applicationContext
  • jkian:这个logger拦截器日志记录在Springmvc可以用吗
    jkian:@恒宇少年 谢了,我已经配置好了。
    恒宇少年:@并亲揍了你一顿jkian 可以,这个是拦截器实现的
  • 56def38f3137:写的很好,辛苦了。
  • b2efe7751b24:跳转成功了,可是写入数据库出错了
    ERROR 1374 --- [nio-8080-exec-2] o.s.web.servlet.HandlerExecutionChain : HandlerInterceptor.afterCompletion threw exception...
    b2efe7751b24:完全看不出问题在哪啊,连接数据库没错啊
  • 3e6d06efe4cb:返回参数是怎么获取的?loggerEntity.setReturnData(JSON.toJSONString(request.getAttribute(LoggerUtils.LOGGER_RETURN),
    SerializerFeature.DisableCircularReferenceDetect,
    SerializerFeature.WriteMapNullValue));

    我没有看见往request 里面设置值
    ad78609cbbe7:在controller里给request设置attribute了,出了controller进了afterCompletion方法当然能get到了啊
  • 会飞的蜗牛F:在拦截器内无法通过SpringBean的方式注入LoggerJPA//拦截器里面是可以进行bean注入的,将拦截器配置类修改为
    @Bean
    LoggerInterceptor loggerInterceptor() {
    return new LoggerInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(loggerInterceptor());
    }
    3e6d06efe4cb:返回参数是怎么获取的?loggerEntity.setReturnData(JSON.toJSONString(request.getAttribute(LoggerUtils.LOGGER_RETURN),
    SerializerFeature.DisableCircularReferenceDetect,
    SerializerFeature.WriteMapNullValue));

    我没有看见往request 里面设置值
    恒宇少年:@gwfeng 拦截器配置可以使用ioc以及new实例
  • 孔垂云:如果请求是以request body的方式,json参数,如何完整记录下来。如果出现异常,如果完整的记录下请求参数及请求url?
  • Spring_java:很不错
  • 8497a0273fdf:大佬又个问题想问下。LoggerInterceptor 这个类里面使用@Autowired 获取loggerJPA 会出现空指针。如果使用@Autowired ,需要配置其他的地方么?
    激萌咖啡:@恒宇少年 我的意思是 “”LoggerInterceptor 这个类里面使用@Autowired 获取loggerJPA 会出现空指针“ 他这个问题应该是 LoggerInterceptor 没有交给spring管理 因此 @autowired 是无效的 出现空指针的吧
    恒宇少年:@激萌区链块 拦截器配置可以有两种,一个是new,一个是spring注入
    激萌咖啡:@compent 加上试试
  • 奥特青年:请问post请求应该怎么拿参数呢?
    恒宇少年:@H_68b0 一个请求内的数据,有效期是当前请求。
    奥特青年:@恒宇少年 我这边试了是拿不到的,并且网上有说post请求放在body里面的数据只能取出一次,然后就没了,也就是说若preHandle里面取出,传到controller再去读的话流就关闭了,需要在传到controller之前再写进去一次。对此我拿不准,不知你怎么看。
    恒宇少年:@H_68b0 一样
  • 紫萱草_:感谢作者的分享
    恒宇少年:@安静de橘子 感谢阅读,继续努力。

本文标题:第八章:使用拦截器记录你的SpringBoot的请求日志

本文链接:https://www.haomeiwen.com/subject/qvcdattx.html