BAEL-3188 How to compress requests using the Spring RestTemplate. (#7688)

* BAEL-3188 How to compress requests using the Spring RestTemplate.

* BAEL-3188 How to compress requests using the Spring RestTemplate. Updated README.

* BAEL-3188 How to compress requests using the Spring RestTemplate.

* BAEL-3188 How to compress requests using the Spring RestTemplate.

* BAEL-3188 How to compress requests using the Spring RestTemplate. Updated parent pom to add new module.
This commit is contained in:
hugogiordano 2019-09-04 14:37:40 +10:00 committed by maibin
parent 06cbdfce02
commit 7472127909
12 changed files with 384 additions and 0 deletions

View File

@ -741,6 +741,7 @@
<module>spring-remoting</module>
<module>spring-rest</module>
<module>spring-rest-angular</module>
<module>spring-rest-compress</module>
<module>spring-rest-full</module>
<module>spring-rest-hal-browser</module>
<module>spring-rest-query-language</module>
@ -928,6 +929,7 @@
<module>spring-remoting/remoting-rmi/remoting-rmi-server</module>
<module>spring-rest</module>
<module>spring-rest-angular</module>
<module>spring-rest-compress</module>
<module>spring-rest-full</module>
<module>spring-rest-simple</module>
<module>spring-resttemplate</module>
@ -1433,6 +1435,7 @@
<module>spring-remoting</module>
<module>spring-rest</module>
<module>spring-rest-angular</module>
<module>spring-rest-compress</module>
<module>spring-rest-full</module>
<module>spring-rest-hal-browser</module>
<module>spring-rest-query-language</module>

View File

@ -0,0 +1,5 @@
=========================================================================
## How to compress requests using the Spring RestTemplate Example Project
### Relevant Articles:
- [How to compress requests using the Spring RestTemplate]()

View File

@ -0,0 +1,66 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>parent-boot-2</artifactId>
<groupId>com.baeldung</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-boot-2</relativePath>
</parent>
<groupId>com.baeldung</groupId>
<artifactId>spring-rest-compress</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-rest-compress</name>
<properties>
<java.version>1.8</java.version>
<commons-io.version>2.6</commons-io.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</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>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,38 @@
package org.baeldung.spring.rest.compress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import java.io.IOException;
public class CompressingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
private static final Logger LOG = LoggerFactory.getLogger(CompressingClientHttpRequestInterceptor.class);
private static final String GZIP_ENCODING = "gzip";
/**
* Compress a request body using Gzip and add Http headers.
*
* @param req
* @param body
* @param exec
* @return
* @throws IOException
*/
@Override
public ClientHttpResponse intercept(HttpRequest req, byte[] body, ClientHttpRequestExecution exec)
throws IOException {
LOG.info("Compressing request...");
HttpHeaders httpHeaders = req.getHeaders();
httpHeaders.add(HttpHeaders.CONTENT_ENCODING, GZIP_ENCODING);
httpHeaders.add(HttpHeaders.ACCEPT_ENCODING, GZIP_ENCODING);
return exec.execute(req, GzipUtils.compress(body));
}
}

View File

@ -0,0 +1,56 @@
package org.baeldung.spring.rest.compress;
import org.apache.commons.codec.Charsets;
import org.apache.commons.io.IOUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class GzipUtils {
/**
* Gzip a string.
*
* @param text
* @return
* @throws Exception
*/
public static byte[] compress(String text) throws Exception {
return GzipUtils.compress(text.getBytes(Charsets.UTF_8));
}
/**
* Gzip a byte array.
*
* @param body
* @return
* @throws IOException
*/
public static byte[] compress(byte[] body) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(output)) {
gzipOutputStream.write(body);
}
} finally {
output.close();
}
return output.toByteArray();
}
/**
* Decompress a Gzipped byte array to a String.
*
* @param body
* @return
* @throws IOException
*/
public static String decompress(byte[] body) throws IOException {
try (GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(body))) {
return IOUtils.toString(gzipInputStream, Charsets.UTF_8);
}
}
}

View File

@ -0,0 +1,38 @@
package org.baeldung.spring.rest.compress;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configure Jetty web server so it handles compressed requests.
*/
@Configuration
public class JettyWebServerConfiguration {
private static final int MIN_BYTES = 1;
/**
* Customise the Jetty web server to automatically decompress requests.
*/
@Bean
public JettyServletWebServerFactory jettyServletWebServerFactory() {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.addServerCustomizers(server -> {
GzipHandler gzipHandler = new GzipHandler();
// Enable request decompression
gzipHandler.setInflateBufferSize(MIN_BYTES);
gzipHandler.setHandler(server.getHandler());
HandlerCollection handlerCollection = new HandlerCollection(gzipHandler);
server.setHandler(handlerCollection);
});
return factory;
}
}

View File

@ -0,0 +1,29 @@
package org.baeldung.spring.rest.compress;
public class Message {
private String text;
public Message() {
}
public Message(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Message {");
sb.append("text='").append(text).append('\'');
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,38 @@
package org.baeldung.spring.rest.compress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class MessageController {
protected static final String PROCESSED = "Processed ";
protected static final String REQUEST_MAPPING = "process";
private static final Logger LOG = LoggerFactory.getLogger(MessageController.class);
/**
* A simple endpoint that responds with "Processed " + supplied Message content.
*
* @param headers
* @param message
* @return
*/
@PostMapping(value = REQUEST_MAPPING)
public ResponseEntity<String> processMessage(@RequestHeader Map<String, String> headers,
@RequestBody Message message) {
// Print headers
headers.forEach((k, v) -> LOG.info(k + "=" + v));
return ResponseEntity.ok(PROCESSED + message.getText());
}
}

View File

@ -0,0 +1,21 @@
package org.baeldung.spring.rest.compress;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfiguration {
/**
* A RestTemplate that compresses requests.
*
* @return RestTemplate
*/
@Bean
public RestTemplate getRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(new CompressingClientHttpRequestInterceptor());
return restTemplate;
}
}

View File

@ -0,0 +1,15 @@
package org.baeldung.spring.rest.compress;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableAutoConfiguration
public class SpringCompressRequestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCompressRequestApplication.class, args);
}
}

View File

@ -0,0 +1,19 @@
package org.baeldung.spring.rest.compress;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class GzipUtilsUnitTest {
@Test
public void givenCompressedText_whenDecompressed_thenSuccessful() throws Exception {
final String expectedText = "Hello Baeldung!";
byte[] compressedText = GzipUtils.compress(expectedText);
String decompressedText = GzipUtils.decompress(compressedText);
assertNotNull(compressedText);
assertEquals(expectedText, decompressedText);
}
}

View File

@ -0,0 +1,56 @@
package org.baeldung.spring.rest.compress;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestTemplate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MessageControllerUnitTest {
private static final Logger LOG = LoggerFactory.getLogger(MessageControllerUnitTest.class);
@Autowired
private RestTemplate restTemplate;
@LocalServerPort
private int randomServerPort;
/**
* As a further test you can intercept the request body, using a tool like
* Wireshark, to see the request body is actually gzipped.
*
* @throws Exception
*/
@Test
public void givenRestTemplate_whenPostCompressedRequest_thenRespondsSuccessfully() throws Exception {
final String text = "Hello Baeldung!";
Message message = new Message(text);
HttpEntity<Message> request = new HttpEntity<>(message);
String uri = String.format("http://localhost:%s/%s", randomServerPort, MessageController.REQUEST_MAPPING);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(uri, request, String.class);
String response = responseEntity.getBody();
LOG.info("Got response [{}]", response);
assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
assertNotNull(response);
assertEquals(MessageController.PROCESSED + text, response);
}
}