小白一看就會(huì)的Spring的RestTemplate的使用
寫在前面
您好,我是碼農(nóng)飛哥,感謝您閱讀此文。作為一名Java開發(fā)者,我們?cè)趺炊祭@不開調(diào)用外部接口的場(chǎng)景,調(diào)用的方式要么是通過(guò)Http協(xié)議來(lái)調(diào)用,要么是通過(guò)RPC協(xié)議來(lái)調(diào)用,通過(guò)Http協(xié)議調(diào)用的話我們就需要用到Http的Api。比較常用的有Apache的HttpClient和原生的HttpURLConnection。這些Api都比較好用,但是我們今天要介紹一種更加好用API,Spring自帶的RestTemplate,能力更強(qiáng),使用更方便。
目錄
寫在前面
怎么用?
SpringBoot項(xiàng)目
設(shè)置超時(shí)時(shí)間
GET請(qǐng)求
返回業(yè)務(wù)對(duì)象類getForObject方法
POST 請(qǐng)求
postForLocation
exchange 方法的使用
總結(jié)
怎么用?
SpringBoot項(xiàng)目
SpringBoot項(xiàng)目中,只需要引入spring-boot-starter-web依賴就可以了,其實(shí)spring-boot-starter-web依賴也是SpringBoot項(xiàng)目必備的一個(gè)依賴。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
設(shè)置超時(shí)時(shí)間
引入依賴之后,就來(lái)開始使用吧,任何一個(gè)Http的Api我們都可以設(shè)置請(qǐng)求的連接超時(shí)時(shí)間,請(qǐng)求超時(shí)時(shí)間,如果不設(shè)置的話,就可能會(huì)導(dǎo)致連接得不到釋放,造成內(nèi)存溢出。這個(gè)是我們需要重點(diǎn)注意的點(diǎn),下面就來(lái)看看RestTemplate如何來(lái)設(shè)置超時(shí)時(shí)間呢?我們可以在SimpleClientHttpRequestFactory類中設(shè)置這兩個(gè)時(shí)間,然后將factory傳給RestTemplate實(shí)例,設(shè)置如下:
@Configuration
public class RestTemplateConfig {
/**
* 服務(wù)器返回?cái)?shù)據(jù)(response)的時(shí)間
/
private static final Integer READ_TIME_OUT = 6000;
/*
* 連接上服務(wù)器(握手成功)的時(shí)間
*/
private static final Integer CONNECT_TIME_OUT = 6000;
@Bean
public RestTemplate restTemplate(){
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient());
return new RestTemplate(requestFactory);
}
@Bean
public HttpClient httpClient(){
//默認(rèn)證書有效
SSLConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactory.getSocketFactory();
SSLContext sslContext = null;
try {
//信任所有的SSL證書
sslContext = SSLContextBuilder.create().setProtocol(SSLConnectionSocketFactory.SSL)
.loadTrustMaterial((x, y) -> true).build();
} catch (Exception e) {
e.printStackTrace();
}
if (sslContext != null) {
sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext);
}
// 支持HTTP、HTTPS
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory)
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
connectionManager.setMaxTotal(200);
connectionManager.setDefaultMaxPerRoute(100);
connectionManager.setValidateAfterInactivity(2000);
RequestConfig requestConfig = RequestConfig.custom()
// 服務(wù)器返回?cái)?shù)據(jù)(response)的時(shí)間,超時(shí)拋出read timeout
.setSocketTimeout(READ_TIME_OUT)
// 連接上服務(wù)器(握手成功)的時(shí)間,超時(shí)拋出connect timeout
.setConnectTimeout(CONNECT_TIME_OUT)
// 從連接池中獲取連接的超時(shí)時(shí)間,超時(shí)拋出ConnectionPoolTimeoutException
.setConnectionRequestTimeout(1000)
.build();
return HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).setConnectionManager(connectionManager).build();
}
}
說(shuō)完了RestTemplate的相關(guān)設(shè)置,下面就來(lái)看看平時(shí)我們用的最多兩種請(qǐng)求方法:get方法和post方法吧。
GET請(qǐng)求
RestTemplate中提供的get請(qǐng)求的方法主要分為兩類,一類是只返回請(qǐng)求體,一類是返回ResponseEntity對(duì)象,這個(gè)對(duì)象主要是包裝了Http請(qǐng)求的響應(yīng)狀態(tài)status,響應(yīng)頭headers,和響應(yīng)體body。后面我們會(huì)詳細(xì)介紹。首先來(lái)看看getForObject方法。
返回業(yè)務(wù)對(duì)象類getForObject方法
getForObject方法的重載方法有如下三個(gè):
/**
方法一,直接將參數(shù)添加到url上面。
* Retrieve a representation by doing a GET on the specified URL.
* The response (if any) is converted and returned.
*
URI Template variables are expanded using the given URI variables, if any.
* @param url the URL 請(qǐng)求地址
* @param responseType the type of the return value 響應(yīng)體的類型
* @param uriVariables the variables to expand the template 傳入的參數(shù)
* @return the converted object
/
@Nullable
T getForObject(String url, Class responseType, Object… uriVariables) throws RestClientException;
/*
方法二,通過(guò)Map來(lái)提交參數(shù)。
* Retrieve a representation by doing a GET on the URI template.
* The response (if any) is converted and returned.
*
URI Template variables are expanded using the given map.
* @param url the URL
* @param responseType the type of the return value
* @param uriVariables the map containing variables for the URI template
* @return the converted object
*/
@Nullable
T getForObject(String url, Class responseType, Map<String, ?> uriVariables) throws RestClientException;
/**
方法三,用URI來(lái)請(qǐng)求。
* Retrieve a representation by doing a GET on the URL .
* The response (if any) is converted and returned.
* @param url the URL
* @param responseType the type of the return value
* @return the converted object
*/
@Nullable
<T> T getForObject(URI url, Class<T> responseType) throws RestClientException;
下面定義了一個(gè)接口,用來(lái)測(cè)試上面三個(gè)方法的使用,這個(gè)接口有兩個(gè)參數(shù),分別是userId和userName。
根據(jù)傳入的userId和userName來(lái)查詢用戶,如果可以查詢的到的話,則返回查詢到的用戶,如果查詢不到的話,則返回找不到數(shù)據(jù)。
響應(yīng)體是JSON格式的。
/**
* get請(qǐng)求獲取用戶
*
* @param userName 用戶名
* @param userId 用戶id
* @return
*/
@ResponseBody
@RequestMapping(value = “/getUser.do”)
public ResultData getUserByName(
@RequestParam(name = “userId”,required = false) Integer userId,
@RequestParam(name = “userName”,required = false) String userName) {
if (StringUtils.isAnyBlank(userName)) {
return new ResultData<>(HttpStatus.BAD_REQUEST.value(), null, “參數(shù)不能為空”);
}
List userList = new ArrayList<>();
for (int i = 1; i <= 2; i++) {
User user = new User();
user.setUserId(i);
user.setUserName(“張三” + i);
user.setAge(20 + i);
userList.add(user);
}
for (User user : userList) {
if (userName.equals(user.getUserName()) && userId.equals(user.getUserId())) {
return new ResultData(HttpStatus.OK.value(), user, “成功”);
}
}
return new ResultData<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), null, “找不到數(shù)據(jù)”);
}
下面我們就分別用那三個(gè)方法請(qǐng)求/getUser.do接口進(jìn)行測(cè)試:
@Test
public void getForObjectTest() {
String baseUrl = “http://localhost:8081/testRestTemplateApp/getUser.do”;
//方法一: 直接拼接參數(shù),推薦使用
String url =baseUrl+"?userName=張三1&userId=1";
ResultData resultData = restTemplate.getForObject(url, ResultData.class);
System.out.println("*****GET直接拼接參數(shù)查詢返回結(jié)果={}" + JSON.toJSONString(resultData));
//方法一:傳參替換,推薦使用
url = baseUrl+"?userName={?}&userId={?}";
resultData = restTemplate.getForObject(url, ResultData.class, “張三2”,2);
System.out.println("*****GET傳參替換查詢返回結(jié)果={}" + JSON.toJSONString(resultData));
//方法一:傳參替換,使用String.format,推薦使用
url = baseUrl + String.format("?userName=%s&userId=%s", “張三2”,2);
resultData = restTemplate.getForObject(url, ResultData.class);
System.out.println("******GET使用String.format查詢返回結(jié)果={}" + JSON.toJSONString(resultData));
//方法二:使用Map,不推薦使用
url = baseUrl + “?userName={userName}&userId={userId}”;
Map<String, Object> paramMap = new HashMap<>();
paramMap.put(“userName”, “張三1”);
paramMap.put(“userId”,1);
resultData = restTemplate.getForObject(url, ResultData.class, paramMap);
System.out.println("******GET使用Map查詢返回結(jié)果={}" + JSON.toJSONString(resultData));
//方法三:使用URI,不推薦使用
URI uri = URI.create(baseUrl+"?userName=%E5%BC%A0%E4%B8%891&userId=1");
ResultData resultData1 = restTemplate.getForObject(uri, ResultData.class);
System.out.println("******GET使用URI查詢返回結(jié)果={}" + JSON.toJSONString(resultData1));
}
運(yùn)行結(jié)果如下:
需要注意的是:
傳參替換使用{?}來(lái)表示坑位,根據(jù)實(shí)際的傳參順序來(lái)填充,如下:
url = baseUrl+"?userName={?}&userId={?}";
resultData = restTemplate.getForObject(url, ResultData.class, “張三2”,2);
使用{xx}來(lái)傳遞參數(shù)時(shí),這個(gè)xx對(duì)應(yīng)的就是map中的key
url = baseUrl + "?userName={userName}&userId={userId}";
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("userName", "張三1");
paramMap.put("userId",1);
當(dāng)響應(yīng)頭是application/json;charset=UTF-8格式的時(shí)候,返回的數(shù)據(jù)類型可以直接寫String.class,如下
String url ="http://localhost:8081/testRestTemplateApp/getUser.do?userName=張三1&userId=1";
String resultData = restTemplate.getForObject(url, String.class);
不推薦直接使用方法三傳入U(xiǎn)RI,原因主要有如下兩點(diǎn): 1. 傳入的參數(shù)包含中文時(shí)必須要轉(zhuǎn)碼,直接傳中文會(huì)報(bào)400的錯(cuò)誤,2. 響應(yīng)的結(jié)果必須要跟接口的返回值保持一致,不然回報(bào)406的錯(cuò)誤。
//userName不能直接傳入張三1,不然會(huì)報(bào)400的錯(cuò)誤
URI uri = URI.create(baseUrl+"?userName=%E5%BC%A0%E4%B8%891&userId=1");
//responseType不能傳入String.class,不然會(huì)報(bào)406的錯(cuò)誤
ResultData resultData1 = restTemplate.getForObject(uri, ResultData.class);
說(shuō)完了getForObject,下面來(lái)看看getForEntity的方法,這三個(gè)方法跟上面的getForObject三個(gè)方法分別對(duì)應(yīng),只是返回值不同。
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)
throws RestClientException;
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables)
throws RestClientException;
<T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException;
這里只列舉一個(gè)參數(shù)拼接的方式來(lái)舉例說(shuō)明:
String baseUrl = “http://localhost:8081/testRestTemplateApp/getUser.do”;
//參數(shù)拼接的方式
String url =baseUrl+"?userName=張三1&userId=1";
ResponseEntity entity = restTemplate.getForEntity(url, ResultData.class);
System.out.println("*****參數(shù)拼接查詢返回結(jié)果={}" + JSON.toJSONString(entity));
運(yùn)行后的結(jié)果如下:有響應(yīng)頭heads,有響應(yīng)體body,有響應(yīng)狀態(tài)statusCodeValue等。
{“body”:{“busCode”:200,“data”:{“userId”:1,“userName”:“張三1”,“age”:21},“msg”:“成功”},“headers”:{“Content-Type”:[“application/json;charset=UTF-8”],“Transfer-Encoding”:[“chunked”],“Date”:[“Fri, 06 Mar 2020 05:42:08 GMT”],“Keep-Alive”:[“timeout=60”],“Connection”:[“keep-alive”]},“statusCode”:“OK”,“statusCodeValue”:200}
POST 請(qǐng)求
說(shuō)完了get請(qǐng)求相關(guān)的方法之后,接下來(lái)我們來(lái)看看post請(qǐng)求相關(guān)的方法,首先還是來(lái)看postForObject的三個(gè)重載方法。
/**
* @param url the URL 請(qǐng)求地址
* @param request the Object to be POSTed (may be {@code null}) 請(qǐng)求體,可以傳入一個(gè)Bean對(duì)象,也可以傳入HttpEntity對(duì)象,包裝請(qǐng)求頭
* @param responseType the type of the return value 響應(yīng)對(duì)象的類型
* @param uriVariables the variables to expand the template 傳入的參數(shù)
* @return the converted object
* @see HttpEntity
*/
@Nullable
<T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
Object... uriVariables) throws RestClientException;
/**
* @param url the URL 請(qǐng)求地址
* @param request the Object to be POSTed (may be {@code null}) 請(qǐng)求體,可以傳入一個(gè)Bean對(duì)象,也可以傳入HttpEntity對(duì)象,包裝請(qǐng)求頭
* @param responseType the type of the return value 響應(yīng)對(duì)象的類型
* @param uriVariables the variables to expand the template 傳入的map
* @return the converted object
* @see HttpEntity
*/
@Nullable
T postForObject(String url, @Nullable Object request, Class responseType,
Map<String, ?> uriVariables) throws RestClientException;
/**
* @param url the URL
* @param request the Object to be POSTed (may be {@code null})
* @param responseType the type of the return value
* @return the converted object
* @see HttpEntity
*/
@Nullable
<T> T postForObject(URI url, @Nullable Object request, Class<T> responseType) throws RestClientException;
還是用上面的/getUser.do接口進(jìn)行測(cè)試。
@Test
public void testPostForObjectForForm() {
String baseUrl = "http://localhost:8081/testRestTemplateApp/getUser.do";
//方法一:表單提交
MultiValueMap<String, Object> request = new LinkedMultiValueMap<>();
request.set("userName","張三1");
request.set("userId",1);
ResultData resultData = restTemplate.postForObject(baseUrl,request, ResultData.class);
System.out.println("*****POST表單提交使用URI查詢返回結(jié)果={}" + JSON.toJSONString(resultData));
//方法二:使用URI
URI uri = URI.create(baseUrl);
resultData = restTemplate.postForObject(uri,request, ResultData.class);
System.out.println("******POST使用URI查詢返回結(jié)果={}" + JSON.toJSONString(resultData));
}
運(yùn)行結(jié)果如下:
從運(yùn)行結(jié)果我們可以看出,
如果傳入的參數(shù)是MultiValueMap類型的對(duì)象是,Spring會(huì)通過(guò)AllEncompassingFormHttpMessageConverter轉(zhuǎn)換器來(lái)將參數(shù)通過(guò)表單提交。
如果直接傳入一個(gè)Map對(duì)象,則會(huì)通過(guò)MappingJackson2HttpMessageConverter轉(zhuǎn)換器對(duì)參數(shù)進(jìn)行轉(zhuǎn)換。
說(shuō)完了表單提交,下面我們看看另外一種場(chǎng)景,如下,這個(gè)接口是一個(gè)保存用戶數(shù)據(jù)的接口,參數(shù)需要格式化后放在請(qǐng)求體中。
@ResponseBody
@PostMapping("/addUserJSON.do")
public ResultData<Boolean> addUserJSON(@RequestBody User user) {
if (user == null) {
return new ResultData<>(HttpStatus.BAD_REQUEST.value(), null, "參數(shù)不能為空");
}
return new ResultData<>(HttpStatus.OK.value(),true,"保存成功");
}
當(dāng)我們需要調(diào)用接口是通過(guò)@RequestBody來(lái)接受參數(shù)時(shí),也就是需要傳入一個(gè)JSON對(duì)象,我們?cè)撊绾握?qǐng)求呢?我們調(diào)用可以postForObject可以直接傳入U(xiǎn)ser對(duì)象, 也可以將請(qǐng)求頭設(shè)置成application/json,然后將User對(duì)象序列化,代碼如下所示:
@Test
public void testPostForObject() {
String baseUrl = "http://localhost:8081/testRestTemplateApp/addUserJSON.do";
User user = new User();
user.setUserName("李四");
user.setAge(23);
//第一種方式:不傳入JSON的參數(shù),不設(shè)置請(qǐng)求頭
ResultData resultData = restTemplate.postForObject(baseUrl, user, ResultData.class);
System.out.println("*********不序列化傳入?yún)?shù)請(qǐng)求結(jié)果={}" + JSON.toJSONString(resultData));
//第二種方式:傳入JSON類型的參數(shù),設(shè)置請(qǐng)求頭
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity httpEntity = new HttpEntity(JSON.toJSONString(user),headers);
resultData = restTemplate.postForObject(baseUrl, httpEntity, ResultData.class);
System.out.println("*********序列化參數(shù)請(qǐng)求結(jié)果={}" + JSON.toJSONString(resultData));
}
第一種方式是由于Spring內(nèi)部的MappingJackson2HttpMessageConverter會(huì)將參數(shù)進(jìn)行序列化并請(qǐng)求接口
第二種方式是直接設(shè)置好請(qǐng)求頭為application/json,并將參數(shù)序列化。所以就不需要通過(guò)MappingJackson2HttpMessageConverter進(jìn)行轉(zhuǎn)換。比較推薦
運(yùn)行結(jié)果如下:
postForEntity方法在此就不在贅述了。
說(shuō)完了,get請(qǐng)求的相關(guān)方法和post請(qǐng)求的相關(guān)方法,接下來(lái)我們來(lái)看看另外一類方法
postForLocation
postForLocation的定義是POST 數(shù)據(jù)到一個(gè)URL,返回新創(chuàng)建資源的URL,就是重定向或者頁(yè)面跳轉(zhuǎn)。
同樣提供了三個(gè)方法,分別如下,需要注意的是返回結(jié)果為URI對(duì)象,即網(wǎng)絡(luò)資源
public URI postForLocation(String url, @Nullable Object request, Object… uriVariables)
throws RestClientException ;
public URI postForLocation(String url, @Nullable Object request, Map<String, ?> uriVariables)
throws RestClientException ;
public URI postForLocation(URI url, @Nullable Object request) throws RestClientException ;
這類接口主要應(yīng)用在需要跳轉(zhuǎn)頁(yè)面的請(qǐng)求,比如,登錄,注冊(cè),支付等post請(qǐng)求,請(qǐng)求成功之后需要跳轉(zhuǎn)到成功的頁(yè)面。這種場(chǎng)景下我們可以使用postForLocation了,提交數(shù)據(jù),并獲取放回的URI,一個(gè)測(cè)試如下:
首先mock一個(gè)接口
@ResponseBody
@RequestMapping(path = "loginSuccess")
public String loginSuccess(String userName, String password) {
return "welcome " + userName;
}
/**
* @param userName
* @param password
* @return
*/
@RequestMapping(path = "login", method = {RequestMethod.GET, RequestMethod.OPTIONS, RequestMethod.POST}
,produces = "charset/utf8")
public String login(@RequestParam(value = "userName", required = false) String userName,
@RequestParam(value = "password", required = false) String password) {
return "redirect:/loginSuccess?userName=" + userName + "&password=" + password + "&status=success";
}
測(cè)試請(qǐng)求是:
@Test
public void testPostLocation() {
String url = "http://localhost:8081/testRestTemplateApp/login";
MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>();
paramMap.add("userName", "bob");
paramMap.add("password", "1212");
URI location = restTemplate.postForLocation(url, paramMap);
System.out.println("*******返回的數(shù)據(jù)=" + location);
}
運(yùn)行結(jié)果如下:
exchange 方法的使用
前面詳細(xì)介紹了getForObject和postForObject這兩個(gè)常用的方法,現(xiàn)在再介紹一個(gè)更通用的方法exchange方法,其實(shí)getForObject和postForObject方法內(nèi)部也是調(diào)用的exchange方法。該方法的特點(diǎn)是ResponseEntity對(duì)象,該對(duì)象包括了整個(gè)響應(yīng)體,包括status,heads等等。下面展示其使用
public T toPostEntity(String url, HttpEntity httpEntity, Class responseType) {
ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, responseType);
logger.info(“請(qǐng)求地址是={},響應(yīng)結(jié)果是={}”, url, new Gson().toJson(responseEntity));
//接受請(qǐng)求失敗,拋出異常
if (HttpStatus.OK.value() != responseEntity.getStatusCodeValue() || responseEntity.getStatusCode().isError()) {
throw new BusinessException(ErrorCode.RESULT_CODE_ERROR);
}
//接受請(qǐng)求成功
return responseEntity.getBody();
}
需要注意的是當(dāng)請(qǐng)求體的contentType與響應(yīng)體的contentType不相同是,傳入的responseType需要指定為String.class。不然,可能會(huì)報(bào)如下錯(cuò)誤。
Could not extract response: no suitable HttpMessageConverter found for response type [class java.lang.Object] and content type [text/html;charset=utf-8]
調(diào)用示例
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
Map<String, Object> paramMap = new HashMap<>();
paramMap.put(“areaName”, “安徽省”);
HttpEntity httpEntity = new HttpEntity(paramMap, headers);
requestHandler.toPostEntity(“http://localhost:8080/v1/data/push”, httpEntity, String.class);
調(diào)用結(jié)果是:
響應(yīng)結(jié)果是={“status”:200,“headers”:{“Aiedu-Time”:[“1616722693”],“Content-Type”:[“application/json;charset\u003dUTF-8”],“Transfer-Encoding”:[“chunked”],“Date”:[“Fri, 26 Mar 2021 01:38:13 GMT”]},“body”:"{“code”:0,“msg”:“請(qǐng)求成功”,“data”:null}"}
介紹完了restTemplate的常用方法,但是,我們或許會(huì)感覺到restTemplate的方法太多了,調(diào)用起來(lái)不太方便,為了使用方便,我們就對(duì)restTemplate做一個(gè)封裝。代碼如下所示:主要封裝成了四個(gè)方法,一個(gè)是通過(guò)get請(qǐng)求的方法,一個(gè)是通過(guò)表單提交的post請(qǐng)求方法,一個(gè)是通過(guò)json提交的post請(qǐng)求方法,最后就是上傳圖片的方法。
@Component
public class RestTemplateProxy {
@Autowired
private RestTemplate restTemplate;
/**
*
* @param url 請(qǐng)求地址
* 參數(shù)可以通過(guò) http://localhost:8888/juheServer/juhe/info/queryCustomer.do?taxNo=92330424MA29G7GY5W
* 或者 http://localhost:8888/juheServer/juhe/info/queryCustomer.do+String.format("?taxNo=%s&order=%s", "92330424MA29G7GY5W","1212121212");
* @param responseType 返回值的類型
* @return
* @author xiagwei
* @date 2020/3/5 5:28 PM
*
*/
public <T> T getForObject(String url, Class<T> responseType) {
return restTemplate.getForObject(url, responseType);
}
/**
* 通過(guò)json的方式請(qǐng)求服務(wù),不需要將數(shù)據(jù)格式化,直接將請(qǐng)求對(duì)象傳入即可
* 可以是map,可以是一個(gè)bean
* @param url 請(qǐng)求接口
* @param requestParam 請(qǐng)求實(shí)體
* @param responseType 返回對(duì)象的clazz
* @return
* @author xiagwei
* @date 2020/3/5 5:36 PM
*/
public <T> T postForObjectJSON(String url, Object requestParam,Class<T> responseType) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity httpEntity = new HttpEntity(requestParam, headers);
return restTemplate.postForObject(url, httpEntity, responseType);
}
/**
* 通過(guò)Form表單的方式提交
* @param url 請(qǐng)求接口
* @param requestParam 請(qǐng)求實(shí)體,可以是一個(gè)實(shí)體,也可以一個(gè)map
* @param responseType 返回對(duì)象的clazz
* @return
* @author xiagwei
* @date 2020/3/5 5:42 PM
*/
public <T> T postForObjectForm(String url, @NotNull Object requestParam, Class<T> responseType) {
MultiValueMap<String, Object> valueRequestMap = createValueMap(requestParam);
return restTemplate.postForObject(url, valueRequestMap, responseType);
}
/**
* 最通用的請(qǐng)求方法
*
* @param url 請(qǐng)求的URL
* @param requestParam 請(qǐng)求參數(shù)
* @param headers 請(qǐng)求頭
* @param response 響應(yīng)結(jié)果的類型
* @return
* @date 2021/3/10 14:21
*/
public <T> T postForEntityHeader(String url, Object requestParam, HttpHeaders headers, Class<T> response) {
MultiValueMap<String, Object> requestEntity = createValueMap(requestParam);
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(requestEntity,headers);
return restTemplate.postForObject(url, httpEntity, response);
}
/**
* 圖片上傳
*
* @param url 請(qǐng)求地址
* @param body 請(qǐng)求體
* MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("uploadFile", new FileSystemResource(ImageUtil.downloadImgByUrl(url)));
* @param responseType 返回結(jié)果的clazz對(duì)象
* @return
* @author xiagwei
* @date 2020/3/5 6:05 PM
*/
public <T> T uploadImg(@NotNull String url, @NotNull MultiValueMap<String, Object> body,Class<T> responseType) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body,headers);
return restTemplate.postForObject(url,requestEntity,responseType);
}
/**
* 基礎(chǔ)的請(qǐng)求方法
*
* @param url
* @param httpEntity
* @param responseType
* @return
* @Author weixiang
* @date 2020/3/5 6:05 PM
*/
public <T> T toPostEntity(String url, HttpEntity httpEntity, Class<T> responseType) {
ResponseEntity<T> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, responseType);
logger.info("請(qǐng)求地址是={},響應(yīng)結(jié)果是={}", url, new Gson().toJson(responseEntity));
//接受請(qǐng)求失敗,拋出異常
if (HttpStatus.OK.value() != responseEntity.getStatusCodeValue() || responseEntity.getStatusCode().isError()) {
throw new BusinessException(ErrorCode.RESULT_CODE_ERROR);
}
//接受請(qǐng)求成功
return responseEntity.getBody();
}
private MultiValueMap createValueMap(Object requestParam) {
MultiValueMap<String, Object> valueRequestMap = new LinkedMultiValueMap<>();
Map<String, Object> param = null;
if (requestParam instanceof Map) {
param = (Map<String, Object>) requestParam;
} else {
param = BeanUtil.beanToMap(requestParam);
}
for (String key : param.keySet()) {
valueRequestMap.add(key, param.get(key));
}
return valueRequestMap;
}
}
這里需要重點(diǎn)說(shuō)下,圖片上傳的方法,上傳圖片的話,我們一定要把請(qǐng)求頭設(shè)置成multipart/form-data,然后其余的參數(shù)通過(guò)MultiValueMap來(lái)設(shè)置。
public <T> T uploadImg(@NotNull String url, @NotNull MultiValueMap<String, Object> body,Class<T> responseType) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body,headers);
return restTemplate.postForObject(url,requestEntity,responseType);
}
總結(jié)
本文主要介紹了restTemplate類的使用,首先介紹了需要引入的依賴,然后介紹了如何設(shè)置超時(shí)時(shí)間,接著就是介紹了restTemplate中g(shù)et請(qǐng)求相關(guān)的方法和post請(qǐng)求相關(guān)的方法,以及這些方法如何調(diào)用。最后就是對(duì)常用的請(qǐng)求方法做了一個(gè)封裝。希望對(duì)讀者朋友們有所幫助。
作者:碼農(nóng)飛哥
微信公眾號(hào):碼農(nóng)飛哥