1. 程式人生 > 其它 >resttemplate get請求_簡單粗暴的RestTemplate

resttemplate get請求_簡單粗暴的RestTemplate

技術標籤:resttemplate get請求resttemplate get請求引數resttemplate get請求設定headerresttemplate post提交jsonresttemplate post請求resttemplate post請求json引數求

前言通常訪問http介面,我們有時候會使用httpclient,但是其程式碼複雜,還得費心進行各種資源回收的編寫,不建議直接使用。而RestTemplate是Spring提供的用於訪問Rest服務的客戶端,對get,post等請求以及反序列化支援都封裝的比較好,使用起來簡單粗暴優雅。但是筆者在使用時候碰到一些問題:1、亂碼。2、不同的請求需要設定不同的超時時間。 故整理出來與大家分享如何循序漸進的封裝一個比較使用順手、完善的配置類。 一、RestTemplate初步配置
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.http.client.ClientHttpRequestFactory;import org.springframework.http.client.SimpleClientHttpRequestFactory;/** * RestTemplate配置類 */@ConfigurationpublicclassRestTemplateConfig{
@Bean public ClientHttpRequestFactory simpleClientHttpRequestFactory() { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); factory.setReadTimeout(5000);//讀超時 單位為ms factory.setConnectTimeout(5000);//連線超時 單位為ms return factory; }}
基於上面這點微量的配置程式碼,我們我們已經可以進行編寫http請求程式碼了,粗暴簡單吧! 二、使用初探
下面來看下如何使用,他有post、get等spring封裝好的API,也有稍微複雜點的exchangeAPI, 但是我們的目的不是討論這些API如何使用,而是建立一個完善已用省心的配置,這裡就以post請求為例子。
import lombok.Data;import java.io.Serializable;@Datapublic class PersonRequest implements Serializable {    // 請求引數}import lombok.Data;import java.io.Serializable;@Datapublic class Person implements Serializable {    /**名稱*/    private String name;    /**年齡*/    private int age;}public static void main(String[] args){        PersonRequest request= new PersonRequest ()        Person person= restTemplate.postForObject("http://172.27.249.130:3000/entity_service",JSONObject.toJSONString(request),Person.class);}
三、問題亂碼配置如果只是上述簡單配置,那麼我們在服務端接受到的引數會出現中文亂碼 {\"name\":\"??\",\"age\":18},這是因為我這裡是以String格式提交資料的,底層其實採用的是StringHttpMessageConverter來處理請求,預設是ISO-8859-1字符集
@Beanpublic RestTemplate restTemplate(ClientHttpRequestFactory factory) {    RestTemplate restTemplate = new RestTemplate(factory);    // 解決字串編碼預設iso亂碼問題,將字符集強制設定為UTF-8    List>> list = restTemplate.getMessageConverters();    for (HttpMessageConverter> httpMessageConverter : list) {        if (httpMessageConverter instanceof StringHttpMessageConverter) {            ((StringHttpMessageConverter) httpMessageConverter).setDefaultCharset(StandardCharsets.UTF_8);            break;        }    }    return restTemplate;}
這個時候我們的亂碼就解決了 {\"name\":\"一斛墨水\",\"age\":18} 四、超時問題 我們的初步配置中,超時時間寫死了,那麼對於我們的url介面,可能A介面處理的慢,10秒鐘才能返回,B介面1分鐘才能返回,而C介面10毫秒就返回了,預設配置超時時間肯定不行,A和B介面只會觸發超時。那有沒有什麼辦法能夠針對不同的介面設定不同的超時時間呢?
// 通過原始碼跟蹤我們發現,// org.apache.http.impl.execchain.MainClientExec#execute// 在發起請求時會優先使用HttpClientContext中的超時時間設定@Overridepublic CloseableHttpResponse execute(        final HttpRoute route,        final HttpRequestWrapper request,        final HttpClientContext context,        final HttpExecutionAware execAware) throws IOException, HttpException {    ....            final int timeout = config.getSocketTimeout();            if (timeout >= 0) {                managedConn.setSocketTimeout(timeout);            }            ....}//而config.getSocketTimeout()取的是RequestConfig屬性socketTimeout的值// 那麼我們就需要再使用的時候,每次重新設定這個值就可以了
五、超時配置
import org.apache.http.client.HttpClient;import org.apache.http.client.config.RequestConfig;import org.apache.http.client.protocol.HttpClientContext;import org.apache.http.protocol.HttpContext;import org.springframework.http.HttpMethod;import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;import java.net.URI;// 參考了https://blog.csdn.net/baozhutang/article/details/88664333public class RestmelateFactory extends HttpComponentsClientHttpRequestFactory {    // 每次請求都可以設定超時時間 單位毫秒 the timeout value in milliseconds        public static ThreadLocal socketTimeoutThreadLocal = new ThreadLocal<>();    public RestmelateFactory(HttpClient httpClient) {        super(httpClient);    }    @Override    protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {        HttpContext context = HttpClientContext.create();        RequestConfig config = createRequestConfig(getHttpClient());//每次都從新設定超時時間        // 從ThreadLocal中獲取超時時間,並設定到context中                Integer socketTimeout = socketTimeoutThreadLocal.get();        if (null != socketTimeout) {            RequestConfig.Builder builder = RequestConfig.copy(config);            builder.setSocketTimeout(socketTimeout);            config = builder.build();        }        context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);        return context;    }}@Beanpublic ClientHttpRequestFactory restTemplateFactory() {    HttpClientBuilder httpClientBuilder = HttpClients.custom();//HttpClient相關配置    RestTemplateFactory factory = new RestTemplateFactory(httpClient);    factory.setConnectTimeout(5000);    // 即為 SocketTimeout        factory.setReadTimeout(30000);    factory.setConnectionRequestTimeout(5000);    return factory;}// 這次在使用,就可以根據不同的請求設定不同的超時時間了// 可以再url服務端打上斷點,一直等到restTemplate超時,// 會發現日誌前後呼叫耗時就是你得超時時間public static void main(String[] args) {    try {       // 設定當前請求超時時間                RestTemplateFactory.socketTimeoutThreadLocal.set(10);        PersonRequest request = new PersonRequest() log.info("handler, start request:" + request);        try {            Person person = restTemplate.postForObject("http://172.27.249.130:3000/entity_service", JSONObject.toJSONString(request), Person.class);        } catch (RestClientException e) {            log.error("handler介面異常, request:" + request, e);        }    } finally {        // 清理ThreadLocal中超時時間                RestTemplateFactory.socketTimeoutThreadLocal.remove();    }}
六、切面設定超時時間每次呼叫都要編寫重複程式碼設定超時時間到ThreadLocal,我強迫症,不能忍。大家要是能忍的話就可以不用再往下看了。下面我們就使用註解加切面消除這項重複工作。
import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * RestTemplate配置,比如目前只有的超時 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface RestTemplateAnnotation {    /**請求超時 the timeout value in milliseconds*/    int timeout();}import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@[email protected]@Slf4jpublic class RestTemplateAspect {@Pointcut(value="@annotation(com.annotation.RestTemplateAnnotation)")    public void accessOperation() {    }    @Around(value = "accessOperation() && @annotation(restTemplateAnnotation)")    public Object doAround(ProceedingJoinPoint joinPoint, RestTemplateAnnotation restTemplateAnnotation) throws Throwable {        try {            // 設定當前請求超時時間            HttpClientRequestFactory.socketTimeoutThreadLocal.set(restTemplateAnnotation.timeout());            return joinPoint.proceed();        } finally {            // 清理ThreadLocal中超時時間            HttpClientRequestFactory.socketTimeoutThreadLocal.remove();        }    }}/***註解使用**@paramrequest*@return*/@RestTemplateAnnotation(timeout=60000)public void handler () {  PersonRequest request = new PersonRequest() log.info("handler, start request:" + request);  try {      Person person = restTemplate.postForObject("http://172.27.249.130:3000/entity_service", JSONObject.toJSONString(request), Person.class);  } catch (RestClientException e) {      log.error("handler介面異常, request:" + request, e);  }}
至此我們就完成了一個使用簡單粗暴優雅的http呼叫封裝 952dc59dbeca9d2389f80284cd20eed9.png

五、預告

下期 :讓電腦桌面煩人的羞羞廣告彈窗無處遁形

如果此文對您有所幫助,煩請關注一下,以方便之後的文章能更及時、更好的幫助到您,謝謝!

0819beac6f0f02dfa2ddb1fa9b7441b2.png