From 3786d4e1b11db116decb8852a792fd452e978893 Mon Sep 17 00:00:00 2001 From: rozagerardo Date: Sun, 8 Jul 2018 05:40:02 -0300 Subject: [PATCH] * Added code for BAEL-1972 (#4632) --- .../controllers/ResponseHeaderController.java | 35 ++++++ .../filter/AddResponseHeaderWebFilter.java | 20 ++++ .../handlers/ResponseHeaderHandler.java | 21 ++++ .../ResponseHeadersRouterFunctions.java | 20 ++++ .../ResponseHeaderLiveTest.java | 63 +++++++++++ .../ResponseHeadersApplication.java | 14 +++ .../FilterResponseHeaderController.java | 24 ++++ .../controllers/ResponseHeaderController.java | 70 ++++++++++++ .../filter/AddResponseHeaderFilter.java | 41 +++++++ .../ResponseHeaderLiveTest.java | 103 ++++++++++++++++++ 10 files changed, 411 insertions(+) create mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/controllers/ResponseHeaderController.java create mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/filter/AddResponseHeaderWebFilter.java create mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/handlers/ResponseHeaderHandler.java create mode 100644 spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/routers/ResponseHeadersRouterFunctions.java create mode 100644 spring-5-reactive/src/test/java/com/baeldung/reactive/responseheaders/ResponseHeaderLiveTest.java create mode 100644 spring-rest/src/main/java/com/baeldung/responseheaders/ResponseHeadersApplication.java create mode 100644 spring-rest/src/main/java/com/baeldung/responseheaders/controllers/FilterResponseHeaderController.java create mode 100644 spring-rest/src/main/java/com/baeldung/responseheaders/controllers/ResponseHeaderController.java create mode 100644 spring-rest/src/main/java/com/baeldung/responseheaders/filter/AddResponseHeaderFilter.java create mode 100644 spring-rest/src/test/java/com/baeldung/responseheaders/ResponseHeaderLiveTest.java diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/controllers/ResponseHeaderController.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/controllers/ResponseHeaderController.java new file mode 100644 index 0000000000..5220ea2f4c --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/controllers/ResponseHeaderController.java @@ -0,0 +1,35 @@ +package com.baeldung.reactive.responseheaders.controllers; + +import org.springframework.http.ResponseEntity; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import reactor.core.publisher.Mono; + +@RestController +@RequestMapping("/response-header") +public class ResponseHeaderController { + + @GetMapping("/response-entity") + public Mono> usingResponseEntityBuilder() { + String responseHeaderKey = "Baeldung-Example-Header"; + String responseHeaderValue = "Value-ResponseEntityBuilder"; + String responseBody = "Response with header using ResponseEntity (builder)"; + + return Mono.just(ResponseEntity.ok() + .header(responseHeaderKey, responseHeaderValue) + .body(responseBody)); + } + + @GetMapping("/server-http-response") + public Mono usingServerHttpResponse(ServerHttpResponse response) { + String responseHeaderKey = "Baeldung-Example-Header"; + String responseHeaderValue = "Value-ServerHttpResponse"; + String responseBody = "Response with header using ServerHttpResponse"; + + response.getHeaders().add(responseHeaderKey, responseHeaderValue); + return Mono.just(responseBody); + } +} diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/filter/AddResponseHeaderWebFilter.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/filter/AddResponseHeaderWebFilter.java new file mode 100644 index 0000000000..8d8484f5cd --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/filter/AddResponseHeaderWebFilter.java @@ -0,0 +1,20 @@ +package com.baeldung.reactive.responseheaders.filter; + +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; + +import reactor.core.publisher.Mono; + +@Component +public class AddResponseHeaderWebFilter implements WebFilter { + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + exchange.getResponse() + .getHeaders() + .add("Baeldung-Example-Filter-Header", "Value-Filter"); + return chain.filter(exchange); + } +} diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/handlers/ResponseHeaderHandler.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/handlers/ResponseHeaderHandler.java new file mode 100644 index 0000000000..20f76d3b6e --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/handlers/ResponseHeaderHandler.java @@ -0,0 +1,21 @@ +package com.baeldung.reactive.responseheaders.functional.handlers; + +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; + +import reactor.core.publisher.Mono; + +@Component +public class ResponseHeaderHandler { + + public Mono useHandler(final ServerRequest request) { + String responseHeaderKey = "Baeldung-Example-Header"; + String responseHeaderValue = "Value-Handler"; + String responseBody = "Response with header using Handler"; + + return ServerResponse.ok() + .header(responseHeaderKey, responseHeaderValue) + .body(Mono.just(responseBody),String.class); + } +} diff --git a/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/routers/ResponseHeadersRouterFunctions.java b/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/routers/ResponseHeadersRouterFunctions.java new file mode 100644 index 0000000000..63f7c7f036 --- /dev/null +++ b/spring-5-reactive/src/main/java/com/baeldung/reactive/responseheaders/functional/routers/ResponseHeadersRouterFunctions.java @@ -0,0 +1,20 @@ +package com.baeldung.reactive.responseheaders.functional.routers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.server.RequestPredicates; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; + +import com.baeldung.reactive.responseheaders.functional.handlers.ResponseHeaderHandler; + +@Configuration +public class ResponseHeadersRouterFunctions { + + @Bean + public RouterFunction responseHeaderRoute(@Autowired ResponseHeaderHandler handler) { + return RouterFunctions.route(RequestPredicates.GET("/functional-response-header/single-handler"), handler::useHandler); + } +} diff --git a/spring-5-reactive/src/test/java/com/baeldung/reactive/responseheaders/ResponseHeaderLiveTest.java b/spring-5-reactive/src/test/java/com/baeldung/reactive/responseheaders/ResponseHeaderLiveTest.java new file mode 100644 index 0000000000..db563e27d1 --- /dev/null +++ b/spring-5-reactive/src/test/java/com/baeldung/reactive/responseheaders/ResponseHeaderLiveTest.java @@ -0,0 +1,63 @@ +package com.baeldung.reactive.responseheaders; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class ResponseHeaderLiveTest { + + private static final String BASE_URL = "http://localhost:8080"; + private static final String ANNOTATION_BASE_URL = BASE_URL + "/response-header"; + private static final String FUNCTIONAL_BASE_URL = BASE_URL + "/functional-response-header"; + private static final String SERVICE_SINGLE_RESPONSE_HEADER = "Baeldung-Example-Header"; + private static final String SERVICE_FILTER_RESPONSE_HEADER = "Baeldung-Example-Filter-Header"; + private static final String SERVICE_FILTER_RESPONSE_HEADER_VALUE = "Value-Filter"; + + private static WebTestClient client; + + @BeforeAll + public static void setup() { + client = WebTestClient.bindToServer() + .baseUrl(BASE_URL) + .build(); + } + + @Test + public void whenUsingResponseEntityBuilderRequest_thenObtainResponseWithCorrectHeaders() { + client = WebTestClient.bindToServer() + .baseUrl(BASE_URL) + .build(); + ResponseSpec response = client.get() + .uri(ANNOTATION_BASE_URL + "/response-entity") + .exchange(); + + response.expectHeader().valueEquals(SERVICE_SINGLE_RESPONSE_HEADER, "Value-ResponseEntityBuilder") + .expectHeader().valueEquals(SERVICE_FILTER_RESPONSE_HEADER, SERVICE_FILTER_RESPONSE_HEADER_VALUE); + } + + @Test + public void whenUsingServerHttpResponseRequest_thenObtainResponseWithCorrectHeaders() { + ResponseSpec response = client.get() + .uri(ANNOTATION_BASE_URL + "/server-http-response") + .exchange(); + + response.expectHeader().valueEquals(SERVICE_SINGLE_RESPONSE_HEADER, "Value-ServerHttpResponse") + .expectHeader().valueEquals(SERVICE_FILTER_RESPONSE_HEADER, SERVICE_FILTER_RESPONSE_HEADER_VALUE); + } + + @Test + public void whenUsingFunctionalHandlerRequest_thenObtainResponseWithCorrectHeaders() { + ResponseSpec response = client.get() + .uri(FUNCTIONAL_BASE_URL + "/single-handler") + .exchange(); + + response.expectHeader().valueEquals(SERVICE_SINGLE_RESPONSE_HEADER, "Value-Handler") + .expectHeader().valueEquals(SERVICE_FILTER_RESPONSE_HEADER, SERVICE_FILTER_RESPONSE_HEADER_VALUE); + } +} diff --git a/spring-rest/src/main/java/com/baeldung/responseheaders/ResponseHeadersApplication.java b/spring-rest/src/main/java/com/baeldung/responseheaders/ResponseHeadersApplication.java new file mode 100644 index 0000000000..ebc18a130b --- /dev/null +++ b/spring-rest/src/main/java/com/baeldung/responseheaders/ResponseHeadersApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.responseheaders; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.ServletComponentScan; + +@ServletComponentScan +@SpringBootApplication +public class ResponseHeadersApplication { + + public static void main(String[] args) { + SpringApplication.run(ResponseHeadersApplication.class, args); + } +} diff --git a/spring-rest/src/main/java/com/baeldung/responseheaders/controllers/FilterResponseHeaderController.java b/spring-rest/src/main/java/com/baeldung/responseheaders/controllers/FilterResponseHeaderController.java new file mode 100644 index 0000000000..c92d4afafd --- /dev/null +++ b/spring-rest/src/main/java/com/baeldung/responseheaders/controllers/FilterResponseHeaderController.java @@ -0,0 +1,24 @@ +package com.baeldung.responseheaders.controllers; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/filter-response-header") +public class FilterResponseHeaderController { + + @GetMapping("/no-extra-header") + public String FilterHeaderResponseWithNoExtraHeader() { + return "Response body with Filter header and no extra header"; + } + + @GetMapping("/extra-header") + public String FilterHeaderResponseWithExtraHeader(HttpServletResponse response) { + response.addHeader("Baeldung-Example-Header", "Value-ExtraHeader"); + return "Response body with Filter header and one extra header"; + } + +} diff --git a/spring-rest/src/main/java/com/baeldung/responseheaders/controllers/ResponseHeaderController.java b/spring-rest/src/main/java/com/baeldung/responseheaders/controllers/ResponseHeaderController.java new file mode 100644 index 0000000000..d93964b815 --- /dev/null +++ b/spring-rest/src/main/java/com/baeldung/responseheaders/controllers/ResponseHeaderController.java @@ -0,0 +1,70 @@ +package com.baeldung.responseheaders.controllers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/single-response-header") +public class ResponseHeaderController { + + @GetMapping("/http-servlet-response") + public String usingHttpServletResponse(HttpServletResponse response) { + response.addHeader("Baeldung-Example-Header", "Value-HttpServletResponse"); + return "Response with header using HttpServletResponse"; + } + + @GetMapping("/response-entity-constructor") + public ResponseEntity usingResponseEntityConstructor() { + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.set("Baeldung-Example-Header", "Value-ResponseEntityContructor"); + String responseBody = "Response with header using ResponseEntity (constructor)"; + HttpStatus responseStatus = HttpStatus.OK; + + return new ResponseEntity(responseBody, responseHeaders, responseStatus); + } + + @GetMapping("/response-entity-contructor-multiple-headers") + public ResponseEntity usingResponseEntityConstructorAndMultipleHeaders() { + List acceptableMediaTypes = new ArrayList<>(Arrays.asList(MediaType.APPLICATION_JSON)); + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.set("Baeldung-Example-Header", "Value-ResponseEntityConstructorAndHeaders"); + responseHeaders.setAccept(acceptableMediaTypes); + String responseBody = "Response with header using ResponseEntity (constructor)"; + HttpStatus responseStatus = HttpStatus.OK; + + return new ResponseEntity(responseBody, responseHeaders, responseStatus); + } + + @GetMapping("/response-entity-builder") + public ResponseEntity usingResponseEntityBuilder() { + String responseHeaderKey = "Baeldung-Example-Header"; + String responseHeaderValue = "Value-ResponseEntityBuilder"; + String responseBody = "Response with header using ResponseEntity (builder)"; + + return ResponseEntity.ok() + .header(responseHeaderKey, responseHeaderValue) + .body(responseBody); + } + + @GetMapping("/response-entity-builder-with-http-headers") + public ResponseEntity usingResponseEntityBuilderAndHttpHeaders() { + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.set("Baeldung-Example-Header", "Value-ResponseEntityBuilderWithHttpHeaders"); + String responseBody = "Response with header using ResponseEntity (builder)"; + + return ResponseEntity.ok() + .headers(responseHeaders) + .body(responseBody); + } +} diff --git a/spring-rest/src/main/java/com/baeldung/responseheaders/filter/AddResponseHeaderFilter.java b/spring-rest/src/main/java/com/baeldung/responseheaders/filter/AddResponseHeaderFilter.java new file mode 100644 index 0000000000..7d4ffb1391 --- /dev/null +++ b/spring-rest/src/main/java/com/baeldung/responseheaders/filter/AddResponseHeaderFilter.java @@ -0,0 +1,41 @@ +package com.baeldung.responseheaders.filter; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@WebFilter("/filter-response-header/*") +public class AddResponseHeaderFilter implements Filter { + + private static final Logger LOGGER = LoggerFactory.getLogger(AddResponseHeaderFilter.class); + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // add special initialization requirements here + LOGGER.trace("Initializing filter..."); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletResponse httpServletResponse = (HttpServletResponse) response; + httpServletResponse.setHeader("Baeldung-Example-Filter-Header", "Value-Filter"); + chain.doFilter(request, response); + } + + @Override + public void destroy() { + // clean up any resource being held by the filter here + LOGGER.trace("Destroying filter..."); + } + +} diff --git a/spring-rest/src/test/java/com/baeldung/responseheaders/ResponseHeaderLiveTest.java b/spring-rest/src/test/java/com/baeldung/responseheaders/ResponseHeaderLiveTest.java new file mode 100644 index 0000000000..bed0de55bd --- /dev/null +++ b/spring-rest/src/test/java/com/baeldung/responseheaders/ResponseHeaderLiveTest.java @@ -0,0 +1,103 @@ +package com.baeldung.responseheaders; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +public class ResponseHeaderLiveTest { + + private static final String BASE_URL = "http://localhost:8082/spring-rest"; + private static final String SINGLE_BASE_URL = BASE_URL + "/single-response-header"; + private static final String FILTER_BASE_URL = BASE_URL + "/filter-response-header"; + private static final String SERVICE_SINGLE_RESPONSE_HEADER = "Baeldung-Example-Header"; + private static final String SERVICE_FILTER_RESPONSE_HEADER = "Baeldung-Example-Filter-Header"; + + @Autowired + private TestRestTemplate template; + + @Test + public void whenHttpServletResponseRequest_thenObtainResponseWithCorrectHeader() { + final String requestUrl = "/http-servlet-response"; + ResponseEntity response = template.getForEntity(SINGLE_BASE_URL + requestUrl, String.class); + HttpHeaders responseHeaders = response.getHeaders(); + + assertThat(responseHeaders).isNotEmpty(); + assertThat(responseHeaders).containsEntry(SERVICE_SINGLE_RESPONSE_HEADER, Arrays.asList("Value-HttpServletResponse")); + } + + @Test + public void whenResponseEntityConstructorRequest_thenObtainResponseWithCorrectHeader() { + final String requestUrl = "/response-entity-constructor"; + ResponseEntity response = template.getForEntity(SINGLE_BASE_URL + requestUrl, String.class); + HttpHeaders responseHeaders = response.getHeaders(); + + assertThat(responseHeaders).isNotEmpty(); + assertThat(responseHeaders).containsEntry(SERVICE_SINGLE_RESPONSE_HEADER, Arrays.asList("Value-ResponseEntityContructor")); + } + + @Test + public void whenResponseEntityConstructorAndMultipleHeadersRequest_thenObtainResponseWithCorrectHeaders() { + final String requestUrl = "/response-entity-contructor-multiple-headers"; + ResponseEntity response = template.getForEntity(SINGLE_BASE_URL + requestUrl, String.class); + HttpHeaders responseHeaders = response.getHeaders(); + + assertThat(responseHeaders).isNotEmpty(); + assertThat(responseHeaders).containsEntry(SERVICE_SINGLE_RESPONSE_HEADER, Arrays.asList("Value-ResponseEntityConstructorAndHeaders")); + assertThat(responseHeaders).containsEntry("Accept", Arrays.asList(MediaType.APPLICATION_JSON.toString())); + } + + @Test + public void whenResponseEntityBuilderRequest_thenObtainResponseWithCorrectHeader() { + final String requestUrl = "/response-entity-builder"; + ResponseEntity response = template.getForEntity(SINGLE_BASE_URL + requestUrl, String.class); + HttpHeaders responseHeaders = response.getHeaders(); + + assertThat(responseHeaders).isNotEmpty(); + assertThat(responseHeaders).containsEntry(SERVICE_SINGLE_RESPONSE_HEADER, Arrays.asList("Value-ResponseEntityBuilder")); + } + + @Test + public void whenResponseEntityBuilderAndHttpHeadersRequest_thenObtainResponseWithCorrectHeader() { + final String requestUrl = "/response-entity-builder-with-http-headers"; + ResponseEntity response = template.getForEntity(SINGLE_BASE_URL + requestUrl, String.class); + HttpHeaders responseHeaders = response.getHeaders(); + + assertThat(responseHeaders).isNotEmpty(); + assertThat(responseHeaders).containsEntry(SERVICE_SINGLE_RESPONSE_HEADER, Arrays.asList("Value-ResponseEntityBuilderWithHttpHeaders")); + } + + @Test + public void whenFilterWithNoExtraHeaderRequest_thenObtainResponseWithCorrectHeader() { + final String requestUrl = "/no-extra-header"; + ResponseEntity response = template.getForEntity(FILTER_BASE_URL + requestUrl, String.class); + HttpHeaders responseHeaders = response.getHeaders(); + + assertThat(responseHeaders).isNotEmpty(); + assertThat(responseHeaders).containsEntry(SERVICE_FILTER_RESPONSE_HEADER, Arrays.asList("Value-Filter")); + } + + @Test + public void whenFilterWithExtraHeaderRequest_thenObtainResponseWithCorrectHeaders() { + final String requestUrl = "/extra-header"; + ResponseEntity response = template.getForEntity(FILTER_BASE_URL + requestUrl, String.class); + HttpHeaders responseHeaders = response.getHeaders(); + + assertThat(responseHeaders).isNotEmpty(); + assertThat(responseHeaders).containsEntry(SERVICE_FILTER_RESPONSE_HEADER, Arrays.asList("Value-Filter")); + assertThat(responseHeaders).containsEntry(SERVICE_SINGLE_RESPONSE_HEADER, Arrays.asList("Value-ExtraHeader")); + } + +}