'Get body as raw string from ServerWebExchange/ServerHttpRequest

I need to get the request body as a raw JSON string in my controller. I'm using Spring WebFlux. If I could change @PostMapper function signature, it will be so easy to get the raw JSON by using "@RequestBody String rawStudent". But I can't do that as it's auto-generated and will affect other handlers, also "@RequestBody Student" already exist and we can't have two @RequestBody.

@RestController
public class StudentController {
    @PostMapping("/student")
    private void newStudent(@RequestBody Student student,
                            ServerWebExchange exchange) {
        String rawStudent = ServerExchangeUtils.getRequestRawBody(exchange); //idealy like this
        System.out.println(rawStudent);
    }
}

What I'm looking for is something like "getRequestRaw(exchange)"



Solution 1:[1]

i had the same problem and i cant change the signaure because it is generated by openapi generator

i found a solution by setting an exchange attribute in a WebFilter :

@Component
@Slf4j
public class SetRequestBodyAttribute implements WebFilter {

    public static final String BODY_STRING_ATTRIBUTE = "BODY_STRING";

    private static ServerHttpRequestPredicate requestsToServe =
            MethodServerHttpRequestPredicate.of(HttpMethod.POST)
                    .and(PathServerHttpRequestPredicate.of("/contacts/import"))
                    .or(MethodServerHttpRequestPredicate.of(HttpMethod.PATCH)
                            .and(PathServerHttpRequestPredicate.of("/contacts/{contact_id}")));

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        if (requestsToServe.test(exchange.getRequest())) {
            log.info("setting request attribute {}.", BODY_STRING_ATTRIBUTE);
            exchange.getAttributes().put(BODY_STRING_ATTRIBUTE, ServerHttpRequestUtils.getBodyAsString(exchange.getRequest()));
        }
        return chain.filter(exchange);
    }
}


@UtilityClass
public class ServerHttpRequestUtils {

    public Mono<String> getBodyAsString(ServerHttpRequest request) {
        return DataBufferUtils.join(request.getBody())
                .map(DataBuffer::asByteBuffer)
                .map(ByteBuffer::array)
                .map(String::new);
    }
}


public interface ServerHttpRequestPredicate {

    boolean test(ServerHttpRequest request);

    @NotNull
    default ServerHttpRequestPredicate and(@NotNull ServerHttpRequestPredicate other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    @NotNull
    default ServerHttpRequestPredicate negate() {
        return (t) -> !test(t);
    }

    @NotNull
    default ServerHttpRequestPredicate or(@NotNull ServerHttpRequestPredicate other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
}

@Value
public class PathServerHttpRequestPredicate implements ServerHttpRequestPredicate {

    public static PathServerHttpRequestPredicate of(String path) {
        return new PathServerHttpRequestPredicate(path);
    }

    PathPattern pathPattern;

    public PathServerHttpRequestPredicate(String path) {
        Assert.notNull(path, "path should not be null!");
        this.pathPattern = PathPatternParser.defaultInstance.parse(path);
    }

    @Override
    public boolean test(ServerHttpRequest request) {
        PathContainer pathContainer = request.getPath().pathWithinApplication();
        PathPattern.PathMatchInfo info = this.pathPattern.matchAndExtract(pathContainer);
        return info != null;
    }
}

@Value(staticConstructor = "of")
public class MethodServerHttpRequestPredicate implements ServerHttpRequestPredicate{

    HttpMethod httpMethod;

    public MethodServerHttpRequestPredicate(HttpMethod httpMethod) {
        Assert.notNull(httpMethod, "httpMethod should not be null!");
        this.httpMethod = httpMethod;
    }

    @Override
    public boolean test(ServerHttpRequest request) {
        return request.getMethod() == httpMethod;
    }
}

and in the controller handler we can get the body as string even if it was injected as Object

Mono<String> bodyAsStringMono = exchange.getAttribute(SetRequestBodyAttribute.BODY_STRING_ATTRIBUTE);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1