首页 > 解决方案 > 如何在过滤器中修改 post call 的对象。弹簧靴

问题描述

我的应用程序中有一个过滤器

@Component
@Order(2)
public class RequestResponseLoggingFilter implements Filter {

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

        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        // SET VALUE OF OBJECT
    }

    // other methods
}

我有一个使用类的 Restcall。

@RequestMapping
Class Test{
  @PostMapping("/test")
  public void postEntry(@Valid @RequestBody Testing testing){
  }
}

Class Testing{
@NotNull(message="ERROR")  
String id;

....
}

我在我的过滤器中获得了 id,我想在我的过滤器中设置测试类的 id。这可能吗?

标签: javaspringspring-boot

解决方案


你可以使用MockHttpServletRequest这样的东西

@Test
public void testAddEventWithWebAuthenticationDetails() {
    HttpSession session = new MockHttpSession(null, "test-session-id");
    MockHttpServletRequest request = new MockHttpServletRequest();
    request.setSession(session);
    request.setRemoteAddr("1.2.3.4");
    WebAuthenticationDetails details = new WebAuthenticationDetails(request);
    Map<String, Object> data = new HashMap<>();
    data.put("test-key", details);
    AuditEvent event = new AuditEvent("test-user", "test-type", data);
    customAuditEventRepository.add(event);
    List<PersistentAuditEvent> persistentAuditEvents = persistenceAuditEventRepository.findAll();
    assertThat(persistentAuditEvents).hasSize(1);
    PersistentAuditEvent persistentAuditEvent = persistentAuditEvents.get(0);
    assertThat(persistentAuditEvent.getData().get("remoteAddress")).isEqualTo("1.2.3.4");
    assertThat(persistentAuditEvent.getData().get("sessionId")).isEqualTo("test-session-id");
}

更多示例在这里

或者

如果你想这样做过滤方式

之前的几点

  • 请求正文只能读取一次。
  • 如果您在过滤器中读取正文,则目标 servlet 将无法重新读取它,这也会导致 IllegalStateException。
  • 您将需要 ServletRequestWrapper 或其子项: HttpServletRequestWrapper 以便您可以读取 HTTP 请求正文,然后 servlet 稍后仍可以读取它。

工作流程将是

  • 唯一的方法是您自己在过滤器中使用整个输入流。
  • 从中获取您想要的内容,然后为您阅读的内容创建一个新的 InputStream。
  • 将该 InputStream 放入 ServletRequestWrapper(或 HttpServletRequestWrapper)。

    // 示例 Wrapper 类,您可以在其中读取正文和修改正文内容

     public class SampleHttpServletRequest 
    
            extends HttpServletRequestWrapper {
    
      private ByteArrayOutputStream cachedBytes;
    
      public SampleHttpServletRequest(HttpServletRequest request) {
        super(request);
      }
    
      @Override
      public ServletInputStream getInputStream() throws IOException {
        if (cachedBytes == null)
          cacheInputStream();
    
          return new CachedServletInputStream();
      }
    
      @Override
      public BufferedReader getReader() throws IOException{
        return new BufferedReader(new InputStreamReader(getInputStream()));
      }
    
      private void cacheInputStream() throws IOException {
        cachedBytes = new ByteArrayOutputStream();
        IOUtils.copy(super.getInputStream(), cachedBytes);
      }
    
      public class CachedServletInputStream extends ServletInputStream {
        private ByteArrayInputStream input;
    
        public CachedServletInputStream() {
          input = new ByteArrayInputStream(cachedBytes.toByteArray());
        }
    
        @Override
        public int read() throws IOException {
          return input.read();
        }
      }
    }
    

过滤器类

public class MyFilter implements Filter {
  @Override
  public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {

    /* wrap the request in order to read the inputstream multiple times */
    MultiReadHttpServletRequest multiReadRequest = new MultiReadHttpServletRequest((HttpServletRequest) request);

    doMyThing(multiReadRequest.getInputStream());
    chain.doFilter(multiReadRequest, response);
  }
}    

有关更多详细信息,请参阅这些帖子

Http Servlet 请求在读取一次后从 POST 正文中丢失参数

HttpServletRequestWrapper,setReadListener / isFinished / isReady 的示例实现?


推荐阅读