Open In App

Get the Response Body in Spring Boot Filter

Last Updated : 17 Sep, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

In a Spring Boot application, filters can be used to intercept requests and responses, allowing you to manipulate them before reaching the controller or after the response is generated. A common requirement is capturing or logging the response body in the Spring Boot filter, especially for monitoring, auditing, or debugging purposes. Capturing the response body in the filter isn't straightforward because once the response body is written, it cannot be retrieved directly from HttpServletResponse. To address this, we can wrap the HttpServletResponse and capture its content.

To capture the response body in the filter, we need to wrap the HttpServletResponse object. This is achieved by creating a custom HttpServletResponseWrapper that buffers the output stream, allowing us to read the response body even after it has been written.

Steps:

  1. Create the Custom HttpServletResponseWrapper: This wrapper class will buffer the output and allow us to capture the response body.
  2. Implement the Filter: The filter will use the wrapper to intercept and read the response body

Implementation to Get the Response Body in Spring Boot Filter

Step 1: Create the new Spring Boot project

Create a new Spring Boot project using IntelliJ IDEA. Choose the following options:

  • Name: spring-boot-response-filter
  • Language: Java
  • Type: Maven
  • Packaging: Jar

Click the Next button to proceed.

Project Metadata

Step 2: Add Dependencies

Add the following dependencies into the Spring Boot project.

  • Spring Web
  • Lombok
  • Spring DevTools

Click on the Create button.

Add Dependencies

Project Structure

After successfully creating the project, the structure will look like the below image:

Project Folder Structure

Step 3: Configure Application Properties

Open the application.properties file and add the following configuration:

spring.application.name=spring-boot-response-filter
server.port = 8080

Step 4: Custom HTTP Response Wrapper

Create the CustomHttpResponseWrapper class to wrap HttpServletResponse and capture the response body.

CustomHttpResponseWrapper.java:

Java
package com.gfg.springbootresponsefilter;

import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.WriteListener;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * Custom wrapper for HttpServletResponse to capture response body.
 */
public class CustomHttpResponseWrapper extends HttpServletResponseWrapper {

    private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    private final PrintWriter printWriter = new PrintWriter(outputStream);

    public CustomHttpResponseWrapper(HttpServletResponse response) {
        super(response);
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return new ServletOutputStream() {
            @Override
            public boolean isReady() {
                // Indicate whether the stream is ready to be written to.
                return true; // Changed to true for better compatibility
            }

            @Override
            public void setWriteListener(WriteListener writeListener) {
                // No-op for synchronous processing
            }

            @Override
            public void write(int b) throws IOException {
                outputStream.write(b); // Write data to buffer
            }
        };
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        return printWriter; // Use PrintWriter to capture text data
    }

    public byte[] getResponseData() throws IOException {
        printWriter.flush(); // Ensure all data is written to the buffer
        return outputStream.toByteArray(); // Return buffered response data
    }
}

Step 5: Filter to Capture Response Body

Create the ResponseBodyLoggingFilter class to intercept the response, capture the body, and log it before sending it back to the client.

ResponseBodyLoggingFilter.java:

Java
package com.gfg.springbootresponsefilter;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * Filter to capture and log the response body.
 */
@Component
public class ResponseBodyLoggingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // No initialization required
    }

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

        // Cast response to HttpServletResponse
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // Wrap the response to capture the body
        CustomHttpResponseWrapper responseWrapper = new CustomHttpResponseWrapper(httpResponse);

        // Continue with the filter chain
        chain.doFilter(request, responseWrapper);

        // Get the response body data from the wrapper
        byte[] responseData = responseWrapper.getResponseData();
        String responseBody = new String(responseData, httpResponse.getCharacterEncoding());

        // Log the response body
        System.out.println("Response Body: " + responseBody);

        // Write the response body back to the client
        response.getOutputStream().write(responseData);
    }

    @Override
    public void destroy() {
        // No cleanup required
    }
}

Step 6: Test Controller

Create the TestController class with a simple REST controller that returns a message to simulate response content.

TestController.java:

Java
package com.gfg.springbootresponsefilter;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * REST controller for testing response body capture.
 */
@RestController
public class TestController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello, World!"; // Response message
    }
}

Step 7: Main Class

The main class remains unchanged and is the entry point of the Spring Boot application.

SpringBootResponseFilterApplication.java:

Java
package com.gfg.springbootresponsefilter;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootResponseFilterApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootResponseFilterApplication.class, args);
    }

}

pom.xml File:

The pom.xml file is configured with the necessary dependencies.

XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gfg</groupId>
    <artifactId>spring-boot-response-filter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-boot-response-filter</name>
    <description>spring-boot-response-filter</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Step 8: Run the Application

Once the project setup is complete, start the application. It will run on port 8080.

Application Starts

Step 9: Test the Application

Use Postman or any other API client to send a GET request to:

http://localhost:8080/hello

We should see the following message in the postman.

Postman ui

Application Logs

In the application logs, you should see the captured response body:

Application Logs

Conclusion

In this example project, we demonstrated how to capture the response body in a Spring Boot filter by creating a custom HttpServletResponseWrapper. This technique can be useful for logging or modifying the response before it is sent to the client.


Next Article

Similar Reads