From 75e9acc874ef3a54b0c590080af95b7b2874b774 Mon Sep 17 00:00:00 2001 From: Trixi Turny Date: Sun, 1 Aug 2021 14:26:57 +0100 Subject: [PATCH 1/4] BAEL-5054 2 examples of file upload with webclient --- webclient_upload/pom.xml | 76 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 webclient_upload/pom.xml diff --git a/webclient_upload/pom.xml b/webclient_upload/pom.xml new file mode 100644 index 0000000000..69f7f78cd1 --- /dev/null +++ b/webclient_upload/pom.xml @@ -0,0 +1,76 @@ + + + + 4.0.0 + + com.baeldung + webclient_upload + 1.0-SNAPSHOT + jar + + + + org.springframework.boot + spring-boot-starter-parent + 2.5.0 + + + webclient_upload Maven Webapp + + 16 + 1.0.1.RELEASE + + + + + + + org.projectreactor + reactor-spring + ${reactor-spring.version} + + + + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-webflux + + + org.projectreactor + reactor-spring + + + org.springframework.boot + spring-boot-starter-test + test + + + io.rest-assured + json-schema-validator + test + + + org.springframework.boot + spring-boot-starter-web + + + + + From 638d34924ba3cf06e6d274684f4a4a1a2a6ab720 Mon Sep 17 00:00:00 2001 From: Trixi Turny Date: Sun, 1 Aug 2021 14:28:51 +0100 Subject: [PATCH 2/4] BAEL-5054 make sure all files are added BAEL-5054 organise packages BAEL-5054 move project to correct folder BAEL-5044 remove old folder --- spring-5-reactive-client/pom.xml | 2 +- .../com/baeldung/reactive/Application.java | 12 +++ .../reactive/controller/UploadController.java | 47 ++++++++++++ .../service/ReactiveUploadService.java | 69 +++++++++++++++++ .../src/main/resources/application.properties | 2 +- webclient_upload/pom.xml | 76 ------------------- 6 files changed, 130 insertions(+), 78 deletions(-) create mode 100644 spring-5-reactive-client/src/main/java/com/baeldung/reactive/Application.java create mode 100644 spring-5-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java create mode 100644 spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java delete mode 100644 webclient_upload/pom.xml diff --git a/spring-5-reactive-client/pom.xml b/spring-5-reactive-client/pom.xml index 136f31b49e..6a0a2d6fe3 100644 --- a/spring-5-reactive-client/pom.xml +++ b/spring-5-reactive-client/pom.xml @@ -133,7 +133,7 @@ org.springframework.boot spring-boot-maven-plugin - com.baeldung.Spring5Application + com.baeldung.reactive.Application JAR diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/Application.java b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/Application.java new file mode 100644 index 0000000000..65e497b519 --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/Application.java @@ -0,0 +1,12 @@ +package com.baeldung.reactive; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} + diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java new file mode 100644 index 0000000000..71cea35685 --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java @@ -0,0 +1,47 @@ +package com.baeldung.reactive.controller; + + +import com.baeldung.reactive.service.ReactiveUploadService; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import reactor.core.publisher.Mono; + + +@RestController +public class UploadController { + final ReactiveUploadService uploadService; + + public UploadController(ReactiveUploadService uploadService) { + this.uploadService = uploadService; + } + + @PostMapping(path = "/upload") + @ResponseBody + public Mono uploadPdf(@RequestParam("file") final MultipartFile multipartFile) { + return uploadService.uploadPdf(multipartFile.getResource()); + } + + @PostMapping(path = "/upload/multipart") + @ResponseBody + public Mono uploadMultipart(@RequestParam("file") final MultipartFile multipartFile) { + return uploadService.uploadMultipart(multipartFile); + } + + + /** + * Fake upload endpoint returning "OK" HttpStatus + * @return "OK" HttpStatus + */ + @PostMapping(path = "/external/upload") + @ResponseBody + public HttpStatus externalUpload() { + return HttpStatus.OK; + } + + @GetMapping("/trixi") + public String returnTrixi() { + return "Trixi"; + + } +} diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java new file mode 100644 index 0000000000..e31674282b --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java @@ -0,0 +1,69 @@ +package com.baeldung.reactive.service; + + +import org.springframework.core.io.Resource; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.client.MultipartBodyBuilder; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.util.UriComponentsBuilder; +import reactor.core.publisher.Mono; + +import java.net.URI; + +@Service +public class ReactiveUploadService { + + private final WebClient webClient; + private static final String EXTERNAL_UPLOAD_URL = "http://localhost:8080/external/upload"; + + public ReactiveUploadService() { + this.webClient = WebClient.create(); + } + + + public Mono uploadPdf(final Resource resource){ + + final URI url = UriComponentsBuilder.fromHttpUrl(EXTERNAL_UPLOAD_URL).build().toUri(); + Mono httpStatusMono = webClient.post() + .uri(url) + .contentType(MediaType.APPLICATION_PDF) + .body(BodyInserters.fromResource(resource)) + .exchangeToMono(response -> { + if (response.statusCode().equals(HttpStatus.OK)) { + return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode()); + } else { + System.out.println("Failed to upload pdf. " + response.statusCode()); + } + return null; + }); + return httpStatusMono; + } + + + public Mono uploadMultipart(final MultipartFile multipartFile){ + final URI url = UriComponentsBuilder.fromHttpUrl(EXTERNAL_UPLOAD_URL).build().toUri(); + + final MultipartBodyBuilder builder = new MultipartBodyBuilder(); + builder.part("file", multipartFile.getResource()); + + Mono httpStatusMono = webClient.post() + .uri(url) + .contentType(MediaType.MULTIPART_FORM_DATA) + .body(BodyInserters.fromMultipartData(builder.build())) + .exchangeToMono(response -> { + if (response.statusCode().equals(HttpStatus.OK)) { + return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode()); + } else { + System.out.println("Failed to upload pdf. " + response.statusCode()); + } + return null; + }); + return httpStatusMono; + } + + +} diff --git a/spring-5-reactive-client/src/main/resources/application.properties b/spring-5-reactive-client/src/main/resources/application.properties index 05033054b1..7859537230 100644 --- a/spring-5-reactive-client/src/main/resources/application.properties +++ b/spring-5-reactive-client/src/main/resources/application.properties @@ -1,5 +1,5 @@ logging.level.root=INFO -server.port=8081 +server.port=8080 logging.level.reactor.netty.http.client.HttpClient=DEBUG \ No newline at end of file diff --git a/webclient_upload/pom.xml b/webclient_upload/pom.xml deleted file mode 100644 index 69f7f78cd1..0000000000 --- a/webclient_upload/pom.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - 4.0.0 - - com.baeldung - webclient_upload - 1.0-SNAPSHOT - jar - - - - org.springframework.boot - spring-boot-starter-parent - 2.5.0 - - - webclient_upload Maven Webapp - - 16 - 1.0.1.RELEASE - - - - - - - org.projectreactor - reactor-spring - ${reactor-spring.version} - - - - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-webflux - - - org.projectreactor - reactor-spring - - - org.springframework.boot - spring-boot-starter-test - test - - - io.rest-assured - json-schema-validator - test - - - org.springframework.boot - spring-boot-starter-web - - - - - From 82c3389ba042400766dd94f3223936729fa86533 Mon Sep 17 00:00:00 2001 From: Trixi Turny Date: Sun, 22 Aug 2021 22:08:17 +0100 Subject: [PATCH 3/4] BAEL-5054 throw ServiceException when not OK BAEL-5054 fix test name and tidy indent BAEL-5054 remove unnecessary changes BAEL-5054 restore main class name BAEL-5054 rename test to end with UnitTest --- spring-5-reactive-client/pom.xml | 2 +- .../com/baeldung/reactive/Application.java | 12 ----- .../reactive/controller/UploadController.java | 17 ------ .../reactive/exception/ServiceException.java | 8 +++ .../service/ReactiveUploadService.java | 53 +++++++++---------- .../src/main/resources/application.properties | 2 +- .../ReactiveUploadServiceUnitTest.java | 44 +++++++++++++++ 7 files changed, 79 insertions(+), 59 deletions(-) delete mode 100644 spring-5-reactive-client/src/main/java/com/baeldung/reactive/Application.java create mode 100644 spring-5-reactive-client/src/main/java/com/baeldung/reactive/exception/ServiceException.java create mode 100644 spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java diff --git a/spring-5-reactive-client/pom.xml b/spring-5-reactive-client/pom.xml index 6a0a2d6fe3..136f31b49e 100644 --- a/spring-5-reactive-client/pom.xml +++ b/spring-5-reactive-client/pom.xml @@ -133,7 +133,7 @@ org.springframework.boot spring-boot-maven-plugin - com.baeldung.reactive.Application + com.baeldung.Spring5Application JAR diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/Application.java b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/Application.java deleted file mode 100644 index 65e497b519..0000000000 --- a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/Application.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.baeldung.reactive; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application { - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} - diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java index 71cea35685..08d6ff55ef 100644 --- a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java +++ b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/controller/UploadController.java @@ -27,21 +27,4 @@ public class UploadController { public Mono uploadMultipart(@RequestParam("file") final MultipartFile multipartFile) { return uploadService.uploadMultipart(multipartFile); } - - - /** - * Fake upload endpoint returning "OK" HttpStatus - * @return "OK" HttpStatus - */ - @PostMapping(path = "/external/upload") - @ResponseBody - public HttpStatus externalUpload() { - return HttpStatus.OK; - } - - @GetMapping("/trixi") - public String returnTrixi() { - return "Trixi"; - - } } diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/exception/ServiceException.java b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/exception/ServiceException.java new file mode 100644 index 0000000000..cd639ec1f9 --- /dev/null +++ b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/exception/ServiceException.java @@ -0,0 +1,8 @@ +package com.baeldung.reactive.exception; + +public class ServiceException extends RuntimeException{ + + public ServiceException(String message) { + super(message); + } +} diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java index e31674282b..11409ce986 100644 --- a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java +++ b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java @@ -1,6 +1,7 @@ package com.baeldung.reactive.service; +import com.baeldung.reactive.exception.ServiceException; import org.springframework.core.io.Resource; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -20,50 +21,46 @@ public class ReactiveUploadService { private final WebClient webClient; private static final String EXTERNAL_UPLOAD_URL = "http://localhost:8080/external/upload"; - public ReactiveUploadService() { - this.webClient = WebClient.create(); + public ReactiveUploadService(final WebClient webClient) { + this.webClient = webClient; } - public Mono uploadPdf(final Resource resource){ + public Mono uploadPdf(final Resource resource) { final URI url = UriComponentsBuilder.fromHttpUrl(EXTERNAL_UPLOAD_URL).build().toUri(); Mono httpStatusMono = webClient.post() - .uri(url) - .contentType(MediaType.APPLICATION_PDF) - .body(BodyInserters.fromResource(resource)) - .exchangeToMono(response -> { - if (response.statusCode().equals(HttpStatus.OK)) { - return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode()); - } else { - System.out.println("Failed to upload pdf. " + response.statusCode()); - } - return null; - }); + .uri(url) + .contentType(MediaType.APPLICATION_PDF) + .body(BodyInserters.fromResource(resource)) + .exchangeToMono(response -> { + if (response.statusCode().equals(HttpStatus.OK)) { + return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode()); + } else { + throw new ServiceException("Error uploading file"); + } + }); return httpStatusMono; } - public Mono uploadMultipart(final MultipartFile multipartFile){ + public Mono uploadMultipart(final MultipartFile multipartFile) { final URI url = UriComponentsBuilder.fromHttpUrl(EXTERNAL_UPLOAD_URL).build().toUri(); final MultipartBodyBuilder builder = new MultipartBodyBuilder(); builder.part("file", multipartFile.getResource()); Mono httpStatusMono = webClient.post() - .uri(url) - .contentType(MediaType.MULTIPART_FORM_DATA) - .body(BodyInserters.fromMultipartData(builder.build())) - .exchangeToMono(response -> { - if (response.statusCode().equals(HttpStatus.OK)) { - return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode()); - } else { - System.out.println("Failed to upload pdf. " + response.statusCode()); - } - return null; - }); + .uri(url) + .contentType(MediaType.MULTIPART_FORM_DATA) + .body(BodyInserters.fromMultipartData(builder.build())) + .exchangeToMono(response -> { + if (response.statusCode().equals(HttpStatus.OK)) { + return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode()); + } else { + throw new ServiceException("Error uploading file"); + } + }); return httpStatusMono; } - - } diff --git a/spring-5-reactive-client/src/main/resources/application.properties b/spring-5-reactive-client/src/main/resources/application.properties index 7859537230..05033054b1 100644 --- a/spring-5-reactive-client/src/main/resources/application.properties +++ b/spring-5-reactive-client/src/main/resources/application.properties @@ -1,5 +1,5 @@ logging.level.root=INFO -server.port=8080 +server.port=8081 logging.level.reactor.netty.http.client.HttpClient=DEBUG \ No newline at end of file diff --git a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java new file mode 100644 index 0000000000..0ca59848d7 --- /dev/null +++ b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.reactive.service; + +import org.junit.jupiter.api.Test; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpStatus; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ReactiveUploadServiceUnitTest { + + private static final String BASE_URL = "http://localhost:8080/external/upload"; + + final WebClient webClientMock = WebClient.builder().baseUrl(BASE_URL) + .exchangeFunction(clientRequest -> Mono.just(ClientResponse.create(HttpStatus.OK) + .header("content-type", "application/json") + .build())) + .build(); + + private final ReactiveUploadService tested = new ReactiveUploadService(webClientMock); + + @Test + void givenAPdf_whenUploadingWithWebClient_thenOK() { + final Resource file = mock(Resource.class); + final Mono result = tested.uploadPdf(file); + final HttpStatus status = result.block(); + assertThat(status).isEqualTo(HttpStatus.OK); + } + + @Test + void givenAMultipartPdf_whenUploadingWithWebClient_thenOK() { + final Resource file = mock(Resource.class); + final MultipartFile multipartFile = mock(MultipartFile.class); + when(multipartFile.getResource()).thenReturn(file); + final Mono result = tested.uploadMultipart(multipartFile); + final HttpStatus status = result.block(); + assertThat(status).isEqualTo(HttpStatus.OK); + } +} \ No newline at end of file From 439848c1659da015d6ed55e18313b0916330b11f Mon Sep 17 00:00:00 2001 From: Trixi Turny Date: Sun, 5 Sep 2021 12:55:26 +0200 Subject: [PATCH 4/4] BAEL-5054 fix indentations --- .../service/ReactiveUploadService.java | 20 +++++++++---------- .../ReactiveUploadServiceUnitTest.java | 8 ++++++-- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java index 11409ce986..a12d54960a 100644 --- a/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java +++ b/spring-5-reactive-client/src/main/java/com/baeldung/reactive/service/ReactiveUploadService.java @@ -34,11 +34,11 @@ public class ReactiveUploadService { .contentType(MediaType.APPLICATION_PDF) .body(BodyInserters.fromResource(resource)) .exchangeToMono(response -> { - if (response.statusCode().equals(HttpStatus.OK)) { - return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode()); - } else { - throw new ServiceException("Error uploading file"); - } + if (response.statusCode().equals(HttpStatus.OK)) { + return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode()); + } else { + throw new ServiceException("Error uploading file"); + } }); return httpStatusMono; } @@ -55,11 +55,11 @@ public class ReactiveUploadService { .contentType(MediaType.MULTIPART_FORM_DATA) .body(BodyInserters.fromMultipartData(builder.build())) .exchangeToMono(response -> { - if (response.statusCode().equals(HttpStatus.OK)) { - return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode()); - } else { - throw new ServiceException("Error uploading file"); - } + if (response.statusCode().equals(HttpStatus.OK)) { + return response.bodyToMono(HttpStatus.class).thenReturn(response.statusCode()); + } else { + throw new ServiceException("Error uploading file"); + } }); return httpStatusMono; } diff --git a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java index 0ca59848d7..40c1e40d92 100644 --- a/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java +++ b/spring-5-reactive-client/src/test/java/com/baeldung/reactive/service/ReactiveUploadServiceUnitTest.java @@ -18,8 +18,8 @@ class ReactiveUploadServiceUnitTest { final WebClient webClientMock = WebClient.builder().baseUrl(BASE_URL) .exchangeFunction(clientRequest -> Mono.just(ClientResponse.create(HttpStatus.OK) - .header("content-type", "application/json") - .build())) + .header("content-type", "application/json") + .build())) .build(); private final ReactiveUploadService tested = new ReactiveUploadService(webClientMock); @@ -27,8 +27,10 @@ class ReactiveUploadServiceUnitTest { @Test void givenAPdf_whenUploadingWithWebClient_thenOK() { final Resource file = mock(Resource.class); + final Mono result = tested.uploadPdf(file); final HttpStatus status = result.block(); + assertThat(status).isEqualTo(HttpStatus.OK); } @@ -37,8 +39,10 @@ class ReactiveUploadServiceUnitTest { final Resource file = mock(Resource.class); final MultipartFile multipartFile = mock(MultipartFile.class); when(multipartFile.getResource()).thenReturn(file); + final Mono result = tested.uploadMultipart(multipartFile); final HttpStatus status = result.block(); + assertThat(status).isEqualTo(HttpStatus.OK); } } \ No newline at end of file