INT-4479: RequestEntity as root for status code
JIRA: https://jira.spring.io/browse/INT-4479 For better user experience expose a `RequestEntity<?>` as a root object for evaluation context for `statusCodeExpression` execution
This commit is contained in:
committed by
Gary Russell
parent
a05004ae38
commit
262e624ef4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
* Copyright 2017-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,6 +27,7 @@ import org.springframework.expression.Expression;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.integration.dsl.ComponentsRegistration;
|
||||
import org.springframework.integration.dsl.MessagingGatewaySpec;
|
||||
@@ -277,7 +278,7 @@ public abstract class HttpInboundEndpointSupportSpec<S extends HttpInboundEndpoi
|
||||
* @return the current Spec.
|
||||
* @see HttpRequestHandlingEndpointSupport#setStatusCodeExpression(Expression)
|
||||
*/
|
||||
public S statusCodeFunction(Function<Void, ?> statusCodeFunction) {
|
||||
public S statusCodeFunction(Function<RequestEntity<?>, ?> statusCodeFunction) {
|
||||
return statusCodeExpression(new FunctionExpression<>(statusCodeFunction));
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.core.ResolvableType;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpRequest;
|
||||
@@ -276,8 +277,8 @@ public class BaseHttpInboundEndpoint extends MessagingGatewaySupport implements
|
||||
}
|
||||
}
|
||||
|
||||
protected HttpStatus evaluateHttpStatus() {
|
||||
Object value = this.statusCodeExpression.getValue(this.evaluationContext);
|
||||
protected HttpStatus evaluateHttpStatus(HttpEntity<?> httpEntity) {
|
||||
Object value = this.statusCodeExpression.getValue(this.evaluationContext, httpEntity);
|
||||
return buildHttpStatus(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,6 +27,8 @@ import org.springframework.context.MessageSource;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -52,15 +54,25 @@ import org.springframework.web.servlet.mvc.Controller;
|
||||
* @author Mark Fisher
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSupport implements Controller {
|
||||
|
||||
private static final String DEFAULT_ERROR_CODE = "spring.integration.http.handler.error";
|
||||
/**
|
||||
* The View model key for the error code.
|
||||
*/
|
||||
public static final String DEFAULT_ERROR_CODE = "spring.integration.http.handler.error";
|
||||
|
||||
private static final String DEFAULT_REPLY_KEY = "reply";
|
||||
/**
|
||||
* The View model key for reply.
|
||||
*/
|
||||
public static final String DEFAULT_REPLY_KEY = "reply";
|
||||
|
||||
private static final String DEFAULT_ERRORS_KEY = "errors";
|
||||
/**
|
||||
* The View model key for errors.
|
||||
*/
|
||||
public static final String DEFAULT_ERRORS_KEY = "errors";
|
||||
|
||||
private volatile Expression viewExpression;
|
||||
|
||||
@@ -82,7 +94,6 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu
|
||||
|
||||
/**
|
||||
* Specify the view name.
|
||||
*
|
||||
* @param viewName The view name.
|
||||
*/
|
||||
public void setViewName(String viewName) {
|
||||
@@ -94,7 +105,6 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu
|
||||
* Specify the key to be used when adding the reply Message or payload to the core map (will be payload only unless
|
||||
* the value of {@link HttpRequestHandlingController#setExtractReplyPayload(boolean)} is <code>false</code>). The
|
||||
* default key is "reply".
|
||||
*
|
||||
* @param replyKey The reply key.
|
||||
*/
|
||||
public void setReplyKey(String replyKey) {
|
||||
@@ -104,7 +114,6 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu
|
||||
/**
|
||||
* The key used to expose {@link Errors} in the core, in the case that message handling fails. Defaults to
|
||||
* "errors".
|
||||
*
|
||||
* @param errorsKey The key value to set.
|
||||
*/
|
||||
public void setErrorsKey(String errorsKey) {
|
||||
@@ -116,7 +125,6 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu
|
||||
* provided in an object error to be optionally translated in the standard MVC way using a {@link MessageSource}.
|
||||
* The default value is <code>spring.integration.http.handler.error</code>. Three arguments are provided: the
|
||||
* exception, its message and its stack trace as a String.
|
||||
*
|
||||
* @param errorCode The error code to set.
|
||||
*/
|
||||
public void setErrorCode(String errorCode) {
|
||||
@@ -126,7 +134,6 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu
|
||||
/**
|
||||
* Specifies a SpEL expression to evaluate in order to generate the view name.
|
||||
* The EvaluationContext will be populated with the reply message as the root object,
|
||||
*
|
||||
* @param viewExpression The view expression.
|
||||
*/
|
||||
public void setViewExpression(Expression viewExpression) {
|
||||
@@ -144,11 +151,14 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu
|
||||
* 'expectReply' property is true, it will also generate a response from the reply Message once received.
|
||||
*/
|
||||
@Override
|
||||
public final ModelAndView handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
|
||||
throws Exception {
|
||||
public final ModelAndView handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
try {
|
||||
Message<?> replyMessage = super.doHandleRequest(servletRequest, servletResponse);
|
||||
ServletServerHttpRequest request = prepareRequest(servletRequest);
|
||||
|
||||
RequestEntity<Object> httpEntity = prepareRequestEntity(request);
|
||||
|
||||
Message<?> replyMessage = doHandleRequest(servletRequest, httpEntity, servletResponse);
|
||||
ServletServerHttpResponse response = new ServletServerHttpResponse(servletResponse);
|
||||
if (replyMessage != null) {
|
||||
Object reply = setupResponseAndConvertReply(response, replyMessage);
|
||||
@@ -156,7 +166,7 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu
|
||||
modelAndView.addObject(this.replyKey, reply);
|
||||
}
|
||||
else {
|
||||
setStatusCodeIfNeeded(response);
|
||||
setStatusCodeIfNeeded(response, httpEntity);
|
||||
}
|
||||
|
||||
if (this.viewExpression != null) {
|
||||
@@ -183,8 +193,9 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu
|
||||
PrintWriter stackTrace = new PrintWriter(new StringWriter());
|
||||
e.printStackTrace(stackTrace);
|
||||
errors.reject(this.errorCode, new Object[] { e, e.getMessage(), stackTrace.toString() },
|
||||
"A Spring Integration handler raised an exception while handling an HTTP request. The exception is of type "
|
||||
+ e.getClass() + " and it has a message: (" + e.getMessage() + ")");
|
||||
"A Spring Integration handler raised an exception while handling an HTTP request. " +
|
||||
"The exception is of type " + e.getClass() + " and it has a message: (" +
|
||||
e.getMessage() + ")");
|
||||
modelAndView.addObject(this.errorsKey, errors);
|
||||
}
|
||||
return modelAndView;
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.ResourceHttpMessageConverter;
|
||||
@@ -245,33 +246,26 @@ public abstract class HttpRequestHandlingEndpointSupport extends BaseHttpInbound
|
||||
* Handles the HTTP request by generating a Message and sending it to the request channel. If this gateway's
|
||||
* 'expectReply' property is true, it will also generate a response from the reply Message once received.
|
||||
* @param servletRequest The servlet request.
|
||||
* @param httpEntity the request entity to use.
|
||||
* @param servletResponse The servlet response.
|
||||
* @return The response Message.
|
||||
* @throws IOException Any IOException.
|
||||
*/
|
||||
protected final Message<?> doHandleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
|
||||
throws IOException {
|
||||
protected final Message<?> doHandleRequest(HttpServletRequest servletRequest, RequestEntity<?> httpEntity,
|
||||
HttpServletResponse servletResponse) {
|
||||
if (isRunning()) {
|
||||
return actualDoHandleRequest(servletRequest, servletResponse);
|
||||
return actualDoHandleRequest(servletRequest, httpEntity, servletResponse);
|
||||
}
|
||||
else {
|
||||
return createServiceUnavailableResponse();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private Message<?> actualDoHandleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
|
||||
throws IOException {
|
||||
@SuppressWarnings("unchecked")
|
||||
private Message<?> actualDoHandleRequest(HttpServletRequest servletRequest, RequestEntity<?> httpEntity,
|
||||
HttpServletResponse servletResponse) {
|
||||
|
||||
this.activeCount.incrementAndGet();
|
||||
try {
|
||||
ServletServerHttpRequest request = this.prepareRequest(servletRequest);
|
||||
|
||||
Object requestBody = null;
|
||||
if (isReadable(request)) {
|
||||
requestBody = extractRequestBody(request);
|
||||
}
|
||||
HttpEntity httpEntity = new HttpEntity(requestBody, request.getHeaders());
|
||||
|
||||
StandardEvaluationContext evaluationContext = this.createEvaluationContext();
|
||||
evaluationContext.setRootObject(httpEntity);
|
||||
|
||||
@@ -284,7 +278,7 @@ public abstract class HttpRequestHandlingEndpointSupport extends BaseHttpInbound
|
||||
|
||||
Cookie[] requestCookies = servletRequest.getCookies();
|
||||
if (!ObjectUtils.isEmpty(requestCookies)) {
|
||||
Map<String, Cookie> cookies = new HashMap<String, Cookie>(requestCookies.length);
|
||||
Map<String, Cookie> cookies = new HashMap<>(requestCookies.length);
|
||||
for (Cookie requestCookie : requestCookies) {
|
||||
cookies.put(requestCookie.getName(), requestCookie);
|
||||
}
|
||||
@@ -312,7 +306,7 @@ public abstract class HttpRequestHandlingEndpointSupport extends BaseHttpInbound
|
||||
evaluationContext.setVariable("matrixVariables", matrixVariables);
|
||||
}
|
||||
|
||||
Map<String, Object> headers = getHeaderMapper().toHeaders(request.getHeaders());
|
||||
Map<String, Object> headers = getHeaderMapper().toHeaders(httpEntity.getHeaders());
|
||||
Object payload = null;
|
||||
if (getPayloadExpression() != null) {
|
||||
// create payload based on SpEL
|
||||
@@ -330,8 +324,8 @@ public abstract class HttpRequestHandlingEndpointSupport extends BaseHttpInbound
|
||||
}
|
||||
|
||||
if (payload == null) {
|
||||
if (requestBody != null) {
|
||||
payload = requestBody;
|
||||
if (httpEntity.getBody() != null) {
|
||||
payload = httpEntity.getBody();
|
||||
}
|
||||
else {
|
||||
payload = requestParams;
|
||||
@@ -350,9 +344,9 @@ public abstract class HttpRequestHandlingEndpointSupport extends BaseHttpInbound
|
||||
|
||||
Message<?> message = messageBuilder
|
||||
.setHeader(org.springframework.integration.http.HttpHeaders.REQUEST_URL,
|
||||
request.getURI().toString())
|
||||
httpEntity.getUrl().toString())
|
||||
.setHeader(org.springframework.integration.http.HttpHeaders.REQUEST_METHOD,
|
||||
request.getMethod().toString())
|
||||
httpEntity.getMethod().toString())
|
||||
.setHeader(org.springframework.integration.http.HttpHeaders.USER_PRINCIPAL,
|
||||
servletRequest.getUserPrincipal())
|
||||
.build();
|
||||
@@ -366,7 +360,7 @@ public abstract class HttpRequestHandlingEndpointSupport extends BaseHttpInbound
|
||||
if (getStatusCodeExpression() != null) {
|
||||
reply = getMessageBuilderFactory().withPayload(e.getMessage())
|
||||
.setHeader(org.springframework.integration.http.HttpHeaders.STATUS_CODE,
|
||||
evaluateHttpStatus())
|
||||
evaluateHttpStatus(httpEntity))
|
||||
.build();
|
||||
}
|
||||
else {
|
||||
@@ -419,9 +413,9 @@ public abstract class HttpRequestHandlingEndpointSupport extends BaseHttpInbound
|
||||
|
||||
}
|
||||
|
||||
protected void setStatusCodeIfNeeded(ServerHttpResponse response) {
|
||||
protected void setStatusCodeIfNeeded(ServerHttpResponse response, HttpEntity<?> httpEntity) {
|
||||
if (getStatusCodeExpression() != null) {
|
||||
HttpStatus httpStatus = evaluateHttpStatus();
|
||||
HttpStatus httpStatus = evaluateHttpStatus(httpEntity);
|
||||
if (httpStatus != null) {
|
||||
response.setStatusCode(httpStatus);
|
||||
}
|
||||
@@ -437,7 +431,7 @@ public abstract class HttpRequestHandlingEndpointSupport extends BaseHttpInbound
|
||||
* @return the processed request (multipart wrapper if necessary)
|
||||
* @see MultipartResolver#resolveMultipart
|
||||
*/
|
||||
private ServletServerHttpRequest prepareRequest(HttpServletRequest servletRequest) {
|
||||
protected ServletServerHttpRequest prepareRequest(HttpServletRequest servletRequest) {
|
||||
if (servletRequest instanceof MultipartHttpServletRequest) {
|
||||
return new MultipartHttpInputMessage((MultipartHttpServletRequest) servletRequest);
|
||||
}
|
||||
@@ -472,8 +466,17 @@ public abstract class HttpRequestHandlingEndpointSupport extends BaseHttpInbound
|
||||
return convertedMap;
|
||||
}
|
||||
|
||||
protected RequestEntity<Object> prepareRequestEntity(ServletServerHttpRequest request) throws IOException {
|
||||
Object requestBody = null;
|
||||
if (isReadable(request)) {
|
||||
requestBody = extractRequestBody(request);
|
||||
}
|
||||
|
||||
return new RequestEntity<>(requestBody, request.getHeaders(), request.getMethod(), request.getURI());
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private Object extractRequestBody(ServletServerHttpRequest request) throws IOException {
|
||||
protected Object extractRequestBody(ServletServerHttpRequest request) throws IOException {
|
||||
MediaType contentType = request.getHeaders().getContentType();
|
||||
if (contentType == null) {
|
||||
contentType = MediaType.APPLICATION_OCTET_STREAM;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,13 +20,13 @@ import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
@@ -60,6 +60,7 @@ import org.springframework.web.HttpRequestHandler;
|
||||
* @author Mark Fisher
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class HttpRequestHandlingMessagingGateway extends HttpRequestHandlingEndpointSupport
|
||||
@@ -81,7 +82,6 @@ public class HttpRequestHandlingMessagingGateway extends HttpRequestHandlingEndp
|
||||
* Flag to determine if conversion and writing out of message handling exceptions should be attempted (default
|
||||
* false, in which case they will simply be re-thrown). If the flag is true and no message converter can convert the
|
||||
* exception a new exception will be thrown.
|
||||
*
|
||||
* @param convertExceptions the flag to set
|
||||
*/
|
||||
public void setConvertExceptions(boolean convertExceptions) {
|
||||
@@ -94,15 +94,18 @@ public class HttpRequestHandlingMessagingGateway extends HttpRequestHandlingEndp
|
||||
* response will be written by the {@link HttpMessageConverter}s.
|
||||
*/
|
||||
public final void handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
|
||||
throws ServletException, IOException {
|
||||
throws IOException {
|
||||
|
||||
Object responseContent = null;
|
||||
Message<?> responseMessage;
|
||||
|
||||
final ServletServerHttpRequest request = new ServletServerHttpRequest(servletRequest);
|
||||
final ServletServerHttpResponse response = new ServletServerHttpResponse(servletResponse);
|
||||
ServletServerHttpRequest request = new ServletServerHttpRequest(servletRequest);
|
||||
ServletServerHttpResponse response = new ServletServerHttpResponse(servletResponse);
|
||||
|
||||
RequestEntity<Object> httpEntity = prepareRequestEntity(request);
|
||||
|
||||
try {
|
||||
responseMessage = super.doHandleRequest(servletRequest, servletResponse);
|
||||
responseMessage = doHandleRequest(servletRequest, httpEntity, servletResponse);
|
||||
if (responseMessage != null) {
|
||||
responseContent = setupResponseAndConvertReply(response, responseMessage);
|
||||
}
|
||||
@@ -140,7 +143,7 @@ public class HttpRequestHandlingMessagingGateway extends HttpRequestHandlingEndp
|
||||
}
|
||||
}
|
||||
else {
|
||||
setStatusCodeIfNeeded(response);
|
||||
setStatusCodeIfNeeded(response, httpEntity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,10 +167,11 @@ public class HttpRequestHandlingMessagingGateway extends HttpRequestHandlingEndp
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private void writeResponse(Object content, ServletServerHttpResponse response, List<MediaType> acceptTypes)
|
||||
throws IOException {
|
||||
|
||||
if (CollectionUtils.isEmpty(acceptTypes)) {
|
||||
acceptTypes = Collections.singletonList(MediaType.ALL);
|
||||
}
|
||||
for (HttpMessageConverter converter : this.getMessageConverters()) {
|
||||
for (HttpMessageConverter converter : getMessageConverters()) {
|
||||
for (MediaType acceptType : acceptTypes) {
|
||||
if (converter.canWrite(content.getClass(), acceptType)) {
|
||||
converter.write(content, acceptType, response);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -28,6 +29,8 @@ import org.junit.Test;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.http.AbstractHttpInboundTests;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -47,11 +50,11 @@ import org.springframework.web.servlet.HandlerMapping;
|
||||
*/
|
||||
public class HttpRequestHandlingMessagingGatewayWithPathMappingTests extends AbstractHttpInboundTests {
|
||||
|
||||
private static ExpressionParser PARSER = new SpelExpressionParser();
|
||||
private static final ExpressionParser PARSER = new SpelExpressionParser();
|
||||
|
||||
|
||||
@Test
|
||||
public void withoutExpression() throws Exception {
|
||||
public void withoutExpression() throws IOException {
|
||||
DirectChannel echoChannel = new DirectChannel();
|
||||
echoChannel.subscribe(message -> {
|
||||
MessageChannel replyChannel = (MessageChannel) message.getHeaders().getReplyChannel();
|
||||
@@ -62,7 +65,8 @@ public class HttpRequestHandlingMessagingGatewayWithPathMappingTests extends Abs
|
||||
request.setContentType("text/plain");
|
||||
|
||||
request.setParameter("foo", "bar");
|
||||
request.setContent("hello".getBytes());
|
||||
String body = "hello";
|
||||
request.setContent(body.getBytes());
|
||||
request.setRequestURI("/fname/bill/lname/clinton");
|
||||
|
||||
HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway(true);
|
||||
@@ -78,7 +82,9 @@ public class HttpRequestHandlingMessagingGatewayWithPathMappingTests extends Abs
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Object result = gateway.doHandleRequest(request, response);
|
||||
RequestEntity<Object> httpEntity = prepareRequestEntity(body, new ServletServerHttpRequest(request));
|
||||
|
||||
Object result = gateway.doHandleRequest(request, httpEntity, response);
|
||||
assertThat(result, instanceOf(Message.class));
|
||||
assertEquals("hello", ((Message<?>) result).getPayload());
|
||||
|
||||
@@ -97,7 +103,8 @@ public class HttpRequestHandlingMessagingGatewayWithPathMappingTests extends Abs
|
||||
request.setMethod("POST");
|
||||
request.setContentType("text/plain");
|
||||
request.setParameter("foo", "bar");
|
||||
request.setContent("hello".getBytes());
|
||||
String body = "hello";
|
||||
request.setContent(body.getBytes());
|
||||
|
||||
String requestURI = "/fname/bill/lname/clinton";
|
||||
|
||||
@@ -120,7 +127,9 @@ public class HttpRequestHandlingMessagingGatewayWithPathMappingTests extends Abs
|
||||
gateway.afterPropertiesSet();
|
||||
gateway.start();
|
||||
|
||||
Object result = gateway.doHandleRequest(request, response);
|
||||
RequestEntity<Object> httpEntity = prepareRequestEntity(body, new ServletServerHttpRequest(request));
|
||||
|
||||
Object result = gateway.doHandleRequest(request, httpEntity, response);
|
||||
assertThat(result, instanceOf(Message.class));
|
||||
assertEquals("bill", ((Message<?>) result).getPayload());
|
||||
}
|
||||
@@ -140,7 +149,8 @@ public class HttpRequestHandlingMessagingGatewayWithPathMappingTests extends Abs
|
||||
request.setMethod("POST");
|
||||
request.setContentType("text/plain");
|
||||
request.setParameter("foo", "bar");
|
||||
request.setContent("hello".getBytes());
|
||||
String body = "hello";
|
||||
request.setContent(body.getBytes());
|
||||
|
||||
String requestURI = "/fname/bill/lname/clinton";
|
||||
|
||||
@@ -163,9 +173,15 @@ public class HttpRequestHandlingMessagingGatewayWithPathMappingTests extends Abs
|
||||
gateway.afterPropertiesSet();
|
||||
gateway.start();
|
||||
|
||||
Object result = gateway.doHandleRequest(request, response);
|
||||
RequestEntity<Object> httpEntity = prepareRequestEntity(body, new ServletServerHttpRequest(request));
|
||||
|
||||
Object result = gateway.doHandleRequest(request, httpEntity, response);
|
||||
assertThat(result, instanceOf(Message.class));
|
||||
assertEquals("bill", ((Map<String, Object>) ((Message<?>) result).getPayload()).get("f"));
|
||||
}
|
||||
|
||||
private static RequestEntity<Object> prepareRequestEntity(Object body, ServletServerHttpRequest request) throws IOException {
|
||||
return new RequestEntity<>(body, request.getHeaders(), request.getMethod(), request.getURI());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@ import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
@@ -63,6 +63,7 @@ import org.springframework.web.server.WebHandler;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
/**
|
||||
* A {@link MessagingGatewaySupport} implementation for Spring WebFlux
|
||||
@@ -151,16 +152,18 @@ public class WebFluxInboundEndpoint extends BaseHttpInboundEndpoint implements W
|
||||
return extractRequestBody(exchange)
|
||||
.doOnSubscribe(s -> this.activeCount.incrementAndGet())
|
||||
.switchIfEmpty(Mono.just(exchange.getRequest().getQueryParams()))
|
||||
.map(body -> new HttpEntity<>(body, exchange.getRequest().getHeaders()))
|
||||
.map(body ->
|
||||
new RequestEntity<>(body, exchange.getRequest().getHeaders(),
|
||||
exchange.getRequest().getMethod(), exchange.getRequest().getURI()))
|
||||
.flatMap(entity -> buildMessage(entity, exchange))
|
||||
.flatMap(requestMessage -> {
|
||||
.flatMap(requestTuple -> {
|
||||
if (this.expectReply) {
|
||||
return sendAndReceiveMessageReactive(requestMessage)
|
||||
return sendAndReceiveMessageReactive(requestTuple.getT1())
|
||||
.flatMap(replyMessage -> populateResponse(exchange, replyMessage));
|
||||
}
|
||||
else {
|
||||
send(requestMessage);
|
||||
return setStatusCode(exchange);
|
||||
send(requestTuple.getT1());
|
||||
return setStatusCode(exchange, requestTuple.getT2());
|
||||
}
|
||||
})
|
||||
.doOnTerminate(this.activeCount::decrementAndGet);
|
||||
@@ -235,7 +238,9 @@ public class WebFluxInboundEndpoint extends BaseHttpInboundEndpoint implements W
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Mono<Message<?>> buildMessage(HttpEntity<?> httpEntity, ServerWebExchange exchange) {
|
||||
private Mono<Tuple2<Message<Object>, RequestEntity<?>>> buildMessage(RequestEntity<?> httpEntity,
|
||||
ServerWebExchange exchange) {
|
||||
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
HttpHeaders requestHeaders = request.getHeaders();
|
||||
Map<String, Object> exchangeAttributes = exchange.getAttributes();
|
||||
@@ -258,7 +263,8 @@ public class WebFluxInboundEndpoint extends BaseHttpInboundEndpoint implements W
|
||||
}
|
||||
|
||||
Map<String, MultiValueMap<String, String>> matrixVariables =
|
||||
(Map<String, MultiValueMap<String, String>>) exchangeAttributes.get(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE);
|
||||
(Map<String, MultiValueMap<String, String>>) exchangeAttributes
|
||||
.get(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE);
|
||||
|
||||
if (!CollectionUtils.isEmpty(matrixVariables)) {
|
||||
evaluationContext.setVariable("matrixVariables", matrixVariables);
|
||||
@@ -314,7 +320,8 @@ public class WebFluxInboundEndpoint extends BaseHttpInboundEndpoint implements W
|
||||
messageBuilder
|
||||
.setHeader(org.springframework.integration.http.HttpHeaders.USER_PRINCIPAL, principal))
|
||||
.defaultIfEmpty(messageBuilder)
|
||||
.map(AbstractIntegrationMessageBuilder::build);
|
||||
.map(AbstractIntegrationMessageBuilder::build)
|
||||
.zipWith(Mono.just(httpEntity));
|
||||
}
|
||||
|
||||
private Mono<Void> populateResponse(ServerWebExchange exchange, Message<?> replyMessage) {
|
||||
@@ -481,10 +488,10 @@ public class WebFluxInboundEndpoint extends BaseHttpInboundEndpoint implements W
|
||||
}
|
||||
|
||||
|
||||
private Mono<Void> setStatusCode(ServerWebExchange exchange) {
|
||||
private Mono<Void> setStatusCode(ServerWebExchange exchange, RequestEntity<?> requestEntity) {
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
if (getStatusCodeExpression() != null) {
|
||||
HttpStatus httpStatus = evaluateHttpStatus();
|
||||
HttpStatus httpStatus = evaluateHttpStatus(requestEntity);
|
||||
if (httpStatus != null) {
|
||||
response.setStatusCode(httpStatus);
|
||||
}
|
||||
|
||||
@@ -355,7 +355,10 @@ public class WebFluxDslTests {
|
||||
.from(WebFlux.inboundChannelAdapter("/reactivePost")
|
||||
.requestMapping(m -> m.methods(HttpMethod.POST))
|
||||
.requestPayloadType(ResolvableType.forClassWithGenerics(Flux.class, String.class))
|
||||
.statusCodeFunction(m -> HttpStatus.ACCEPTED))
|
||||
.statusCodeFunction(e ->
|
||||
HttpMethod.POST.equals(e.getMethod())
|
||||
? HttpStatus.ACCEPTED
|
||||
: HttpStatus.BAD_REQUEST))
|
||||
.channel(c -> c.queue("storeChannel"))
|
||||
.get();
|
||||
}
|
||||
|
||||
@@ -360,10 +360,11 @@ instances of which can be injected into the `HttpRequestHandlingEndpointSupport`
|
||||
|
||||
Starting with version 4.1, you can configure the `<http:inbound-channel-adapter>` with a `status-code-expression` to override the default `200 OK` status.
|
||||
The expression must return an object that can be converted to an `org.springframework.http.HttpStatus` enum value.
|
||||
The `evaluationContext` has a `BeanResolver` but no variables, so the usage of this attribute is somewhat limited.
|
||||
The `evaluationContext` has a `BeanResolver` and, starting with version 5.1, is supplied with the `RequestEntity<?>` as root object.
|
||||
An example might be to resolve, at runtime, some scoped bean that returns a status code value.
|
||||
However, most likely, it is set to a fixed value such as `status-code=expression="204"` (No Content), or `status-code-expression="T(org.springframework.http.HttpStatus).NO_CONTENT"`.
|
||||
By default, `status-code-expression` is null, meaning that the normal '200 OK' response status is returned.
|
||||
Using the `RequestEntity<?>` as root object, the status code can be conditional e.g. on the request method, some header, URI content or even request body.
|
||||
The following example shows how to set the status code to `ACCEPTED`:
|
||||
|
||||
====
|
||||
|
||||
@@ -165,3 +165,10 @@ When a `JmsMessageDrivenEndpoint` or `JmsInboundGateway` is stopped, the associa
|
||||
You can configure the endpoints to revert to the previous behavior.
|
||||
|
||||
See <<jms>> for more information.
|
||||
|
||||
[[x51.-http]]
|
||||
=== HTTP/WebFlux Support
|
||||
|
||||
The `statusCodeExpression` (and `Function`) is now supplied with the `RequestEntity<?>` as a root object for evaluation context, so request headers, method, URI and body are available for target status code calculation.
|
||||
|
||||
See <<http>> and <<webflux>> for more information.
|
||||
|
||||
Reference in New Issue
Block a user