Spring MVC记录传入请求

1. 简介

在本教程中,我们将研究如何使用Spring MVC记录传入的请求。

2. 示例应用程序

让我们首先看一下我们的示例应用程序。

@RestController
public class ContactController {

    @PostMapping("/contact/{name}")
    public String contact(@PathVariable("name") String name, @RequestBody String details) {
        return "Contact details received for: " + name;
    }
}

我们有一个简单的 REST 控制器,其中包含单个端点 -/contact/{name}。在接下来的示例中,我们将针对此终结点发出请求。

3. 自定义实现

现在,我们将探索一些自定义实现来记录传入的 HTTP 请求。

3.1. 使用处理程序拦截器

HandlerInterceptor类为我们提供了在请求处理之前和之后运行的钩子。因此,我们将使用这些方法来记录请求数据:

@Slf4j
@Component
public class CustomRequestLoggingInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        StringBuffer requestURL = request.getRequestURL();
        log.info("preHandle => Request URL: {}", requestURL);
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        int status = response.getStatus();
        log.info("afterCompletion => Response Status: {}", status);
    }
}

我们的CustomRequestLoggingInterceptor类扩展了 HandlerInterceptorAdapter,它是一个实现HandlerInterceptor的抽象类。请注意,preHandle将在请求处理之前运行,afterCompletion将在请求处理完成后运行。

现在我们有了HandlerInterceptor,我们必须使用WebMvcConfigurerbean 注册它:

@Component
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CustomRequestLoggingInterceptor());
    }
}

当应用程序收到请求时,我们的CustomRequestLoggingInterceptor类也会被调用:

INFO 27115 --- [nio-8081-exec-1] .j.s.m.r.CustomRequestLoggingInterceptor : preHandle => Request URL: http://localhost:8081/contact/John
INFO 27115 --- [nio-8081-exec-1] .j.s.m.r.CustomRequestLoggingInterceptor : afterCompletion => Response Status: 200

3.2. 使用过滤器

过滤器在 servlet 之前和之后运行,因此它适用于记录请求。在我们的例子中,servlet 是 Spring MVC 的DispatcherServlet,它处理所有传入的请求。

@Slf4j
@Component
public class CustomRequestLoggingFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
      throws IOException, ServletException {
        final HttpServletRequest currentRequest = (HttpServletRequest) servletRequest;
        final HttpServletResponse currentResponse = (HttpServletResponse) servletResponse;

        StringBuffer requestURL = currentRequest.getRequestURL();
        log.info("Request URL: {}", requestURL);
        try {
            chain.doFilter(currentRequest, servletResponse);
        } finally {
            int status = currentResponse.getStatus();
            log.info("Response status: {}", status);
        }
    }
}

在这里,实际的请求处理发生在chain.doFilter调用中。换句话说,DispatcherServlet获取请求并选择适当的控制器方法。因此,我们在过滤器中编写此调用之前和之后的日志语句。

此外,我们可以使用FilterRegistrationBean 配置过滤器的注册属性,尽管我们在这里选择了默认值。

当应用程序为请求提供服务时,将写入以下日志:

INFO 5835 --- [nio-8081-exec-1] c.j.s.m.r.CustomRequestLoggingFilter     : Request URL: http://localhost:8081/contact/John
INFO 5835 --- [nio-8081-exec-1] c.j.s.m.r.CustomRequestLoggingFilter     : Response status: 200

4. 弹簧 MVC 支持

Spring MVC内置了对日志记录请求的支持,我们接下来将对此进行研究。

4.1. 使用共享资源请求日志记录过滤器

Spring MVC提供了CommonsRequestLoggingFilter,它可以记录请求URL,正文和其他相关信息

要在应用程序中使用它,我们必须首先为它定义一个 bean:

@Bean
public CommonsRequestLoggingFilter requestLoggingFilter() {
    CommonsRequestLoggingFilter requestLoggingFilter = new CommonsRequestLoggingFilter();
    requestLoggingFilter.setIncludeClientInfo(true);
    requestLoggingFilter.setIncludeHeaders(true);
    requestLoggingFilter.setIncludeQueryString(true);
    requestLoggingFilter.setIncludePayload(true);
    return requestLoggingFilter;
}

在这里,我们正在创建一个CommonsRequestLoggingFilter的实例,并为丰富的日志语句启用所有包含选项。

然后,我们将筛选器的日志级别更改为DEBUG。我们可以使用application.properties 来做到这一点:

logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG

当新请求到达时,筛选器会提供日志:

DEBUG 27115 --- [nio-8081-exec-1] o.s.w.f.CommonsRequestLoggingFilter      : Before request [uri=/contact/John;client=127.0.0.1;headers=[accept:"text/plain, application/json, application/*+json, */*", content-type:"text/plain;charset=UTF-8", user-agent:"Java/1.8.0_191", host:"localhost:8081", connection:"keep-alive", content-length:"15"]]
DEBUG 27115 --- [nio-8081-exec-1] o.s.w.f.CommonsRequestLoggingFilter      : After request [uri=/contact/John;client=127.0.0.1;headers=[accept:"text/plain, application/json, application/*+json, */*", content-type:"text/plain;charset=UTF-8", user-agent:"Java/1.8.0_191", host:"localhost:8081", connection:"keep-alive", content-length:"15"];payload=London, England]

4.2. 扩展抽象请求日志记录过滤器

除了使用CommonsRequestLoggingFilter,我们还可以创建自己的过滤器来扩展AbstractRequestLoggingFilter。事实上,CommonsRequestLoggingFilter也是AbstractRequestLoggingFilter 的实现。

@Component
public class AnotherCustomLoggingFilter extends AbstractRequestLoggingFilter {

    @Value("${request.logging.shouldLog}")
    private boolean shouldLog;

    public AnotherCustomLoggingFilter(){
        setIncludeClientInfo(true);
        setIncludeHeaders(true);
        setIncludePayload(true);
        setIncludeQueryString(true);
        setBeforeMessagePrefix("Request started => ");
        setAfterMessagePrefix("Request ended => ");
    }

    @Override
    protected boolean shouldLog(HttpServletRequest request) {
        return shouldLog;
    }

    @Override
    protected void beforeRequest(HttpServletRequest request, String message) {
        logger.info(message);
    }

    @Override
    protected void afterRequest(HttpServletRequest request, String message) {
        logger.info(message);
    }
}

在这里,我们有OtherCustomLoggingFilter它实现了 3 个方法:shouldLogbeforeRequestafterRequest

我们使用应用程序属性 -request.logging.shouldLog 启用日志记录行为。在beforeRequestafterRequest方法中,我们只是记录消息,尽管我们也可以执行更复杂的操作。最后,我们在构造函数中启用包含选项。

日志输出与CommonsRequestLoggingFilter 非常相似:

INFO 5835 --- [nio-8081-exec-1] c.j.s.m.r.AnotherCustomLoggingFilter     : Request started => uri=/contact/John;client=127.0.0.1;headers=[accept:"text/plain, application/json, application/*+json, */*", content-type:"text/plain;charset=UTF-8", user-agent:"Java/1.8.0_191", host:"localhost:8081", connection:"keep-alive", content-length:"15"]
INFO 5835 --- [nio-8081-exec-1] c.j.s.m.r.AnotherCustomLoggingFilter     : Request ended => uri=/contact/John;client=127.0.0.1;headers=[accept:"text/plain, application/json, application/*+json, */*", content-type:"text/plain;charset=UTF-8", user-agent:"Java/1.8.0_191", host:"localhost:8081", connection:"keep-alive", content-length:"15"];payload=London, England

5. 总结

在本教程中,我们研究了使用 Spring MVC 记录传入请求的不同方法。

Github 上查看本教程中所有示例的源代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值