如何修改过滤器中的帖子调用对象。春季靴

时间:2018-07-27 00:58:48

标签: java spring spring-boot

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

@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,我想在我的过滤器中设置Testing类的ID。这可能吗?

1 个答案:

答案 0 :(得分:1)

您可以使用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");
}

更多示例here

如果要进行过滤的方式

在此之前的几点

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

工作流程将是

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

    // Sample 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 request lose params from POST body after read it once

HttpServletRequestWrapper, example implementation for setReadListener / isFinished / isReady?