Java Spring 在处理之前更改响应

Posted

技术标签:

【中文标题】Java Spring 在处理之前更改响应【英文标题】:Java Spring change the response before handle it 【发布时间】:2016-12-09 05:23:26 【问题描述】:

好的,我一直在尝试实现一个系统,在该系统中,在检查请求上的参数(如路径)后,我实际上会修改响应以使用不同的数据进行回答。想法是创建后端演示功能,这样客户端可以演示(不测试)应用程序而无需实际发出数据库请求。

所以,我的第一次尝试是使用 servlet 过滤器,可以在 here 找到一个非常好的答案,还有一些名为 The Essentials of Filters 的好文档。但我无法让它工作,我认为因为我使用带有@Controller 和 @ResponseBody 的 spring,即使我遵循完全相同的示例,我也会得到一个 null 作为 wrapperResponse。

然后我尝试了Interceptors,here 有很好的例子,并且一个很好的实际答案here。但是这样做的问题是,通常人们会使用 postHandle 来修改 body,我真的不希望句柄甚至触发,因为这意味着数据库调用也会被触发。如果我将 preHandler 用作here,它只会创建一个新的 servlet,我不希望这样。

最后我尝试@ControllerAdvice,它基本上允许您在发送之前重写正文,但同样,处理程序得到处理,所有数据库调用都使用它。

我的目标是我不必在每个处理程序中放置重复的代码,我可以让 preHandler 插入一些额外的标头并在 @ControllerAdvice 中检查该标头,但这意味着我必须制作一些 IF/ELSE在处理程序中,因此它不会被处理,我必须在系统中拥有的 100 个 @Controllers 上重复这一点,我想要 DRY。

我很确定解决方案就在这个answer的过滤器上

public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain) throws IOException, ServletException 

System.out.println("BEFORE filter");
PrintWriter out = response.getWriter();
CharResponseWrapper responseWrapper = new CharResponseWrapper(
        (HttpServletResponse) response);

chain.doFilter(request, responseWrapper);

String servletResponse = new String(responseWrapper.toString());

out.write(servletResponse + " filtered"); // Here you can change the response


System.out.println("AFTER filter, original response: "
        + servletResponse);


但我不能让它与 spring 和 @ResponseBody 调用一起工作。说实话,this 没有回答我的问题。

【问题讨论】:

【参考方案1】:

这就是我设法做到这一点的方式。

首先我创建了一个拦截器,它实际上过滤请求以传递我们想要演示的内容。在预处理程序中,我没有尝试使用 Response outstream 创建响应,而是使用 RequestDispatcher 将请求转发到一个新的控制器,我称之为 Demo 控制器。

@Override
public boolean preHandle(HttpServletRequest request,
        HttpServletResponse response, Object handler) throws Exception 
    // TODO Auto-generated method stub

    Pattern pattern = Pattern.compile("someregex");
    Matcher matcher = pattern.matcher(request.getPathInfo());

    if (matcher.find())
    
        if (matcher.group(0).equals("SOMETHING"))
        
            HandlerMethod handlerMethod = ((HandlerMethod)handler);
            request.setAttribute("methodName", handlerMethod.getBeanType().getSimpleName());
            request.getRequestDispatcher("/demo").forward(request, response);
            return false;
        
        return true;
    
    else
    
        return true;
    

在演示控制器中,您可以创建一个您想要演示的正确响应。这里的好处是,在新的演示中,转发请求将具有原始请求 javax.servlet.forward.request_uri 的属性,并且您可以插入数据,作为转发前请求的控制器名称。所有这些数据都可以在 Demo 控制器中提取,以生成所需的数据。

【讨论】:

以上是关于Java Spring 在处理之前更改响应的主要内容,如果未能解决你的问题,请参考以下文章

Spring中的@Async

转Spring中@Async

如何在spring mvc中的操作之前发送响应

Spring @async原理

五:JAVA日志体系

Spring中@Async用法总结