Search code examples
spring-bootfilterresponsehttpresponsespring-restcontroller

spring boot RestController get HttpServletResponse content


I use spring boot build project, RestController return string data.

I want get response content in Filter.

But cant get, please help me.

controller:

@RestController
@RequestMapping(value = "/service/example")
public class ExampleController {
    @RequestMapping(value = "/get/test", method = RequestMethod.POST)
    public String message(@RequestBody String data) {
        return "test";
    }

    @RequestMapping(value = "/get/test1", method = RequestMethod.POST)
    public void message(HttpServletRequest request, HttpServletResponse response) throws IOException {
        PrintWriter writer = response.getWriter();
        writer.write("dfsfd");
        writer.flush();
    }
}

filter:

@WebFilter(filterName="myFilter",urlPatterns="/service/*")
public class MyFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
        MyHttpServletResponseWrapper responseWrapper = new MyHttpServletResponseWrapper(response);
        filterChain.doFilter(request, responseWrapper);
        String responseContent = responseWrapper.getContent();
        System.out.println("response="+responseContent);
    }
}

MyHttpServletResponseWrapper :

public class MyHttpServletResponseWrapper extends HttpServletResponseWrapper {

    private PrintWriter cachedWriter;
    private CharArrayWriter bufferedWriter;

    /**
     * Constructs a response adaptor wrapping the given response.
     *
     * @param response The response to be wrapped
     * @throws IllegalArgumentException if the response is null
     */
    public MyHttpServletResponseWrapper(HttpServletResponse response) {
        super(response);
        bufferedWriter = new CharArrayWriter();
        cachedWriter = new PrintWriter(bufferedWriter);
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        return cachedWriter;
    }

    /**
     * 获取原始HTML
     *
     * @return
     */
    public String getContent() {
        byte[] bytes = bufferedWriter.toString().getBytes();
        try {
            return new String(bytes, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            return "";
        }
    }
}

post to /service/example/get/test cant get content. but post to /service/example/get/test1 can get content.

why?

My project has many rest like /service/example/get/test, I dont want to change each one.

how to get response content in filter, please help, Thanks!!!


Solution

  • I created one simple spring boot project, in this project you can control which url you want to filter:

    Rest service class (3 services, we will filter 2 only)

    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.filter.GenericFilterBean;
    
    @SpringBootApplication
    @RestController
    @RequestMapping(value = "/service/example")
    public class DemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    
        @RequestMapping(value = "/get/test", method = RequestMethod.POST)
        public String message(@RequestBody String data) {
            return "test";
        }
    
        @RequestMapping(value = "/get/test1", method = RequestMethod.POST)
        public void message(HttpServletRequest request, HttpServletResponse response) throws IOException {
            PrintWriter writer = response.getWriter();
            writer.write("dfsfd");
            writer.flush();
        }
    
        @RequestMapping(value = "/api", method = RequestMethod.POST)
        public void messages(HttpServletRequest request, HttpServletResponse response) throws IOException {
            PrintWriter writer = response.getWriter();
            writer.write("dfsfd");
            writer.flush();
        }
    
    
        @Bean
        public FilterRegistrationBean someFilterRegistration() {
    
            FilterRegistrationBean registration = new FilterRegistrationBean();
            registration.setFilter(myFilter());
            registration.addUrlPatterns("/service/example/get/*");
            registration.setOrder(1);
            return registration;
        } 
    
        @Bean(name = "someFilter")
        public GenericFilterBean myFilter() {
            return new MyFilter();
        }
    }
    

    MyFilter class:

    import java.io.IOException;
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import org.springframework.web.filter.GenericFilterBean;
    
    public class MyFilter extends GenericFilterBean {
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
                throws IOException, ServletException {
            System.out.println("Filter called");
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
    }
    

    try to call 3 services:

    http://localhost:8080/service/example/get/test

    http://localhost:8080/service/example/get/test1

    http://localhost:8080/service/example/api

    and check the printed log.

    you can control the url patter using this line

    registration.addUrlPatterns("/service/example/get/*");
    

    I hope this sample help you, thanks