欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用spring的restTemplate注意點

 更新時間:2021年10月28日 09:28:02   作者:書生楊陽  
這篇文章主要介紹了使用spring的restTemplate注意點,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

使用spring的restTemplate注意點

spring的restTemplate可以向一個url發(fā)送請求并接收服務(wù)器端的響應(yīng)信息。但在發(fā)請求時,會對請求的url值進(jìn)行編碼再發(fā)送。

下面看spring的RestTemplate的源碼

restTemplate基本上發(fā)送請求的方法內(nèi)部都會調(diào)用到execute()方法:

這里寫圖片描述

expand()方法的代碼如下:

這里寫圖片描述

encode()方法的代碼如下:

這里寫圖片描述

所以如果使用非spring的服務(wù)器接收時,需要進(jìn)行解碼才能接收到RestTemplate發(fā)送的內(nèi)容。(spring的服務(wù)器接收到參數(shù)時會自動進(jìn)行一次解碼,所以使用restTemplate發(fā)送消息,Spring的服務(wù)器接收時不會出現(xiàn)問題)。

spring的RestTemplate使用指南

前言:現(xiàn)在restful接口越來越廣泛,而如今很多接口摒棄了傳統(tǒng)的配置復(fù)雜的webService開發(fā)模式,在java領(lǐng)域只需要很簡單的springMvc就可以聲明為一個控制器,再加上service層,就可以直接操作數(shù)據(jù)庫成為一個靈活的接口。

而我們請求接口的次數(shù)也會越來越多(最近我在和一個工具對接的時候,對方公司提供的接口全部由我們主動去調(diào)用),一般我們請求接口,都采用Apache Httpclient工具,這個工具穩(wěn)定,既可以建立長連接,保持不錯的性能,而它唯一的不足就是使用起來麻煩多變,并且要很多層判斷處理,今天我要談的就是spring對httpClient的再封裝工具類,restTemplate,采用模板模式抽象出來的高效工具。

有點類似于jdbcTemplate,今天我們就來一步步揭開它的使用方法

一:restTemplate簡介

1.1:restTemplate的類結(jié)構(gòu)

可以看出它繼承自HttpAccessor這個統(tǒng)一的處理器,然后再繼承自InterceptingHttpAccessor,這個攔截轉(zhuǎn)換器,最終RestTemplate實現(xiàn)了封裝httpClient的模板工具類

1.2:restTemplate的方法

Spring用于同步客戶端HTTP訪問的中心類。它簡化了與HTTP服務(wù)器的通信,并執(zhí)行RESTful原則。它處理HTTP連接,使應(yīng)用程序代碼提供URL,使用可能的模板變量,并提取結(jié)果。

注意:默認(rèn)情況下,RestTemplate依賴于標(biāo)準(zhǔn)的JDK來建立HTTP連接。你可以切換使用不同的HTTP庫,如Apache HttpComponents,Netty和OkHttp通過setRequestFactory屬性。內(nèi)部模板使用HttpMessageConverter實例將HTTP消息轉(zhuǎn)換為POJO和從POJO轉(zhuǎn)換。主要MIME類型的轉(zhuǎn)換器是默認(rèn)注冊的,但您也可以注冊其他轉(zhuǎn)換器通過setMessageConverters

以下是http方法和restTempalte方法的比對映射,可以看出restTemplate提供了操作http的方法,其中exchange方法可以用來做任何的請求,一般我們都是用它來封裝不同的請求方式。

二:restTemplate的配置方法

2.1:在springboot中的配置

springboot是一款簡化傳統(tǒng)xml配置式的開發(fā)方式,主要采用注解的方式來代替?zhèn)鹘y(tǒng)繁瑣的xml配置,接下來我們就用springboot提供的注解來配置restTemplate:

@Configuration
public class RestTemplateConfig {
    private static final Logger logger= LoggerFactory.getLogger(RestTemplateConfig.class);
    @Bean
    public RestTemplate restTemplate() {
        // 添加內(nèi)容轉(zhuǎn)換器,使用默認(rèn)的內(nèi)容轉(zhuǎn)換器
        RestTemplate restTemplate = new RestTemplate(httpRequestFactory());
        // 設(shè)置編碼格式為UTF-8
        List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
        HttpMessageConverter<?> converterTarget = null;
        for (HttpMessageConverter<?> item : converterList) {
            if (item.getClass() == StringHttpMessageConverter.class) {
                converterTarget = item;
                break;
            }
        }
        if (converterTarget != null) {
            converterList.remove(converterTarget);
        }
        HttpMessageConverter<?> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
        converterList.add(1,converter);
        LOGGER.info("-----restTemplate-----初始化完成");
        return restTemplate;
    }
    @Bean
    public ClientHttpRequestFactory httpRequestFactory() {
        return new HttpComponentsClientHttpRequestFactory(httpClient());
    }
    @Bean
    public HttpClient httpClient() {
        // 長連接保持30秒
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
        //設(shè)置整個連接池最大連接數(shù) 根據(jù)自己的場景決定
        connectionManager.setMaxTotal(500);
        //同路由的并發(fā)數(shù),路由是對maxTotal的細(xì)分
        connectionManager.setDefaultMaxPerRoute(500);
        //requestConfig
        RequestConfig requestConfig = RequestConfig.custom()
                //服務(wù)器返回數(shù)據(jù)(response)的時間,超過該時間拋出read timeout
                .setSocketTimeout(10000)
                //連接上服務(wù)器(握手成功)的時間,超出該時間拋出connect timeout
                .setConnectTimeout(5000)
                //從連接池中獲取連接的超時時間,超過該時間未拿到可用連接,會拋出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
                .setConnectionRequestTimeout(500)
                .build();
        //headers
        List<Header> headers = new ArrayList<>();
        headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));
        headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
        headers.add(new BasicHeader("Accept-Language", "zh-CN"));
        headers.add(new BasicHeader("Connection", "Keep-Alive"));
        headers.add(new BasicHeader("Content-type", "application/json;charset=UTF-8"));
        return HttpClientBuilder.create()
                .setDefaultRequestConfig(requestConfig)
                .setConnectionManager(connectionManager)
                .setDefaultHeaders(headers)
                // 保持長連接配置,需要在頭添加Keep-Alive
                .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
                //重試次數(shù),默認(rèn)是3次,沒有開啟
                .setRetryHandler(new DefaultHttpRequestRetryHandler(2, true))
                .build();
    }
}

首先解釋以下@configuration,它的主要作用就是在spring容器啟動的時候,初始化IOC,使用了這個注解,那么該類就會在spring啟動的時候,把@Bean注解標(biāo)識的類進(jìn)行依賴注入。@Bean理解的話,就好比在配置文件中配置<bean>.接下來就是在restTemplate的構(gòu)造方法中添加httpRequest的工廠,使用連接池來優(yōu)化http通信,默認(rèn)使用長連接時間為30秒,再設(shè)置路由讓http連接定向到指定的IP,然后設(shè)置并發(fā)數(shù)。再就是設(shè)置請求配置的超時時間,為了防止請求時間過長而引起資源的過渡浪費。如果在超過設(shè)置的timeout還沒有數(shù)據(jù)返回,就直接斷開連接。headers是添加默認(rèn)的請求頭,這里設(shè)置了傳送的格式為json,語言為中-英等等屬性。HttpClientBuilder.create設(shè)置請求頭到HttpClient,然后在設(shè)置保持的時間,重試的次數(shù),注入給httpClient進(jìn)行封裝。

在bean中的HttpMessageConverter,就是http信息轉(zhuǎn)換器,它的主要作用就是轉(zhuǎn)換和解析返回來的json數(shù)據(jù),restTemplate默認(rèn)使用jackson來作為底層的解析工具,而其它的比如Gson,fastjson等等第三方開源庫放在headers這個list中,如果要使用,可以通過以下代碼進(jìn)行改變:

         this.restTemplate.getMessageConverters().clear();
        final List<HttpMessageConverter<?>> myHttpMessageConverter = new ArrayList<HttpMessageConverter<?>>();
         
        //自己實現(xiàn)的messgeConverter
        HttpMessageConverter<Object> messageConverter = new MyHttpMessageConverter<Object>();
        
        myHttpMessageConverter.add(messageConverter);
        
        this.restTemplate.setMessageConverters(myHttpMessageConverter);

三:restUtil工具類

restUtil就是通過包裝restTemplate暴露出面向外界的方法,通過高度封裝,可以隱藏內(nèi)部細(xì)節(jié),簡單使用,在使用它的時候,我們只需要傳入請求的url和對應(yīng)的參數(shù),然后就可以取到結(jié)果了。參數(shù)一般有兩種形式,一種是直接傳入json,另一種是key、value形式的,key/value形式的,可以直接使用execute方法,傳入url和請求的方法類型就可以了。在開頭看到了restTemplate基本上是支持所有http請求的,接下來的工具類就介紹一下post和get請求的主要封裝方法

@Component
public class RestUtil {
    @Autowired
    private  RestTemplate restTemplate;
    //一些自定義的請求頭參數(shù)
    public static final String supplierID="";
    public static final String interfacekey= "";
    /**
     * DLT專用執(zhí)行方法
     * @param param 請求參數(shù):可以添加一些常量請求值
     * @param url 訪問的url
     * @param method 請求的方法
     * @return
     */
    public String execute(Map<String,Object> param, String url, HttpMethod method){
        HttpHeaders headers = this.getDefaultHeader();
        Map<String,Object> requestor = this.getDefaultParam();
        param.put("requestor",requestor);
        param.put("supplierID",supplierID);
        HttpEntity<Map<String,Object>> requestEntity = new HttpEntity<>(param, headers);
        ResponseEntity<String> response = restTemplate.exchange(url,method, requestEntity, String.class);
        return response.getBody();
    }
    /**
     * 獲取默認(rèn)的頭請求信息
     * @return
     */
    public HttpHeaders getDefaultHeader(){
        String timestamp = ""+System.currentTimeMillis();
        String signature = EncoderByMd5(supplierID + timestamp + interfacekey);
        HttpHeaders headers = new HttpHeaders();
        headers.add("signature", signature);
        headers.add("timestamp", timestamp);
        return headers;
    }
    /**
     * 獲取默認(rèn)的參數(shù)
     * @return
     */
    public Map<String,Object> getDefaultParam(){
        Map<String,Object> defParam = new HashMap<>();
        defParam.put("invoker","xx");
        defParam.put("operatorName","xx");
        return defParam;
    }
    /**
     * 通過MD5加密
     * @param str
     * @return
     */
    public static String EncoderByMd5(String str){
        if (str == null) {
            return null;
        }
        try {
            // 確定計算方法
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            BASE64Encoder base64en = new BASE64Encoder();
            // 加密后的字符串
            return base64en.encode(md5.digest(str.getBytes("utf-8"))).toUpperCase();
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
            return null;
        }
    }
   
    /**
     * get請求
     * @param url 請求的url
     * @param jsonData 請求的json
     * @return
     */
    public String restGet(String url,String jsonData){
        return request(url, jsonData,HttpMethod.GET);
    }
    /**
     * @param url 請求的url
     * @param jsonData json數(shù)據(jù)
     * @param httpMethod
     * @return
     */
    private String request(String url, String jsonData,HttpMethod httpMethod) {
        ResponseEntity<String> response=null;
        try {
            if (Check.isEmpty(url)) {
                throw new IllegalArgumentException();
            }
            HttpEntity<String> requestEntity = new HttpEntity<String>(jsonData);
            response = restTemplate.exchange(url, httpMethod, requestEntity, String.class);
        }catch (Exception ex){
            ex.printStackTrace();
            return "";
        }
        return response.getBody().toString();
    }
    /**
     * Get請求獲取實體類
     * @param url 請求的url
     * @param responseType 返回的類型
     * @param parms 不限定個數(shù)的參數(shù)
     * @param <T> 泛型
     * @return
     */
    public <T> T getForEntity(String url,Class<T> responseType,Object... parms){
        return (T) restTemplate.getForEntity(url,responseType,parms);
    }
   /**
    * Get請求
    * @param url
    * @param parm
    * @return
     */
   public String get(String url,Map<String,Object> parm){
    return restTemplate.getForEntity(url,String.class,parm).getBody();
 }
}

四:使用示例

4.1:首先我們用springBoot來搭建一個簡單的rest請求鏈接

我們來模擬一個請求,傳入年齡和性別、身高,計算出標(biāo)準(zhǔn)體重的接口,這段代碼比較簡單,我只給出示范代碼:

@SpringBootApplication
@RestController
public class HealApplication {
    @RequestMapping(value = "weight", method = RequestMethod.GET)
    public ResultModel getWeight(@RequestParam(value = "height", required = false) Integer height,   @RequestParam(value = "sex", required = false) Integer sex, @RequestParam(value = "age", required = false) Integer age) {
        if (height == null || age == null || sex == null || (!sex.equals(0) && !sex.equals(1))) {
            return new ResultModel(400, "缺少請求參數(shù)或者參數(shù)錯誤", 0d);
        }
        double condition = getStandardWeight(sex, age, height);
        return new ResultModel(200, "請求成功", condition);
    }
    /**
     * 獲取標(biāo)準(zhǔn)體重
     *
     * @param sex    性別 1:男  2:女
     * @param age    年齡
     * @param height
     * @return 體重(單位:kg)
     */
    public double getStandardWeight(int sex, int age, int height) {
        double weight = 0.0;
        switch (sex) {
            //男性
            case 1:
                if (age < 12 && age > 2) {
                    weight = age * 2 + 12;
                } else if (age > 12) {
                    weight = (height - 150) * 0.6 + 50;
                }
                break;
            case 0:
                if (age < 12 && age > 2) {
                    weight = age * 2 + 12;
                } else if (age > 12) {
                    weight = (height - 100) * 0.6 + 50;
                }
                break;
            default:
                weight = 0;
                break;
        }
        return weight;
    }

可以看到我們的控制器有個映射weight請求的方法,通過傳入年齡、身高、性別,就可以計算出標(biāo)準(zhǔn)體重,我們來啟動springBoot,先試著用瀏覽器訪問一下,可以看出如下結(jié)果:

4.2:為了表明接口是通的,我們再用postman來試一下,可以看到返回結(jié)果正確:

4.3:在springboot里引入testNg單元測試類,測試一下訪問這個鏈接的結(jié)果:

public class TestRestManager  extends OrderProviderApplicationTests {
    @Autowired
    private RestUtil restUtil;
    /**
     * 請求方法為GEt
     * @return
     */
    @Test
    private void  requestGet(){
        String url="http://localhost:8080/weight?age={age}&sex={sex}&height={height}";
        //組裝請求參數(shù)
        Map<String,Object> parmMap =new HashMap<String,Object>();
        parmMap.put("age",35);
        parmMap.put("sex",1);
        parmMap.put("height",178);
        String result = restUtil.get(url, parmMap);
        System.out.println(result);
    }
}

結(jié)果返回以下內(nèi)容:

五:總結(jié)

本篇博客講述了RestTemplate的簡介,還有配置方法和使用示例,作為一款非常不錯的rest請求工具,屏蔽了復(fù)雜的HttpClient的實現(xiàn)細(xì)節(jié),向外暴露出簡單、易于使用的接口,使得我們的開發(fā)工作越來越簡單、高效,更多的方法工具可以研究一下restTemplate的具體Api,打開源碼,一切都了如指掌。在平時的工作中,應(yīng)該多發(fā)現(xiàn)這種工具類,從而來代替一些傳統(tǒng)的工具,對于提升工作效率有著突飛猛進(jìn)的效果和不可言喻的方便。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java ConcurrentHashMap用法案例詳解

    Java ConcurrentHashMap用法案例詳解

    這篇文章主要介紹了Java ConcurrentHashMap用法案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • springboot大文件上傳、分片上傳、斷點續(xù)傳、秒傳的實現(xiàn)

    springboot大文件上傳、分片上傳、斷點續(xù)傳、秒傳的實現(xiàn)

    本文主要介紹了springboot大文件上傳、分片上傳、斷點續(xù)傳、秒傳的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • 深入Java7的一些新特性以及對腳本語言支持API的介紹

    深入Java7的一些新特性以及對腳本語言支持API的介紹

    本篇文章是對Java7的一些新特性以及對腳本語言支持API的概述,需要的朋友參考下
    2013-05-05
  • 詳解ssh框架原理及流程

    詳解ssh框架原理及流程

    在本文中小編給大家整理的是關(guān)于ssh框架原理及流程的相關(guān)知識點內(nèi)容,有此需要的朋友們可以學(xué)習(xí)下。
    2019-07-07
  • Netty分布式高性能工具類同線程下回收對象解析

    Netty分布式高性能工具類同線程下回收對象解析

    這篇文章主要為大家介紹了Netty分布式高性能工具類同線程下回收對象解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • 舉例講解Java的Hibernate框架中的多對一和一對多映射

    舉例講解Java的Hibernate框架中的多對一和一對多映射

    這篇文章主要介紹了Java的Hibernate框架中的多對一和一對多映射,Hibernate是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2015-12-12
  • Java中的instanceof關(guān)鍵字在Android中的用法實例詳解

    Java中的instanceof關(guān)鍵字在Android中的用法實例詳解

    instanceof是Java的一個二元操作符,和==,>,<是同一類東西。接下來通過本文給大家介紹Java中的instanceof關(guān)鍵字在Android中的用法,非常不錯,具有參考借鑒價值,感興趣的朋友一起學(xué)習(xí)吧
    2016-07-07
  • springboot?使用clickhouse實時大數(shù)據(jù)分析引擎(使用方式)

    springboot?使用clickhouse實時大數(shù)據(jù)分析引擎(使用方式)

    這篇文章主要介紹了springboot?使用clickhouse實時大數(shù)據(jù)分析引擎的方法,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2022-02-02
  • Struts 2 實現(xiàn)Action的幾種方式

    Struts 2 實現(xiàn)Action的幾種方式

    本篇文章主要介紹了Struts 2 實現(xiàn)Action的幾種方式,Struts 2框架下實現(xiàn)Action類有三種方式,有興趣的可以了解一下
    2017-10-10
  • 詳解Java中自定義注解的使用

    詳解Java中自定義注解的使用

    Annontation是Java5開始引入的新特征,中文名稱叫注解,它提供了一種安全的類似注釋的機(jī)制,用來將任何的信息或元數(shù)據(jù)(metadata)與程序元素(類、方法、成員變量等)進(jìn)行關(guān)聯(lián)。本文主要介紹了自定義注解的使用,希望對大家有所幫助
    2023-03-03

最新評論