RestTemplate接口調(diào)用神器常見用法匯總
1、RestTemplate 概述
發(fā)送 http 請求,估計很多人用過 httpclient 和 okhttp,確實挺好用的,而 Spring web 中的 RestTemplate 和這倆的功能類似,也是用來發(fā)送 http 請求的,不過用法上面比前面的 2 位要容易很多。
spring 框架提供的 RestTemplate 類可用于在應(yīng)用中調(diào)用 rest 服務(wù),它簡化了與 http 服務(wù)的通信方式,統(tǒng)一了 RESTful 的標(biāo)準(zhǔn),封裝了 http 鏈接, 我們只需要傳入 url 及返回值類型即可。相較于之前常用的 HttpClient,RestTemplate 是一種更優(yōu)雅的調(diào)用 RESTful 服務(wù)的方式。
在 Spring 應(yīng)用程序中訪問第三方 REST 服務(wù)與使用 Spring RestTemplate 類有關(guān)。RestTemplate 類的設(shè)計原則與許多其他 Spring 模板類(例如 JdbcTemplate、JmsTemplate)相同,為執(zhí)行復(fù)雜任務(wù)提供了一種具有默認(rèn)行為的簡化方法。
RestTemplate 默認(rèn)依賴 JDK 提供 http 連接的能力(HttpURLConnection),如果有需要的話也可以通過 setRequestFactory 方法替換為例如 Apache HttpComponents、Netty 或 OkHttp 等其它 HTTP library。
考慮到 RestTemplate 類是為調(diào)用 REST 服務(wù)而設(shè)計的,因此它的主要方法與 REST 的基礎(chǔ)緊密相連就不足為奇了,后者是 HTTP 協(xié)議的方法:HEAD、GET、POST、PUT、DELETE 和 OPTIONS。例如,RestTemplate 類具有 headForHeaders()、getForObject()、postForObject()、put()和 delete()等方法。
下面給大家上案例,案例是重點,通過案例,把我知道的用法都給盤出來。
2、案例代碼
2.1、git 地址
https://gitee.com/javacode2018/springmvc-series
2.2、關(guān)鍵代碼位置
文中的所有 controller 代碼,在RestTemplateTestController
類中。
所有@Test 用例的代碼,在RestTemplateTest
。
2.3、如何運行測試用例?
- 拉取項目
- 將 chat16-RestTemplate 模塊發(fā)布到 tomcat9 中
- 運行 RestTemplateTest 中對應(yīng)的用例即可
下面咱們來看 RestTemplate 常見的用法匯總。
3、發(fā)送 Get 請求
3.1、普通請求
接口代碼
@GetMapping("/test/get") @ResponseBody public BookDto get() { return new BookDto(1, "SpringMVC系列"); }
使用 RestTemplate 調(diào)用上面這個接口,通常有 2 種寫法,如下
@Test public void test1() { RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/chat16/test/get"; //getForObject方法,獲取響應(yīng)體,將其轉(zhuǎn)換為第二個參數(shù)指定的類型 BookDto bookDto = restTemplate.getForObject(url, BookDto.class); System.out.println(bookDto); } @Test public void test2() { RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/chat16/test/get"; //getForEntity方法,返回值為ResponseEntity類型 // ResponseEntity中包含了響應(yīng)結(jié)果中的所有信息,比如頭、狀態(tài)、body ResponseEntity<BookDto> responseEntity = restTemplate.getForEntity(url, BookDto.class); //狀態(tài)碼 System.out.println(responseEntity.getStatusCode()); //獲取頭 System.out.println("頭:" + responseEntity.getHeaders()); //獲取body BookDto bookDto = responseEntity.getBody(); System.out.println(bookDto); }
test1 輸出
BookDto{id=1, name='SpringMVC系列'}
test2 輸出
200 OK
頭:[Content-Type:"application/json;charset=UTF-8", Transfer-Encoding:"chunked", Date:"Sat, 02 Oct 2021 07:05:15 GMT", Keep-Alive:"timeout=20", Connection:"keep-alive"]
BookDto{id=1, name='SpringMVC系列'}
3.2、url 中含有動態(tài)參數(shù)
接口代碼
@GetMapping("/test/get/{id}/{name}") @ResponseBody public BookDto get(@PathVariable("id") Integer id, @PathVariable("name") String name) { return new BookDto(id, name); }
使用 RestTemplate 調(diào)用上面這個接口,通常有 2 種寫法,如下
@Test public void test3() { RestTemplate restTemplate = new RestTemplate(); //url中有動態(tài)參數(shù) String url = "http://localhost:8080/chat16/test/get/{id}/{name}"; Map<String, String> uriVariables = new HashMap<>(); uriVariables.put("id", "1"); uriVariables.put("name", "SpringMVC系列"); //使用getForObject或者getForEntity方法 BookDto bookDto = restTemplate.getForObject(url, BookDto.class, uriVariables); System.out.println(bookDto); } @Test public void test4() { RestTemplate restTemplate = new RestTemplate(); //url中有動態(tài)參數(shù) String url = "http://localhost:8080/chat16/test/get/{id}/{name}"; Map<String, String> uriVariables = new HashMap<>(); uriVariables.put("id", "1"); uriVariables.put("name", "SpringMVC系列"); //getForEntity方法 ResponseEntity<BookDto> responseEntity = restTemplate.getForEntity(url, BookDto.class, uriVariables); BookDto bookDto = responseEntity.getBody(); System.out.println(bookDto); }
test3 輸出
BookDto{id=1, name='SpringMVC系列'}
test4 輸出
BookDto{id=1, name='SpringMVC系列'}
3.3、接口返回值為泛型
接口代碼
@GetMapping("/test/getList") @ResponseBody public List<BookDto> getList() { return Arrays.asList( new BookDto(1, "Spring高手系列"), new BookDto(2, "SpringMVC系列") ); }
當(dāng)接口的返回值為泛型的時候,這種情況比較特殊,使用 RestTemplate 調(diào)用上面這個接口,代碼如下,需要用到restTemplate.exchange
的方法,這個方法中有個參數(shù)是ParameterizedTypeReference
類型,通過這個參數(shù)類指定泛型類型
@Test public void test5() { RestTemplate restTemplate = new RestTemplate(); //返回值為泛型 String url = "http://localhost:8080/chat16/test/getList"; //若返回結(jié)果是泛型類型的,需要使用到exchange方法, //這個方法中有個參數(shù)是ParameterizedTypeReference類型,通過這個參數(shù)類指定泛型類型 ResponseEntity<List<BookDto>> responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<List<BookDto>>() { }); List<BookDto> bookDtoList = responseEntity.getBody(); System.out.println(bookDtoList); }
輸出
[BookDto{id=1, name='Spring高手系列'}, BookDto{id=2, name='SpringMVC系列'}]
3.4、下載小文件
接口代碼如下,這個接口會下載服務(wù)器端的 1.txt 文件。
/** * 下載文件 * * @return */ @GetMapping("/test/downFile") @ResponseBody public HttpEntity<InputStreamResource> downFile() { //將文件流封裝為InputStreamResource對象 InputStream inputStream = this.getClass().getResourceAsStream("/1.txt"); InputStreamResource inputStreamResource = new InputStreamResource(inputStream); //設(shè)置header MultiValueMap<String, String> headers = new HttpHeaders(); headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=1.txt"); HttpEntity<InputStreamResource> httpEntity = new HttpEntity<>(inputStreamResource); return httpEntity; }
使用 RestTemplate 調(diào)用這個接口,代碼如下,目前這個文件的內(nèi)容比較少,可以直接得到一個數(shù)組。
@Test public void test6() { RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/chat16/test/downFile"; //文件比較小的情況,直接返回字節(jié)數(shù)組 ResponseEntity<byte[]> responseEntity = restTemplate.getForEntity(url, byte[].class); //獲取文件的內(nèi)容 byte[] body = responseEntity.getBody(); String content = new String(body); System.out.println(content); }
注意:如果文件大的時候,這種方式就有問題了,會導(dǎo)致 oom,要用下面的方式了。
3.5、下載大文件
接口代碼,繼續(xù)使用上面下載 1.txt 的代碼
/** * 下載文件 * * @return */ @GetMapping("/test/downFile") @ResponseBody public HttpEntity<InputStreamResource> downFile() { //將文件流封裝為InputStreamResource對象 InputStream inputStream = this.getClass().getResourceAsStream("/1.txt"); InputStreamResource inputStreamResource = new InputStreamResource(inputStream); //設(shè)置header MultiValueMap<String, String> headers = new HttpHeaders(); headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=1.txt"); HttpEntity<InputStreamResource> httpEntity = new HttpEntity<>(inputStreamResource); return httpEntity; }
此時使用 RestTemplate 調(diào)用這個接口,代碼如下
文件比較大的時候,比如好幾個 G,就不能返回字節(jié)數(shù)組了,會把內(nèi)存撐爆,導(dǎo)致 OOM,需要使用 execute 方法了,這個方法中有個 ResponseExtractor 類型的參數(shù),restTemplate 拿到結(jié)果之后,會回調(diào){@link ResponseExtractor#extractData}這個方法,在這個方法中可以拿到響應(yīng)流,然后進(jìn)行處理,這個過程就是變讀邊處理,不會導(dǎo)致內(nèi)存溢出
@Test public void test7() { RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/chat16/test/downFile"; /** * 文件比較大的時候,比如好幾個G,就不能返回字節(jié)數(shù)組了,會把內(nèi)存撐爆,導(dǎo)致OOM * 需要這么玩: * 需要使用execute方法了,這個方法中有個ResponseExtractor類型的參數(shù), * restTemplate拿到結(jié)果之后,會回調(diào){@link ResponseExtractor#extractData}這個方法, * 在這個方法中可以拿到響應(yīng)流,然后進(jìn)行處理,這個過程就是變讀邊處理,不會導(dǎo)致內(nèi)存溢出 */ String result = restTemplate.execute(url, HttpMethod.GET, null, new ResponseExtractor<String>() { @Override public String extractData(ClientHttpResponse response) throws IOException { System.out.println("狀態(tài):"+response.getStatusCode()); System.out.println("頭:"+response.getHeaders()); //獲取響應(yīng)體流 InputStream body = response.getBody(); //處理響應(yīng)體流 String content = IOUtils.toString(body, "UTF-8"); return content; } }, new HashMap<>()); System.out.println(result); }
3.6、傳遞頭
接口代碼
@GetMapping("/test/header") @ResponseBody public Map<String, List<String>> header(HttpServletRequest request) { Map<String, List<String>> header = new LinkedHashMap<>(); Enumeration<String> headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); Enumeration<String> values = request.getHeaders(name); List<String> list = new ArrayList<>(); while (values.hasMoreElements()) { list.add(values.nextElement()); } header.put(name, list); } return header; }
使用 RestTemplate 調(diào)用接口,請求頭中傳遞數(shù)據(jù),代碼如下,注意代碼①和②
,這兩處是關(guān)鍵,用到了HttpHeaders
和RequestEntity
- 請求頭放在 HttpHeaders 對象中
- RequestEntity:請求實體,請求的所有信息都可以放在 RequestEntity 中,比如 body 部分、頭、請求方式、url 等信息
@Test public void test8() { RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/chat16/test/header"; //①:請求頭放在HttpHeaders對象中 MultiValueMap<String, String> headers = new HttpHeaders(); headers.add("header-1", "V1"); headers.add("header-2", "Spring"); headers.add("header-2", "SpringBoot"); //②:RequestEntity:請求實體,請求的所有信息都可以放在RequestEntity中,比如body部分、頭、請求方式、url等信息 RequestEntity requestEntity = new RequestEntity( null, //body部分?jǐn)?shù)據(jù) headers, //頭 HttpMethod.GET,//請求方法 URI.create(url) //地址 ); ResponseEntity<Map<String, List<String>>> responseEntity = restTemplate.exchange(requestEntity, new ParameterizedTypeReference<Map<String, List<String>>>() { }); Map<String, List<String>> result = responseEntity.getBody(); System.out.println(result); }
輸出
{accept=[application/json, application/*+json], header-1=[V1], header-2=[Spring, SpringBoot], user-agent=[Java/1.8.0_121], host=[localhost:8080], connection=[keep-alive]}
3.7、綜合案例:含頭、url 動態(tài)參數(shù)
接口
@GetMapping("/test/getAll/{path1}/{path2}") @ResponseBody public Map<String, Object> getAll(@PathVariable("path1") String path1, @PathVariable("path2") String path2, HttpServletRequest request) { Map<String, Object> result = new LinkedHashMap<>(); result.put("path1", path1); result.put("path2", path2); //頭 Map<String, List<String>> header = new LinkedHashMap<>(); Enumeration<String> headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); Enumeration<String> values = request.getHeaders(name); List<String> list = new ArrayList<>(); while (values.hasMoreElements()) { list.add(values.nextElement()); } header.put(name, list); } result.put("header", header); return result; }
如下,使用 RestTemplate 調(diào)用接口,GET 方式、傳遞 header、path 中動態(tài)參數(shù)。
@Test public void test9() { RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/chat16/test/getAll/{path1}/{path2}"; //①:請求頭 MultiValueMap<String, String> headers = new HttpHeaders(); headers.add("header-1", "V1"); headers.add("header-2", "Spring"); headers.add("header-2", "SpringBoot"); //②:url中的2個參數(shù) Map<String, String> uriVariables = new HashMap<>(); uriVariables.put("path1", "v1"); uriVariables.put("path2", "v2"); //③:HttpEntity:HTTP實體,內(nèi)部包含了請求頭和請求體 HttpEntity requestEntity = new HttpEntity( null,//body部分,get請求沒有body,所以為null headers //頭 ); //④:使用exchange發(fā)送請求 ResponseEntity<Map<String, Object>> responseEntity = restTemplate.exchange( url, //url HttpMethod.GET, //請求方式 requestEntity, //請求實體(頭、body) new ParameterizedTypeReference<Map<String, Object>>() { },//返回的結(jié)果類型 uriVariables //url中的占位符對應(yīng)的值 ); Map<String, Object> result = responseEntity.getBody(); System.out.println(result); }
輸出
{path1=v1, path2=v2, header={accept=[application/json, application/*+json], header-1=[V1], header-2=[Spring, SpringBoot], user-agent=[Java/1.8.0_121], host=[localhost:8080], connection=[keep-alive]}}
4、POST 請求
4.1、post 請求常見的 3 種類型
http 請求頭中的 Content-Type 用來指定請求的類型,常見的有 3 種
Content-Type | 說明 |
---|---|
application/x-www-form-urlencoded | 頁面中普通的 form 表單提交時就是這種類型,表單中的元素會按照名稱和值拼接好,然后之間用&連接,格式如:p1=v1&p2=v2&p3=v3 然后通過 urlencoded 編碼之后丟在 body 中發(fā)送 |
multipart/form-data | 頁面中表單上傳文件的時候,用到的就是這種格式 |
application/json | 將發(fā)送的數(shù)據(jù)轉(zhuǎn)換為 json 格式,丟在 http 請求的 body 中發(fā)送,后端接口通常用@RequestBody 配合對象來接收。 |
下面看則種方式的案例。
4.2、普通表單請求
普通表單默認(rèn)為 application/x-www-form-urlencoded 類型的請求。
接口代碼
@PostMapping("/test/form1") @ResponseBody public BookDto form1(BookDto bookDto) { return bookDto; }
使用 RestTemplate 調(diào)用接口
@Test public void test10() { RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/chat16/test/form1"; //①:表單信息,需要放在MultiValueMap中,MultiValueMap相當(dāng)于Map<String,List<String>> MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); //調(diào)用add方法填充表單數(shù)據(jù)(表單名稱:值) body.add("id","1"); body.add("name","SpringMVC系列"); //②:發(fā)送請求(url,請求體,返回值需要轉(zhuǎn)換的類型) BookDto result = restTemplate.postForObject(url, body, BookDto.class); System.out.println(result); }
如果想攜帶頭信息,代碼如下
@Test public void test11() { RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/chat16/test/form1"; //①:表單信息,需要放在MultiValueMap中,MultiValueMap相當(dāng)于Map<String,List<String>> MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); //調(diào)用add方法放入表單元素(表單名稱:值) body.add("id","1"); body.add("name","SpringMVC系列"); //②:請求頭 HttpHeaders headers = new HttpHeaders(); //調(diào)用set方法放入請求頭 headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE); //③:請求實體:包含了請求體和請求頭 HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(body, headers); //④:發(fā)送請求(url,請求實體,返回值需要轉(zhuǎn)換的類型) BookDto result = restTemplate.postForObject(url, httpEntity, BookDto.class); System.out.println(result); }
4.3、上傳本地文件
上傳文件 Content-Type 為 multipart/form-data 類型。
接口如下,上傳上傳單個文件,返回值為一個 Map 類型,是泛型類型
@PostMapping(value = "/test/form2") @ResponseBody public Map<String, String> form2(@RequestParam("file1") MultipartFile file1) { Map<String, String> fileMetadata = new LinkedHashMap<>(); fileMetadata.put("文件名", file1.getOriginalFilename()); fileMetadata.put("文件類型", file1.getContentType()); fileMetadata.put("文件大小(byte)", String.valueOf(file1.getSize())); return fileMetadata; }
使用 RestTemplate 調(diào)用接口,主要下面代碼②
上傳的文件需要包裝為org.springframework.core.io.Resource
,常用的有 3 中[FileSystemResource、InputStreamResource、ByteArrayResource],這里案例中我們用到的是 FileSystemResource 來上傳本地文件,另外 2 種(InputStreamResource、ByteArrayResource)用法就比較特殊了,見下個案例。
@Test public void test12() { RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/chat16/test/form2"; //①:表單信息,需要放在MultiValueMap中,MultiValueMap相當(dāng)于Map<String,List<String>> MultiValueMap<String, Object> body = new LinkedMultiValueMap<>(); //調(diào)用add方法放入表單元素(表單名稱:值) //②:文件對應(yīng)的類型,需要是org.springframework.core.io.Resource類型的,常見的有[FileSystemResource、InputStreamResource、ByteArrayResource] body.add("file1", new FileSystemResource(".\\src\\main\\java\\com\\javacode2018\\springmvc\\chat16\\dto\\UserDto.java")); //③:頭 HttpHeaders headers = new HttpHeaders(); headers.add("header1", "v1"); headers.add("header2", "v2"); //④:請求實體 RequestEntity<MultiValueMap<String, Object>> requestEntity = new RequestEntity<>(body, headers, HttpMethod.POST, URI.create(url)); //⑤:發(fā)送請求(請求實體,返回值需要轉(zhuǎn)換的類型) ResponseEntity<Map<String, String>> responseEntity = restTemplate.exchange( requestEntity, new ParameterizedTypeReference<Map<String, String>>() { }); Map<String, String> result = responseEntity.getBody(); System.out.println(result); }
4.4、通過流或字節(jié)數(shù)組的方式上傳文件
有時候,上傳的文件是通過流的方式或者字節(jié)數(shù)組的方式,那么就需要用到 InputStreamResource、ByteArrayResource 這倆了。
**注意:**使用這倆的時候,需要重寫 2 個方法,否則會上傳失敗
getFilename:文件名稱
contentLength:長度
@Test public void test13() { RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/chat16/test/form2"; //①:表單信息,需要放在MultiValueMap中,MultiValueMap相當(dāng)于Map<String,List<String>> MultiValueMap<String, Object> body = new LinkedMultiValueMap<>(); /** * ②:通過流的方式上傳文件,流的方式需要用到InputStreamResource類,需要重寫2個方法 * getFilename:文件名稱 * contentLength:長度 */ InputStream inputStream = RestTemplateTest.class.getResourceAsStream("/1.txt"); InputStreamResource inputStreamResource = new InputStreamResource(inputStream) { @Override public String getFilename() { return "1.txt"; } @Override public long contentLength() throws IOException { return inputStream.available(); } }; body.add("file1", inputStreamResource); //③:頭 HttpHeaders headers = new HttpHeaders(); headers.add("header1", "v1"); headers.add("header2", "v2"); //④:請求實體 RequestEntity<MultiValueMap<String, Object>> requestEntity = new RequestEntity<>(body, headers, HttpMethod.POST, URI.create(url)); //⑤:發(fā)送請求(請求實體,返回值需要轉(zhuǎn)換的類型) ResponseEntity<Map<String, String>> responseEntity = restTemplate.exchange( requestEntity, new ParameterizedTypeReference<Map<String, String>>() { }); Map<String, String> result = responseEntity.getBody(); System.out.println(result); }
4.5、復(fù)雜表單:多個普通元素+多文件上傳
接口
/** * 復(fù)雜的表單:包含了普通元素、多文件 * * @param userDto * @return */ @PostMapping("/test/form3") @ResponseBody public Map<String, String> form3(UserDto userDto) { Map<String, String> result = new LinkedHashMap<>(); result.put("name", userDto.getName()); result.put("headImg", userDto.getHeadImg().getOriginalFilename()); result.put("idImgList", Arrays.toString(userDto.getIdImgList().stream(). map(MultipartFile::getOriginalFilename).toArray())); return result; }
UserDto:包含了多個元素(姓名、頭像、多張證件照),這種可以模擬復(fù)雜的表單
public class UserDto { //姓名 private String name; //頭像 private MultipartFile headImg; //多張證件照 private List<MultipartFile> idImgList; //get set 省略了... }
用 RestTemplate 調(diào)用這個接口,代碼如下
@Test public void test14() { RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/chat16/test/form3"; //①:表單信息,需要放在MultiValueMap中,MultiValueMap相當(dāng)于Map<String,List<String>> MultiValueMap<String, Object> body = new LinkedMultiValueMap<>(); body.add("name", "路人"); body.add("headImg", new FileSystemResource(".\\src\\main\\resources\\1.jpg")); //來2張證件照,元素名稱一樣 body.add("idImgList", new FileSystemResource(".\\src\\main\\resources\\2.jpg")); body.add("idImgList", new FileSystemResource(".\\src\\main\\resources\\3.jpg")); //③:頭 HttpHeaders headers = new HttpHeaders(); headers.add("header1", "v1"); headers.add("header2", "v2"); //④:請求實體 RequestEntity<MultiValueMap<String, Object>> requestEntity = new RequestEntity<>(body, headers, HttpMethod.POST, URI.create(url)); //⑤:發(fā)送請求(請求實體,返回值需要轉(zhuǎn)換的類型) ResponseEntity<Map<String, String>> responseEntity = restTemplate.exchange( requestEntity, new ParameterizedTypeReference<Map<String, String>>() { }); Map<String, String> result = responseEntity.getBody(); System.out.println(result); }
輸出
{name=路人, headImg=1.jpg, idImgList=[2.jpg, 3.jpg]}
4.6、發(fā)送 json 格式數(shù)據(jù):傳遞 java 對象
接口
/** * body中json格式的數(shù)據(jù),返回值非泛型 * * @param bookDto * @return */ @PostMapping("/test/form4") @ResponseBody public BookDto form4(@RequestBody BookDto bookDto) { return bookDto; }
RestTemplate 調(diào)用接口
@Test public void test15() { RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/chat16/test/form4"; BookDto body = new BookDto(1, "SpringMVC系列"); BookDto result = restTemplate.postForObject(url, body, BookDto.class); System.out.println(result); }
輸出
BookDto{id=1, name='SpringMVC系列'}
4.7、發(fā)送 json 格式數(shù)據(jù):傳遞 java 對象,返回值為泛型
接口
/** * body中json格式的數(shù)據(jù),返回值為泛型 * * @param bookDtoList * @return */ @PostMapping("/test/form5") @ResponseBody public List<BookDto> form5(@RequestBody List<BookDto> bookDtoList) { return bookDtoList; }
用 RestTemplate 調(diào)用這個接口,代碼如下
@Test public void test16() { RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/chat16/test/form5"; //①:請求體,發(fā)送的時候會被轉(zhuǎn)換為json格式數(shù)據(jù) List<BookDto> body = Arrays.asList( new BookDto(1, "SpringMVC系列"), new BookDto(2, "MySQL系列")); //②:頭 HttpHeaders headers = new HttpHeaders(); headers.add("header1", "v1"); headers.add("header2", "v2"); //③:請求實體 RequestEntity requestEntity = new RequestEntity(body, headers, HttpMethod.POST, URI.create(url)); //④:發(fā)送請求(請求實體,返回值需要轉(zhuǎn)換的類型) ResponseEntity<List<BookDto>> responseEntity = restTemplate.exchange( requestEntity, new ParameterizedTypeReference<List<BookDto>>() { }); //⑤:獲取結(jié)果 List<BookDto> result = responseEntity.getBody(); System.out.println(result); }
輸出
[BookDto{id=1, name='SpringMVC系列'}, BookDto{id=2, name='MySQL系列'}]
4.8、發(fā)送 json 字符串格式數(shù)據(jù)
上面 2 個 json 案例 body 都是 java 對象,RestTemplate 默認(rèn)自動配上 Content-Type=application/json
但是如果 body 的值是 json 格式字符串的時候,調(diào)用的時候需要在頭中明確指定 Content-Type=application/json,寫法如下:
public void delete(String url, Object... uriVariables); public void delete(String url, Map<String, ?> uriVariables); public void delete(URI url);
輸出
[BookDto{id=1, name='SpringMVC系列'}, BookDto{id=2, name='MySQL系列'}]
5、DELETE、PUT、OPTION 請求
5.1、DELETE 請求
public void delete(String url, Object... uriVariables); public void delete(String url, Map<String, ?> uriVariables); public void delete(URI url);
5.2、PUT 請求
PUT 請求和 POST 請求類似,將類型改為 PUT 就可以了。
5.3、OPTIONS 請求
OPTIONS 請求用來探測接口支持哪些 http 方法
public Set<HttpMethod> optionsForAllow(String url, Object... uriVariables); public Set<HttpMethod> optionsForAllow(String url, Map<String, ?> uriVariables); public Set<HttpMethod> optionsForAllow(URI url);
6、集成 HttpClient
RestTemplate 內(nèi)部默認(rèn)用的是 jdk 自帶的 HttpURLConnection 發(fā)送請求的,性能上面并不是太突出。
可以將其替換為 httpclient 或者 okhttp。
先來看下如何替換為 HttpClient。
引入 maven 配置
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.7</version> </dependency>
創(chuàng)建 RestTemplate 時指定 HttpClient 配置,代碼如下
public HttpClient httpClient() { HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); try { //設(shè)置信任ssl訪問 SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build(); httpClientBuilder.setSSLContext(sslContext); HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() // 注冊http和https請求 .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", sslConnectionSocketFactory).build(); //使用Httpclient連接池的方式配置(推薦),同時支持netty,okHttp以及其他http框架 PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); // 最大連接數(shù) poolingHttpClientConnectionManager.setMaxTotal(1000); // 同路由并發(fā)數(shù) poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); //配置連接池 httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager); // 重試次數(shù) httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(0, true)); //設(shè)置默認(rèn)請求頭 List<Header> headers = new ArrayList<>(); httpClientBuilder.setDefaultHeaders(headers); return httpClientBuilder.build(); } catch (Exception e) { throw new RuntimeException(e); } } public ClientHttpRequestFactory clientHttpRequestFactory() { HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient()); // 連接超時(毫秒),這里設(shè)置10秒 clientHttpRequestFactory.setConnectTimeout(10 * 1000); // 數(shù)據(jù)讀取超時時間(毫秒),這里設(shè)置60秒 clientHttpRequestFactory.setReadTimeout(60 * 1000); // 從連接池獲取請求連接的超時時間(毫秒),不宜過長,必須設(shè)置,比如連接不夠用時,時間過長將是災(zāi)難性的 clientHttpRequestFactory.setConnectionRequestTimeout(10 * 1000); return clientHttpRequestFactory; } public RestTemplate restTemplate(){ //創(chuàng)建RestTemplate的時候,指定ClientHttpRequestFactory return new RestTemplate(this.clientHttpRequestFactory()); } @Test public void test18() { RestTemplate restTemplate = this.restTemplate(); String url = "http://localhost:8080/chat16/test/get"; //getForObject方法,獲取響應(yīng)體,將其轉(zhuǎn)換為第二個參數(shù)指定的類型 BookDto bookDto = restTemplate.getForObject(url, BookDto.class); System.out.println(bookDto); }
7、集成 okhttp
引入 maven 配置
<dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.3.1</version> </dependency>
創(chuàng)建 RestTemplate
new RestTemplate(new OkHttp3ClientHttpRequestFactory());
8、總結(jié)
RestTemplate 使用確實非常容易,建議大家去看一下 RestTemplate 的源碼,debug 跟蹤一下過程,這樣用起來就非常順手了。
到此這篇關(guān)于RestTemplate接口調(diào)用神器常見用法匯總的文章就介紹到這了,更多相關(guān)RestTemplate接口調(diào)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot 如何使用RestTemplate來調(diào)用接口
- SpringBoot-RestTemplate如何實現(xiàn)調(diào)用第三方API
- Spring boot2X Consul如何通過RestTemplate實現(xiàn)服務(wù)調(diào)用
- 關(guān)于SpringBoot大文件RestTemplate下載解決方案
- 基于springboot的RestTemplate、okhttp和HttpClient對比分析
- 關(guān)于springboot 中使用httpclient或RestTemplate做MultipartFile文件跨服務(wù)傳輸?shù)膯栴}
- Spring遠(yuǎn)程調(diào)用HttpClient/RestTemplate的方法
- Springboot使用RestTemplate調(diào)用第三方接口的操作代碼
相關(guān)文章
一文讀懂a(chǎn)va中的Volatile關(guān)鍵字使用
volatile關(guān)鍵字的作用保證了變量的可見性(visibility)。被volatile關(guān)鍵字修飾的變量,如果值發(fā)生了變更,其他線程立馬可見,避免出現(xiàn)臟讀的現(xiàn)象。這篇文章主要介紹了ava中的Volatile關(guān)鍵字使用,需要的朋友可以參考下2020-03-03解決IDEA service層跳轉(zhuǎn)實現(xiàn)類的快捷圖標(biāo)消失問題
這篇文章主要介紹了解決IDEA service層跳轉(zhuǎn)實現(xiàn)類的快捷圖標(biāo)消失問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02MyBatis中如何接收String類型的參數(shù)實現(xiàn)
這篇文章主要介紹了MyBatis中如何接收String類型的參數(shù)實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02SpringBoot集成WebSocket【基于純H5】進(jìn)行點對點[一對一]和廣播[一對多]實時推送
這篇文章主要介紹了SpringBoot集成WebSocket【基于純H5】進(jìn)行點對點[一對一]和廣播[一對多]實時推送,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-08-08Javaweb實現(xiàn)完整個人博客系統(tǒng)流程
這篇文章主要介紹了怎樣用Java來實現(xiàn)一個完整的個人博客系統(tǒng),我們通過實操上手的方式可以高效的鞏固所學(xué)的基礎(chǔ)知識,感興趣的朋友一起來看看吧2022-03-03