文末可以領取所有系列高清 pdf,
大家好,我是路人,這是 SpringMVC 系列第 21 篇,
本文介紹 Spring web 中特別牛逼的一個類 RestTemplate,
目錄
1、RestTemplate 概述
2、案例代碼
2.1、git 地址
2.2、關鍵代碼位置
2.3、如何運行測驗用例?
3、發送 Get 請求
3.1、普通請求
3.2、url 中含有動態引數
3.3、介面回傳值為泛型
3.4、下載小檔案
3.5、下載大檔案
3.6、傳遞頭
3.7、綜合案例:含頭、url 動態引數
4、POST 請求
4.1、post 請求常見的 3 種型別
4.2、普通表單請求
4.3、上傳本地檔案
4.4、通過流或位元組陣列的方式上傳檔案
4.5、復雜表單:多個普通元素+多檔案上傳
4.6、發送 json 格式資料:傳遞 java 物件
4.7、發送 json 格式資料:傳遞 java 物件,回傳值為泛型
4.8、發送 json 字串格式資料
5、DELETE、PUT、OPTION 請求
5.1、DELETE 請求
5.2、PUT 請求
5.3、OPTIONS 請求
6、集成 HttpClient
7、集成 okhttp
8、總結
9、SpringMVC 系列目錄
10、更多好文章
11、【路人甲 Java】所有系列高清 PDF
1、RestTemplate 概述
發送 http 請求,估計很多人用過 httpclient 和 okhttp,確實挺好用的,而 Spring web 中的 RestTemplate 和這倆的功能類似,也是用來發送 http 請求的,不過用法上面比前面的 2 位要容易很多,
spring 框架提供的 RestTemplate 類可用于在應用中呼叫 rest 服務,它簡化了與 http 服務的通信方式,統一了 RESTful 的標準,封裝了 http 鏈接, 我們只需要傳入 url 及回傳值型別即可,相較于之前常用的 HttpClient,RestTemplate 是一種更優雅的呼叫 RESTful 服務的方式,
在 Spring 應用程式中訪問第三方 REST 服務與使用 Spring RestTemplate 類有關,RestTemplate 類的設計原則與許多其他 Spring 模板類(例如 JdbcTemplate、JmsTemplate)相同,為執行復雜任務提供了一種具有默認行為的簡化方法,
RestTemplate 默認依賴 JDK 提供 http 連接的能力(HttpURLConnection),如果有需要的話也可以通過 setRequestFactory 方法替換為例如 Apache HttpComponents、Netty 或 OkHttp 等其它 HTTP library,
考慮到 RestTemplate 類是為呼叫 REST 服務而設計的,因此它的主要方法與 REST 的基礎緊密相連就不足為奇了,后者是 HTTP 協議的方法:HEAD、GET、POST、PUT、DELETE 和 OPTIONS,例如,RestTemplate 類具有 headForHeaders()、getForObject()、postForObject()、put()和 delete()等方法,
下面給大家上案例,案例是重點,通過案例,把我知道的用法都給盤出來,
2、案例代碼
2.1、git 地址
https://gitee.com/javacode2018/springmvc-series

2.2、關鍵代碼位置
文中的所有 controller 代碼,在RestTemplateTestController類中,
所有@Test 用例的代碼,在RestTemplateTest,

2.3、如何運行測驗用例?
拉取專案
將 chat16-RestTemplate 模塊發布到 tomcat9 中
運行 RestTemplateTest 中對應的用例即可
下面咱們來看 RestTemplate 常見的用法匯總,
3、發送 Get 請求
3.1、普通請求
介面代碼
@GetMapping("/test/get")
@ResponseBody
public BookDto get() {
return new BookDto(1, "SpringMVC系列");
}
使用 RestTemplate 呼叫上面這個介面,通常有 2 種寫法,如下
@Test
public void test1() {
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/chat16/test/get";
//getForObject方法,獲取回應體,將其轉換為第二個引數指定的型別
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中包含了回應結果中的所有資訊,比如頭、狀態、body
ResponseEntity<BookDto> responseEntity = restTemplate.getForEntity(url, BookDto.class);
//狀態碼
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 中含有動態引數
介面代碼
@GetMapping("/test/get/{id}/{name}")
@ResponseBody
public BookDto get(@PathVariable("id") Integer id, @PathVariable("name") String name) {
return new BookDto(id, name);
}
使用 RestTemplate 呼叫上面這個介面,通常有 2 種寫法,如下
@Test
public void test3() {
RestTemplate restTemplate = new RestTemplate();
//url中有動態引數
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中有動態引數
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系列")
);
}
當介面的回傳值為泛型的時候,這種情況比較特殊,使用 RestTemplate 呼叫上面這個介面,代碼如下,需要用到restTemplate.exchange的方法,這個方法中有個引數是ParameterizedTypeReference型別,通過這個引數類指定泛型型別
@Test
public void test5() {
RestTemplate restTemplate = new RestTemplate();
//回傳值為泛型
String url = "http://localhost:8080/chat16/test/getList";
//若回傳結果是泛型型別的,需要使用到exchange方法,
//這個方法中有個引數是ParameterizedTypeReference型別,通過這個引數類指定泛型型別
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、下載小檔案
介面代碼如下,這個介面會下載服務器端的 1.txt 檔案,
/**
* 下載檔案
*
* @return
*/
@GetMapping("/test/downFile")
@ResponseBody
public HttpEntity<InputStreamResource> downFile() {
//將檔案流封裝為InputStreamResource物件
InputStream inputStream = this.getClass().getResourceAsStream("/1.txt");
InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
//設定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 呼叫這個介面,代碼如下,目前這個檔案的內容比較少,可以直接得到一個陣列,
@Test
public void test6() {
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/chat16/test/downFile";
//檔案比較小的情況,直接回傳位元組陣列
ResponseEntity<byte[]> responseEntity = restTemplate.getForEntity(url, byte[].class);
//獲取檔案的內容
byte[] body = responseEntity.getBody();
String content = new String(body);
System.out.println(content);
}
注意:如果檔案大的時候,這種方式就有問題了,會導致 oom,要用下面的方式了,
3.5、下載大檔案
介面代碼,繼續使用上面下載 1.txt 的代碼
/**
* 下載檔案
*
* @return
*/
@GetMapping("/test/downFile")
@ResponseBody
public HttpEntity<InputStreamResource> downFile() {
//將檔案流封裝為InputStreamResource物件
InputStream inputStream = this.getClass().getResourceAsStream("/1.txt");
InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
//設定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 呼叫這個介面,代碼如下
檔案比較大的時候,比如好幾個 G,就不能回傳位元組陣列了,會把記憶體撐爆,導致 OOM,需要使用 execute 方法了,這個方法中有個 ResponseExtractor 型別的引數,restTemplate 拿到結果之后,會回呼{@link ResponseExtractor#extractData}這個方法,在這個方法中可以拿到回應流,然后進行處理,這個程序就是變讀邊處理,不會導致記憶體溢位
@Test
public void test7() {
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/chat16/test/downFile";
/**
* 檔案比較大的時候,比如好幾個G,就不能回傳位元組陣列了,會把記憶體撐爆,導致OOM
* 需要這么玩:
* 需要使用execute方法了,這個方法中有個ResponseExtractor型別的引數,
* restTemplate拿到結果之后,會回呼{@link ResponseExtractor#extractData}這個方法,
* 在這個方法中可以拿到回應流,然后進行處理,這個程序就是變讀邊處理,不會導致記憶體溢位
*/
String result = restTemplate.execute(url,
HttpMethod.GET,
null,
new ResponseExtractor<String>() {
@Override
public String extractData(ClientHttpResponse response) throws IOException {
System.out.println("狀態:"+response.getStatusCode());
System.out.println("頭:"+response.getHeaders());
//獲取回應體流
InputStream body = response.getBody();
//處理回應體流
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 呼叫介面,請求頭中傳遞資料,代碼如下,注意代碼①和②,這兩處是關鍵,用到了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部分資料
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 動態引數
介面
@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 呼叫介面,GET 方式、傳遞 header、path 中動態引數,
@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個引數
Map<String, String> uriVariables = new HashMap<>();
uriVariables.put("path1", "v1");
uriVariables.put("path2", "v2");
//③:HttpEntity:HTTP物體,內部包含了請求頭和請求體
HttpEntity requestEntity = new HttpEntity(
null,//body部分,get請求沒有body,所以為null
headers //頭
);
//④:使用exchange發送請求
ResponseEntity<Map<String, Object>> responseEntity = restTemplate.exchange(
url, //url
HttpMethod.GET, //請求方式
requestEntity, //請求物體(頭、body)
new ParameterizedTypeReference<Map<String, Object>>() {
},//回傳的結果型別
uriVariables //url中的占位符對應的值
);
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 中發送 |
| multipart/form-data | 頁面中表單上傳檔案的時候,用到的就是這種格式 |
| application/json | 將發送的資料轉換為 json 格式,丟在 http 請求的 body 中發送,后端介面通常用@RequestBody 配合物件來接收, |
下面看則種方式的案例,
4.2、普通表單請求
普通表單默認為 application/x-www-form-urlencoded 型別的請求,
介面代碼
@PostMapping("/test/form1")
@ResponseBody
public BookDto form1(BookDto bookDto) {
return bookDto;
}
使用 RestTemplate 呼叫介面
@Test
public void test10() {
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/chat16/test/form1";
//①:表單資訊,需要放在MultiValueMap中,MultiValueMap相當于Map<String,List<String>>
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
//呼叫add方法填充表單資料(表單名稱:值)
body.add("id","1");
body.add("name","SpringMVC系列");
//②:發送請求(url,請求體,回傳值需要轉換的型別)
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相當于Map<String,List<String>>
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
//呼叫add方法放入表單元素(表單名稱:值)
body.add("id","1");
body.add("name","SpringMVC系列");
//②:請求頭
HttpHeaders headers = new HttpHeaders();
//呼叫set方法放入請求頭
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
//③:請求物體:包含了請求體和請求頭
HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(body, headers);
//④:發送請求(url,請求物體,回傳值需要轉換的型別)
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 呼叫介面,主要下面代碼②上傳的檔案需要包裝為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相當于Map<String,List<String>>
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
//呼叫add方法放入表單元素(表單名稱:值)
//②:檔案對應的型別,需要是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));
//⑤:發送請求(請求物體,回傳值需要轉換的型別)
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、通過流或位元組陣列的方式上傳檔案
有時候,上傳的檔案是通過流的方式或者位元組陣列的方式,那么就需要用到 InputStreamResource、ByteArrayResource 這倆了,
**注意:**使用這倆的時候,需要重寫 2 個方法,否則會上傳失敗
getFilename:檔案名稱
contentLength:長度
@Test
public void test13() {
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/chat16/test/form2";
//①:表單資訊,需要放在MultiValueMap中,MultiValueMap相當于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));
//⑤:發送請求(請求物體,回傳值需要轉換的型別)
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、復雜表單:多個普通元素+多檔案上傳
介面
/**
* 復雜的表單:包含了普通元素、多檔案
*
* @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:包含了多個元素(姓名、頭像、多張證件照),這種可以模擬復雜的表單
public class UserDto {
//姓名
private String name;
//頭像
private MultipartFile headImg;
//多張證件照
private List<MultipartFile> idImgList;
//get set 省略了...
}
用 RestTemplate 呼叫這個介面,代碼如下
@Test
public void test14() {
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/chat16/test/form3";
//①:表單資訊,需要放在MultiValueMap中,MultiValueMap相當于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));
//⑤:發送請求(請求物體,回傳值需要轉換的型別)
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、發送 json 格式資料:傳遞 java 物件
介面
/**
* body中json格式的資料,回傳值非泛型
*
* @param bookDto
* @return
*/
@PostMapping("/test/form4")
@ResponseBody
public BookDto form4(@RequestBody BookDto bookDto) {
return bookDto;
}
RestTemplate 呼叫介面
@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、發送 json 格式資料:傳遞 java 物件,回傳值為泛型
介面
/**
* body中json格式的資料,回傳值為泛型
*
* @param bookDtoList
* @return
*/
@PostMapping("/test/form5")
@ResponseBody
public List<BookDto> form5(@RequestBody List<BookDto> bookDtoList) {
return bookDtoList;
}
用 RestTemplate 呼叫這個介面,代碼如下
@Test
public void test16() {
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/chat16/test/form5";
//①:請求體,發送的時候會被轉換為json格式資料
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));
//④:發送請求(請求物體,回傳值需要轉換的型別)
ResponseEntity<List<BookDto>> responseEntity = restTemplate.exchange(
requestEntity,
new ParameterizedTypeReference<List<BookDto>>() {
});
//⑤:獲取結果
List<BookDto> result = responseEntity.getBody();
System.out.println(result);
}
輸出
[BookDto{id=1, name='SpringMVC系列'}, BookDto{id=2, name='MySQL系列'}]
4.8、發送 json 字串格式資料
上面 2 個 json 案例 body 都是 java 物件,RestTemplate 默認自動配上 Content-Type=application/json
但是如果 body 的值是 json 格式字串的時候,呼叫的時候需要在頭中明確指定 Content-Type=application/json,寫法如下:
@Test
public void test17() {
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/chat16/test/form5";
//①:請求體為一個json格式的字串
String body = "[{\"id\":1,\"name\":\"SpringMVC系列\"},{\"id\":2,\"name\":\"MySQL系列\"}]";
/**
* ②:若請求體為json字串的時候,需要在頭中設定Content-Type=application/json;
* 若body是普通的java類的時候,無需指定這個,RestTemplate默認自動配上Content-Type=application/json
*/
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
//③:請求物體(body,頭、請求方式,uri)
RequestEntity requestEntity = new RequestEntity(body, headers, HttpMethod.POST, URI.create(url));
//④:發送請求(請求物體,回傳值需要轉換的型別)
ResponseEntity<List<BookDto>> responseEntity = restTemplate.exchange(
requestEntity,
new ParameterizedTypeReference<List<BookDto>>() {
});
//⑤:獲取結果
List<BookDto> result = responseEntity.getBody();
System.out.println(result);
}
輸出
[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 內部默認用的是 jdk 自帶的 HttpURLConnection 發送請求的,性能上面并不是太突出,
可以將其替換為 httpclient 或者 okhttp,
先來看下如何替換為 HttpClient,
引入 maven 配置
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.7</version>
</dependency>
創建 RestTemplate 時指定 HttpClient 配置,代碼如下
public HttpClient httpClient() {
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
try {
//設定信任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);
// 最大連接數
poolingHttpClientConnectionManager.setMaxTotal(1000);
// 同路由并發數
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);
//配置連接池
httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
// 重試次數
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(0, true));
//設定默認請求頭
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());
// 連接超時(毫秒),這里設定10秒
clientHttpRequestFactory.setConnectTimeout(10 * 1000);
// 資料讀取超時時間(毫秒),這里設定60秒
clientHttpRequestFactory.setReadTimeout(60 * 1000);
// 從連接池獲取請求連接的超時時間(毫秒),不宜過長,必須設定,比如連接不夠用時,時間過長將是災難性的
clientHttpRequestFactory.setConnectionRequestTimeout(10 * 1000);
return clientHttpRequestFactory;
}
public RestTemplate restTemplate(){
//創建RestTemplate的時候,指定ClientHttpRequestFactory
return new RestTemplate(this.clientHttpRequestFactory());
}
@Test
public void test18() {
RestTemplate restTemplate = this.restTemplate();
String url = "http://localhost:8080/chat16/test/get";
//getForObject方法,獲取回應體,將其轉換為第二個引數指定的型別
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>
創建 RestTemplate
new RestTemplate(new OkHttp3ClientHttpRequestFactory());
8、總結
RestTemplate 使用確實非常容易,建議大家去看一下 RestTemplate 的原始碼,debug 跟蹤一下程序,這樣用起來就非常順手了,
《尚硅谷 Java 學科全套教程(總 207.77GB)
9、SpringMVC 系列目錄
SpringMVC 系列第 1 篇:helloword
SpringMVC 系列第 2 篇:@Controller、@RequestMapping
SpringMVC 系列第 3 篇:例外高效的一款介面測驗利器
SpringMVC 系列第 4 篇:controller 常見的接收引數的方式
SpringMVC 系列第 5 篇:@RequestBody 大解密,說點你不知道的
SpringMVC 系列第 6 篇:上傳檔案的 4 種方式,你都會么?
SpringMVC 系列第 7 篇:SpringMVC 回傳視圖常見的 5 種方式,你會幾種?
SpringMVC 系列第 8 篇:回傳 json & 通用回傳值設計
SpringMVC 系列第 9 篇:SpringMVC 回傳 null 是什么意思?
SpringMVC 系列第 10 篇:異步處理
SpringMVC 系列第 11 篇:集成靜態資源
SpringMVC 系列第 12 篇:攔截器
SpringMVC 系列第 13 篇:統一例外處理
SpringMVC 系列第 14 篇:實戰篇:通用回傳值 & 例外處理設計
SpringMVC 系列第 15 篇:全注解的方式 & 原理決議
SpringMVC 系列第 16 篇:通過原始碼決議 SpringMVC 處理請求的流程
SpringMVC 系列第 17 篇:原始碼決議 SpringMVC 容器的啟動程序
SpringMVC 系列第 18 篇:強大的 RequestBodyAdvice 解密
SpringMVC 系列第 19 篇:強大的 ResponseBodyAdvice 解密
SpringMVC 系列第 20 篇:RestFull 詳解
10、更多好文章
Spring 高手系列(共 56 篇)
Java 高并發系列(共 34 篇)
MySql 高手系列(共 27 篇)
Maven 高手系列(共 10 篇)
Mybatis 系列(共 12 篇)
聊聊 db 和快取一致性常見的實作方式
介面冪等性這么重要,它是什么?怎么實作?
泛型,有點難度,會讓很多人懵逼,那是因為你沒有看這篇文章!
11、【路人甲 Java】所有系列高清 PDF
領取方式,掃碼發送:yyds

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/345786.html
標籤:其他
上一篇:OkHttp快取篇
下一篇:iOS15適配本地通知功能
