RestTemplate接口調(diào)用神器常見用法匯總
1、RestTemplate 概述
發(fā)送 http 請求,估計(jì)很多人用過 httpclient 和 okhttp,確實(shí)挺好用的,而 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è)計(jì)原則與許多其他 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è)計(jì)的,因此它的主要方法與 REST 的基礎(chǔ)緊密相連就不足為奇了,后者是 HTTP 協(xié)議的方法:HEAD、GET、POST、PUT、DELETE 和 OPTIONS。例如,RestTemplate 類具有 headForHeaders()、getForObject()、postForObject()、put()和 delete()等方法。
下面給大家上案例,案例是重點(diǎn),通過案例,把我知道的用法都給盤出來。
2、案例代碼
2.1、git 地址
https://gitee.com/javacode2018/springmvc-series

2.2、關(guān)鍵代碼位置
文中的所有 controller 代碼,在RestTemplateTestController類中。
所有@Test 用例的代碼,在RestTemplateTest。

2.3、如何運(yùn)行測試用例?
- 拉取項(xiàng)目
- 將 chat16-RestTemplate 模塊發(fā)布到 tomcat9 中
- 運(yùn)行 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:請求實(shí)體,請求的所有信息都可以放在 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:請求實(shí)體,請求的所有信息都可以放在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實(shí)體,內(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, //請求實(shí)體(頭、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);
//③:請求實(shí)體:包含了請求體和請求頭
HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(body, headers);
//④:發(fā)送請求(url,請求實(shí)體,返回值需要轉(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");
//④:請求實(shí)體
RequestEntity<MultiValueMap<String, Object>> requestEntity = new RequestEntity<>(body, headers, HttpMethod.POST, URI.create(url));
//⑤:發(fā)送請求(請求實(shí)體,返回值需要轉(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");
//④:請求實(shí)體
RequestEntity<MultiValueMap<String, Object>> requestEntity = new RequestEntity<>(body, headers, HttpMethod.POST, URI.create(url));
//⑤:發(fā)送請求(請求實(shí)體,返回值需要轉(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");
//④:請求實(shí)體
RequestEntity<MultiValueMap<String, Object>> requestEntity = new RequestEntity<>(body, headers, HttpMethod.POST, URI.create(url));
//⑤:發(fā)送請求(請求實(shí)體,返回值需要轉(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");
//③:請求實(shí)體
RequestEntity requestEntity = new RequestEntity(body, headers, HttpMethod.POST, URI.create(url));
//④:發(fā)送請求(請求實(shí)體,返回值需要轉(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 使用確實(shí)非常容易,建議大家去看一下 RestTemplate 的源碼,debug 跟蹤一下過程,這樣用起來就非常順手了。
到此這篇關(guān)于RestTemplate接口調(diào)用神器常見用法匯總的文章就介紹到這了,更多相關(guān)RestTemplate接口調(diào)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot 如何使用RestTemplate來調(diào)用接口
- SpringBoot-RestTemplate如何實(shí)現(xiàn)調(diào)用第三方API
- Spring boot2X Consul如何通過RestTemplate實(shí)現(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)實(shí)現(xiàn)類的快捷圖標(biāo)消失問題
這篇文章主要介紹了解決IDEA service層跳轉(zhuǎn)實(shí)現(xiàn)類的快捷圖標(biāo)消失問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
MyBatis中如何接收String類型的參數(shù)實(shí)現(xiàn)
這篇文章主要介紹了MyBatis中如何接收String類型的參數(shù)實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
SpringBoot集成WebSocket【基于純H5】進(jìn)行點(diǎn)對點(diǎn)[一對一]和廣播[一對多]實(shí)時推送
這篇文章主要介紹了SpringBoot集成WebSocket【基于純H5】進(jìn)行點(diǎn)對點(diǎn)[一對一]和廣播[一對多]實(shí)時推送,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
Javaweb實(shí)現(xiàn)完整個人博客系統(tǒng)流程
這篇文章主要介紹了怎樣用Java來實(shí)現(xiàn)一個完整的個人博客系統(tǒng),我們通過實(shí)操上手的方式可以高效的鞏固所學(xué)的基礎(chǔ)知識,感興趣的朋友一起來看看吧2022-03-03

