RestTemplate 使用詳解

一、簡介

常見的http客戶端請求工具:

  1. JDK 自帶 HttpURLConnection
  2. Apache HttpClient
  3. OKHttp

以上 工具雖然常用乏盐,但對于 RESTful 操作相對不是太友好。所以晌柬,從 Spring3.0開始支持的一個(gè) HTTP 請求工具RestTemplate,提供了常見的 REST請求方案的模板。
RestTemplate只是提供了 Http請求模板,其底層默認(rèn)是使用HttpURLConnection作為真正的請求工具懂讯。它可以通過構(gòu)造方法替換底層的執(zhí)行引擎,常見的引擎又HttpClient台颠、Netty褐望、OkHttp勒庄。

二、簡單的請求

1瘫里、GET請求

1. 直接拼接參數(shù)

  String params = "http://localhost:10011/user/params?name=諸葛亮&age=100";
  String result = template.getForObject(HOST  + params, String.class);
  LOGGER.info("請求返回結(jié)果:{}", result);

2. 占位符參數(shù)

  // 1实蔽、可以直接在方法中指定參數(shù), 此種方式還可以使用下標(biāo)的形式。
  // 請求路徑還可以為:name={0}&age={1}
 String url = "http://localhost:10011/user/params?name={name}&age={age}";
 String result = template.getForObject(url , String.class, "李四", 20);
 LOGGER.info("請求返回結(jié)果:{}", result);

// 2谨读、 通過 Map 傳遞參數(shù)局装,此種方式必須使用占位符,并且 map 中的 key 值劳殖,要與請求
// 路徑中的 占位符一致
Map<String, Object> map = new HashMap<>();
map.put("name", "王五");
map.put("age", 30);
ResponseEntity<String> forEntity = template.getForEntity(HOST + url , String.class, map);

2铐尚、POST請求

接口實(shí)例
如下的接口實(shí)例中兩個(gè)方法的唯一區(qū)別為 一個(gè)參數(shù)中加了注解@RequestBody,一個(gè)沒有加哆姻,兩者在 POST請求中傳值方式不同宣增。

    // 接口 1
    @RequestMapping("/obj")
    @ResponseBody
    public User getObj(User user){
        return user;
    }
    // 接口 2
    @RequestMapping("/body")
    @ResponseBody
    public User getBody(@RequestBody User user){
        return user;
    }

1、帶有 @RequestBody 注解的請求

此種情況下矛缨,請求參數(shù)可以為 設(shè)置User對象爹脾,也可以說使用Map

   String url = "http://localhost:10011/user/body";
   
   User user = new User().setName("張三")
            .setAge(40);
    String result = template.postForObject(url, user, String.class);
    LOGGER.info("請求返回結(jié)果:{}", result);

    Map<String, Object> map = new HashMap<>();
    map.put("name", "王五");
    map.put("age", 30);

    ResponseEntity<String> forEntity = template.postForEntity(url, map, String.class);

    LOGGER.info("請求返回結(jié)果:{}", forEntity.getBody());

2、不帶@RequestBody 注解的請求

此種情況下箕昭,傳的參數(shù)需要使用MultiValueMap

  MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
  map.add("name", "王五");
  map.add("age", 30);
  ResponseEntity<String> forEntity = template.postForEntity(url, map, String.class);

   LOGGER.info("請求返回結(jié)果:{}", forEntity.getBody());

三灵妨、帶請求頭的請求

1、GET 請求

GET請求中的getForObjectgetForEntity 方法不支持傳遞頭信息盟广,需要使用 通用方法exchange闷串,如下所示:

  String url = "http://localhost:10011/user/params?name={name}&age={age}";
   // 定義頭信息
   HttpHeaders headers = new HttpHeaders();
   headers.add("token", UUID.randomUUID().toString());
   // 請求參數(shù)
   Map<String, Object> map = new HashMap<>();
   map.put("name", "王五");
   map.put("age", 30);

   // 使用 HttpEntity 對 頭信息進(jìn)行封裝
   HttpEntity<Map<String, Object>> entity = new HttpEntity<>(headers);
   // 請求方法 exchange
   ResponseEntity<String> response = template.exchange(url, HttpMethod.GET, entity, String.class, map);
   LOGGER.info("請求返回結(jié)果:{}", response.getBody());

2、POST請求

POST 請求添加頭信息比較簡單筋量,只需要使用 HttpEntity 對請求對象進(jìn)行一次封裝即可烹吵。

   // 定義頭信息
   HttpHeaders headers = new HttpHeaders();
   headers.add("token", UUID.randomUUID().toString());
   User user = new User().setName("張三")
            .setAge(40);
    // 使用 HttpEntity 把請求對象user 和 header 進(jìn)行組裝
   HttpEntity<User> userHttpEntity = new HttpEntity<>(user, headers);
    // 把請求參數(shù)改為 httpEntity 對象即可
   String result = template.postForObject(url, userHttpEntity, String.class);
   LOGGER.info("請求返回結(jié)果:{}", result);

四、form 表單請求

form表單的提交只需要需要把頭信息ContentType 設(shè)置為MediaType.APPLICATION_FORM_URLENCODED 桨武,同時(shí)參數(shù)需要使用 MultiValueMap 封裝肋拔。如下所示:

     String url = "http://localhost:10011/user/obj";
      
     HttpHeaders headers = new HttpHeaders();
     headers.add("token", UUID.randomUUID().toString());
     // 設(shè)置請求類型
     headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
     // 組裝參數(shù)
     MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
     multiValueMap.add("name", "王五");
     multiValueMap.add("age", 30);
     // 發(fā)送請求
     HttpEntity< MultiValueMap<String, Object>> request = new HttpEntity<>(multiValueMap, headers);
     ResponseEntity<String> exchange = template.exchange(url, HttpMethod.POST, request, String.class);
     LOGGER.info("請求返回結(jié)果:{}", exchange.getBody());

五、上傳下載

1呀酸、上傳

  String url = "http://localhost:10011/user/upload";
  HttpHeaders headers = new HttpHeaders();

  // 模擬讀取文件
  File file = new File("F:/run.bat");
  //從File句柄創(chuàng)建一個(gè)新的FileSystemResource
  FileSystemResource resource = new FileSystemResource(file);

  MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
  multiValueMap.add("name", "update.bat");
  multiValueMap.add("file", resource);

  HttpEntity< MultiValueMap<String, Object>> request = new HttpEntity<>(multiValueMap, headers);
  ResponseEntity<String> exchange = template.exchange(url, HttpMethod.POST, request, String.class);
  LOGGER.info("請求返回結(jié)果:{}", exchange.getBody());

2凉蜂、下載

1. 小文件下載
小文件下載比較簡單,只需要把請求響應(yīng)類型設(shè)置為byte[] 即可性誉,如下所示:

   String url = "http://localhost:10011/user/downLoad";
   // 請求下載
   ResponseEntity<byte[]> entity = template.getForEntity(url, byte[].class);
   // 寫文件
   byte[] body = entity.getBody();
   Files.write(Paths.get("D:/download.jpg"), body);

這種下載方法實(shí)際上是將下載文件一次性加載到客戶端本地內(nèi)存窿吩,然后從內(nèi)存將文件寫入磁盤。這種方式對于小文件的下載還比較適合错览,如果文件比較大或者文件下載并發(fā)量比較大纫雁,容易造成內(nèi)存的大量占用,從而降低應(yīng)用的運(yùn)行效率倾哺。

2. 大文件下載

這種下載方式的區(qū)別在于

  • 設(shè)置了請求頭APPLICATION_OCTET_STREAM轧邪,表示以流的形式進(jìn)行數(shù)據(jù)加載
  • RequestCallback 結(jié)合File.copy保證了接收到一部分文件內(nèi)容刽脖,就向磁盤寫入一部分內(nèi)容。而不是全部加載到內(nèi)存忌愚,最后再寫入磁盤文件曲管。
   String url = "http://localhost:10011/user/downLoad";

   String targetPath = "D:/download.jpg";

   // 定義請求頭的接收類型
   RequestCallback requestCallback = request -> request.getHeaders()
           .setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
   //對響應(yīng)進(jìn)行流式處理而不是將其全部加載到內(nèi)存中
   template.execute(url, HttpMethod.GET, requestCallback, clientHttpResponse -> {
       Files.copy(clientHttpResponse.getBody(), Paths.get(targetPath));
       return null;
   });

六、更換底層請求執(zhí)行引擎

Spring中已經(jīng)提供了大部分的執(zhí)行引擎硕糊,比如 HttpClientOkHttp3 等院水,要想使用這些底層引擎只需要加入響應(yīng)的依賴,然后再初始化類似简十,在構(gòu)造方法中指定響應(yīng)的執(zhí)行引擎即可衙耕。

// 1、使用 HttpClient 引擎勺远。
RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
// 2、使用OkHttp3 引擎
RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory());

七时鸵、攔截器

當(dāng)所有的請求需要設(shè)置公共信息時(shí)胶逢,就可以使用攔截器,為每個(gè)請求設(shè)置饰潜。設(shè)置方法如下:

  RestTemplate template = new RestTemplate();
  // 此處設(shè)置了一個(gè)公共請求頭 AUTHORIZATION
  ClientHttpRequestInterceptor interceptor = new ClientHttpRequestInterceptor() {
       @Override
       public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
           HttpHeaders headers = request.getHeaders();
           headers.set(HttpHeaders.AUTHORIZATION, "636213dc4ac6e9220a0f5107");
           return execution.execute(request, body);
       }
   };
   template.setInterceptors(Arrays.asList(interceptor));
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末初坠,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子彭雾,更是在濱河造成了極大的恐慌碟刺,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件薯酝,死亡現(xiàn)場離奇詭異半沽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)吴菠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門者填,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人做葵,你說我怎么就攤上這事占哟。” “怎么了酿矢?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵榨乎,是天一觀的道長。 經(jīng)常有香客問我瘫筐,道長蜜暑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任严肪,我火速辦了婚禮史煎,結(jié)果婚禮上谦屑,老公的妹妹穿的比我還像新娘。我一直安慰自己篇梭,他們只是感情好氢橙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著恬偷,像睡著了一般悍手。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上袍患,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天坦康,我揣著相機(jī)與錄音,去河邊找鬼诡延。 笑死滞欠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的肆良。 我是一名探鬼主播筛璧,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼惹恃!你這毒婦竟也來了夭谤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤巫糙,失蹤者是張志新(化名)和其女友劉穎朗儒,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體参淹,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡醉锄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浙值。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榆鼠。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖亥鸠,靈堂內(nèi)的尸體忽然破棺而出妆够,到底是詐尸還是另有隱情,我是刑警寧澤负蚊,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布神妹,位于F島的核電站,受9級特大地震影響家妆,放射性物質(zhì)發(fā)生泄漏鸵荠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一伤极、第九天 我趴在偏房一處隱蔽的房頂上張望蛹找。 院中可真熱鬧姨伤,春花似錦、人聲如沸庸疾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽届慈。三九已至徒溪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間金顿,已是汗流浹背臊泌。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留揍拆,地道東北人渠概。 一個(gè)月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像嫂拴,于是被迫代替她去往敵國和親高氮。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 文章目錄 1 概述:[https://blog.csdn.net/qq_44509920/article/deta...
    燒瓶小人閱讀 724評論 0 1
  • 一顷牌,OKHttp介紹 okhttp是一個(gè)第三方類庫,用于android中請求網(wǎng)絡(luò)塞淹。 這是一個(gè)開源項(xiàng)目,是安卓端最火...
    流船閱讀 67,486評論 7 55
  • 一 OKHttp簡介 OKHttp是一個(gè)處理網(wǎng)絡(luò)請求的開源項(xiàng)目窟蓝,Android 當(dāng)前最火熱網(wǎng)絡(luò)框架,由移動支付Sq...
    嚶嚶嚶999閱讀 4,756評論 0 7
  • 一 饱普、OKHttp簡介OKHttp是一個(gè)處理網(wǎng)絡(luò)請求的開源項(xiàng)目运挫,Android 當(dāng)前最火熱網(wǎng)絡(luò)框架,由移動支付Sq...
    GODANDDEVIL閱讀 1,307評論 0 0
  • 前言 最近有個(gè)想法——就是把 Android 主流開源框架進(jìn)行深入分析套耕,然后寫成一系列文章谁帕,包括該框架的詳細(xì)使用與...
    wildma閱讀 1,349評論 1 5