Since the rise of RESTFul API, Spring has provided developers with a client to access Rest. RestTemplate can not only call http interface conveniently, but also call micro-services under the same registry. It also has load balancing and fusing mechanisms. Of course, I've heard about OKhttp, HTTPClient and other network frameworks, but we're focusing on RestTemplate (one implementation is based on HTTPClient), because SpringBook comes with it, and the basic usage scenarios are covered.
What is RestTemplate?
RestTemplate is Spring's client for accessing Rest services.
RestTemplate provides a variety of convenient access methods to remote Http services, which can greatly improve the writing efficiency of the client.
Calling the default constructor of RestTemplate, the RestTemplate object creates HTTP requests at the bottom by using the implementation under the java.net package.
You can specify different HTTP requests by using ClientHttpRequestFactory.
ClientHttpRequestFactory interface provides two main implementations
1. One is SimpleClient HttpRequestFactory, which creates the underlying Http request connection in a way provided by J2SE (as provided by the java.net package).
2. One way is to use HttpComponents Client HttpRequestFactory. The bottom layer uses HttpClient to access remote Http services, and HttpClient can configure connection pool and certificate information.
Simple Configuration of RestTemplate
@Configuration class RestTemplateConfig { /** * Build a RestTemplate Bean with the default configuration */ @Bean fun restTemplate():RestTemplate { return RestTemplateBuilder().build() } }
Send POST requests and submit parameters through Form forms
@Component class RestTemplateClient { @Autowired lateinit var restTemplate: RestTemplate val logger:Logger = LoggerFactory.getLogger(this.javaClass) /** * Send POST requests and submit parameters through Form forms */ fun <T> postForm(params: Map<String, String>, url: String, t:T) : ResultDTO<T>? { logger.info("request URL===========:{}", url) logger.info("Request parameters===========:{}", params) val httpHeaders = HttpHeaders() httpHeaders.contentType = MediaType.APPLICATION_FORM_URLENCODED val requestParams = LinkedMultiValueMap<String, String>() params.forEach(requestParams::add) val httpEntity = HttpEntity<MultiValueMap<String, String>>(requestParams, httpHeaders) return restTemplate.postForObject(url, httpEntity, ResultDTO<T>().javaClass) } }
Writing Controller and Testing
@RestController @RequestMapping("/api") class LotteryController { @Autowired lateinit var restTemplateClient: RestTemplateClient /** * Lottery Type Query */ @PostMapping("/lottery/types") fun lotteryTypes(@RequestBody params:Map<String, String>) : ResultDTO<LotteryDTO>? { return restTemplateClient.postForm(params, UrlEnums.DEMO1.url, LotteryDTO()) } }
Send POST requests, pass JSON parameters
/** * Send POST requests and submit parameters through Form forms */ fun <T> postBody(params: Map<String, String>, url: String, t:T) : ResultDTO<T>? { logger.info("request URL===========:{}", url) logger.info("Request parameters===========:{}", params) val httpHeaders = HttpHeaders() httpHeaders.contentType = MediaType.APPLICATION_JSON_UTF8 val httpEntity = HttpEntity(params, httpHeaders) return restTemplate.postForObject(url, httpEntity, ResultDTO<T>().javaClass) }
Send GET requests
/** * Send POST requests and submit parameters through Form forms */ fun <T> get(params: Map<String, String>, url: String, t:T) : ResultDTO<T>? { logger.info("request URL===========:{}", url) logger.info("Request parameters===========:{}", params) val builder = StringBuilder() params.forEach{k, v -> builder.append(k).append("=").append(v).append("&") } val param : String = builder.toString().substring(0, builder.length - 1) return restTemplate.getForObject(url.plus(param), ResultDTO<T>().javaClass) }
GET Download Resources
/** * Download resources */ fun downGet(url: String, headerParams: Map<String, String>) : ByteArray? { logger.info("Resources URL==========>:{}", url) val httpHeaders = HttpHeaders() if (!CollectionUtils.isEmpty(headerParams)) { headerParams.forEach(httpHeaders::add) } val httpEntity = HttpEntity(LinkedMultiValueMap<String, String>().putAll(httpHeaders)) return restTemplate.exchange(url, HttpMethod.GET, httpEntity, ByteArray::class.java).body }
Invoking Microservice Interface
When we develop micro-service applications, sometimes an application may deploy many, but not on different machines. At this time, we can use Nginx to do a load balancing, but what we recommend here is Spring Cloud to provide load balancing. Just add a comment on the Bean to @LoadBalanced, as follows:
@Bean @LoadBalanced fun restTemplate():RestTemplate { return RestTemplateBuilder().build() }
The difference between calling a normal HTTP request and calling a microservice is that it is http://application.name/xxx. The path we access is the microservice application name+business routing, because the service will be registered in the registry, and the registry will maintain the application name. When we access the application, we can know that the application is on that machine.
The basic usage is finished, but there is still a problem, because we use the simplest configuration, where we do not set the default timeout, the official default is 60S, but our business is usually response speed is required, a minute of waiting time for users is too long, at this time we need a timeout mechanism, specific settings. Set the following:
package io.intodream.kotlin05.config import org.apache.http.impl.client.HttpClientBuilder import org.springframework.beans.factory.annotation.Value import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.boot.web.client.RestTemplateBuilder import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.client.ClientHttpRequestFactory import org.springframework.http.client.HttpComponentsClientHttpRequestFactory import org.springframework.http.client.SimpleClientHttpRequestFactory import org.springframework.http.converter.HttpMessageConverter import org.springframework.http.converter.StringHttpMessageConverter import org.springframework.stereotype.Component import org.springframework.web.client.RestTemplate import java.nio.charset.StandardCharsets /** * @description * RestTemplate To configure * @author Jwenk * @copyright intoDream.io Dream building technology * @email xmsjgzs@163.com * @date 2019-04-05,22:42 */ @Configuration class RestTemplateConfig { @Value("\${remote.maxTotalConnect}") val maxTotalConnect: Int = 0 @Value("\${remote.maxConnectPerRoute}") val maxConnectPerRoute: Int = 200 @Value("\${remote.connectTimeout}") val connectTimeout: Int = 2000 @Value("\${remote.readTimeout}") val readTimeout: Int = 3000 /** * Create HTTP Client Factory */ private fun createFactory() : ClientHttpRequestFactory { if (this.maxTotalConnect <= 0) { val factory = SimpleClientHttpRequestFactory() factory.setReadTimeout(this.readTimeout) factory.setConnectTimeout(this.connectTimeout) return factory } val httpClient = HttpClientBuilder.create() .setMaxConnTotal(this.maxTotalConnect) .setMaxConnPerRoute(this.maxConnectPerRoute).build() val factory = HttpComponentsClientHttpRequestFactory(httpClient) factory.setConnectTimeout(this.connectTimeout) factory.setReadTimeout(this.readTimeout) return factory } /** * Build a RestTemplate Bean with the default configuration */ @Bean fun restTemplate():RestTemplate { val restTemplate = RestTemplate(this.createFactory()) val converterList : MutableList<HttpMessageConverter<*>> = restTemplate.messageConverters var converterTarget : HttpMessageConverter<*>? = null /** * Setting String HttpMessageConverter Character Set to UTF-8 resolves the problem of Chinese scrambling */ for (item: HttpMessageConverter<*> in converterList) { if (StringHttpMessageConverter::class.java == item.javaClass) { converterTarget = item break } } if (null != converterTarget) { converterList.remove(converterTarget) } converterList.add(1, StringHttpMessageConverter(StandardCharsets.UTF_8)) return restTemplate } }
Remember to introduce the jar of HttpClient in pom.xml, otherwise the startup will be wrong
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.6</version> </dependency>
Some of the use and configuration optimization of RestTemplate is over. My favorite friends can pay attention to my blog. https://www.tisnz.com If there is something wrong, please correct it.