Java中調(diào)用第三方接口的詳細(xì)代碼示例
0、測(cè)試接口
寫(xiě)兩個(gè)測(cè)試接口,一個(gè)GET,一個(gè)POST
@RestController @RequestMapping("/svc1") public class Controller { @GetMapping("/t1") public String doGet(@RequestParam(required = false) String name) { return "test" + name; } @PostMapping("/t2") public ResultVo doPost(@RequestBody RequestBodyDto dto, @RequestParam String key) { return new ResultVo(200, "操作成功", dto.getName() + dto.getChoose() + key); } }
1、JDK的HttpURLConnection
原生版,主要依靠JDK的 java.net包,GET請(qǐng)求:
import java.net.HttpURLConnection; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; @Slf4j public class TestDemo { public static void main(String[] args) { BufferedReader reader = null; try { // 創(chuàng)建URL對(duì)象 URL url = new URL("http://localhost:8080/svc1/t1"); // 打開(kāi)連接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); // 讀取響應(yīng) reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); // 處理響應(yīng) String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = reader.readLine()) != null) { response.append(inputLine); } System.out.println(response); } catch (Exception e) { log.error("調(diào)用失敗"); e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
URL類(lèi)是JDK java.net包下的一個(gè)類(lèi),表示一個(gè)統(tǒng)一資源標(biāo)識(shí)符(Uniform Resource Identifier)引用
POST請(qǐng)求:
import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import com.alibaba.fastjson.JSON; @Slf4j public class TestDemo { public static void main(String[] args) { try { // 創(chuàng)建URL對(duì)象 URL url = new URL("http://localhost:8080/svc1/t2?key=abc"); // 打開(kāi)連接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); // 設(shè)置請(qǐng)求頭與數(shù)據(jù)格式 connection.setRequestProperty("Content-Type", "application/json; utf-8"); connection.setRequestProperty("Accept", "application/json"); // 允許向服務(wù)器寫(xiě)入數(shù)據(jù) connection.setDoOutput(true); RequestBodyDto dto = new RequestBodyDto("Tom", "A"); String json = JSON.toJSONString(dto); // 寫(xiě)入JSON到請(qǐng)求體 try (OutputStream os = connection.getOutputStream()) { BufferedOutputStream bos = new BufferedOutputStream(os); bos.write(json.getBytes(StandardCharsets.UTF_8)); bos.flush(); } // 讀取響應(yīng) try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"))) { StringBuilder response = new StringBuilder(); String responseLine; while ((responseLine = br.readLine()) != null) { response.append(responseLine.trim()); } System.out.println("Response: " + response.toString()); } } catch (Exception e) { e.printStackTrace(); } } }
2、Apache的HttpClient
后續(xù)這些方式,本質(zhì)上就是對(duì)java.net包的一個(gè)封裝了。先引入Apache做http請(qǐng)求的依賴(lài)坐標(biāo):
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.4.16</version> </dependency>
public class TestDemo { public static void main(String[] args) { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { // 創(chuàng)建POST請(qǐng)求對(duì)象 HttpPost httpPost = new HttpPost("http://localhost:8080/svc1/t2?key=abc"); // 設(shè)置請(qǐng)求頭 httpPost.setHeader("Content-Type", "application/json; utf-8"); httpPost.setHeader("Accept", "application/json"); // 設(shè)置請(qǐng)求體 RequestBodyDto dto = new RequestBodyDto("Tom", "A"); String json = JSON.toJSONString(dto); StringEntity entity = new StringEntity(json); httpPost.setEntity(entity); // 執(zhí)行請(qǐng)求并獲取響應(yīng) CloseableHttpResponse response = httpClient.execute(httpPost); HttpEntity responseEntity = response.getEntity(); // 處理響應(yīng) if (null != responseEntity) { String responseStr = EntityUtils.toString(responseEntity); System.out.println(responseStr); // 也可按需把json串反序列化成Java對(duì)象,略 } } catch (IOException e) { e.printStackTrace(); } } }
3、SpringBoot的RestTemplate
使用SpringBoot封裝的RestTemplate,依賴(lài)寫(xiě)web的:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
把RestTemplate的Bean放到IoC容器中:
@Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
3.1 GET
發(fā)送Get請(qǐng)求,常用方法:
- getForObject
- getForEntity
/** * url為請(qǐng)求的地址 * responseType為請(qǐng)求響應(yīng)body的類(lèi)型 * urlVariables為url中的參數(shù)綁定 * */ getForEntity(Stringurl,Class responseType,Object…urlVariables) /** * URI對(duì)象來(lái)替代之前getForEntity的url和urlVariables參數(shù)來(lái)指定訪(fǎng)問(wèn)地址和參數(shù)綁定 * URI是JDK java.net包下的一個(gè)類(lèi) * */ getForEntity(URI url,Class responseType)
示例:
@SpringBootTest class LearningApplicationTests { @Resource private RestTemplate restTemplate; @Test void contextLoads() { String url = "http://localhost:8080/svc1/t1?name={name}"; // 參數(shù) Map<String, String> paramMap = new HashMap<>(); paramMap.put("name", "Tom"); ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, paramMap); // 狀態(tài)碼 HttpStatus statusCode = responseEntity.getStatusCode(); // 響應(yīng) String body = responseEntity.getBody(); System.out.println(statusCode + body); } }
接口路徑不用字符串,改為URI對(duì)象:
@Test void testTemplate() { String url = "http://localhost:8080/svc1/t1"; String name = "Tom"; // 使用 UriComponentsBuilder 構(gòu)建 URL URI uri = UriComponentsBuilder.fromHttpUrl(url) .queryParam("name", name) .build() .toUri(); ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class); // 狀態(tài)碼 HttpStatus statusCode = responseEntity.getStatusCode(); // 響應(yīng) String body = responseEntity.getBody(); System.out.println(statusCode + body); }
最后,getForObject:
getForObject(String url,Class responseType,Object...urlVariables) getForObject(String url,Class responseType,Map urlVariables) getForObject(URI url,Class responseType)
和getForEntity的區(qū)別是,getForObject只有一個(gè)響應(yīng)的內(nèi)容,響應(yīng)碼、響應(yīng)頭等沒(méi)有
3.2 POST
常用方法:
- postForEntity
- postForObject
- postForLocation
以postForEntity為例,其參數(shù)可選:(重載)
postForEntity(String url,Object request,Class responseType,Object... uriVariables) postForEntity(String url,Object request,Class responseType,Map uriVariables) postForEntity(URI url,Object request,Class responseType)
示例:
@Test void testTemplate2() { String url = "http://localhost:8080/svc1/t2?key=Tom"; RestTemplate restTemplate = new RestTemplate(); // 請(qǐng)求頭 HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.AUTHORIZATION, "Bear xx"); // headers.set("Content-Type", "application/x-www-form-urlencoded"); headers.add(HttpHeaders.CONTENT_TYPE, "application/json"); // 創(chuàng)建請(qǐng)求體對(duì)象并放入數(shù)據(jù) HttpEntity<RequestBodyDto> requestData = new HttpEntity<>(new RequestBodyDto("Tom", "A"), headers); // 和postForEntity一個(gè)意思 ResponseEntity<String> responseEntity = restTemplate.exchange( url, HttpMethod.POST, requestData, String.class ); // 獲取響應(yīng)狀態(tài)碼和響應(yīng)體 HttpStatus statusCode = responseEntity.getStatusCode(); String responseBody = responseEntity.getBody(); System.out.println(statusCode + " " + responseBody); }
4、SpringCloud的Feign
上面的RestTemplate,在調(diào)三方接口時(shí)挺好用的,但微服務(wù)架構(gòu)下,各個(gè)微服務(wù)之間調(diào)用時(shí),url就不好寫(xiě),由此,用Feign:一個(gè)聲明式的http客戶(hù)端
核心思路是聲明出:
- 你調(diào)誰(shuí)
- 用什么方式
- 請(qǐng)求參數(shù)是啥
- 返回類(lèi)型是啥
引入依賴(lài):
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
啟動(dòng)類(lèi)上加上@EnableFeignClients
//在order的啟動(dòng)類(lèi)中開(kāi)啟Feign @EnableFeignClients @MapperScan("com.llg.order.mapper") @SpringBootApplication public class OrderApplication{ public static void main(String[] args){ SpringApplication.run(OrderApplication.class,args); } }
- 以order服務(wù)調(diào)用user服務(wù)為例,編寫(xiě)調(diào)用方:
// 遠(yuǎn)程調(diào)用userservice服務(wù) @FeignClient("userservice") public interface UserClient { @GetMapping("/user/{id}") User findById(@PathVariable("id") Long id); // 后續(xù)接口自行添加 } ?。indById這個(gè)方法名隨便起 ?。≌{(diào)用的接口路徑、調(diào)用的服務(wù)名、請(qǐng)求參數(shù)、返回類(lèi)型聲明正確就行
主要是基于SpringMVC的注解來(lái)聲明遠(yuǎn)程調(diào)用的信息,比如: ?服務(wù)名稱(chēng):userservice ?請(qǐng)求方式:GET ?請(qǐng)求路徑:/user/{id} ?請(qǐng)求參數(shù):Long id ?返回值類(lèi)型:User
- 注入上面定義的FeignClient類(lèi),也就是UserClient,直接調(diào)用聲明的那個(gè)方法
@Autowired private UserClient userClient; public Order queryOrderById(Long orderId){ //查詢(xún)訂單 Order order = orderMapper.findById(orderId); //利用feign發(fā)起http請(qǐng)求,查用戶(hù) User user = userClient.findById(order.getUserId()); //封裝,對(duì)象的某個(gè)屬性也是個(gè)對(duì)象,即引用類(lèi)型 order.setUser(user); return order; }
- 被調(diào)用方有多個(gè)實(shí)例時(shí),負(fù)載均衡也不用考慮,F(xiàn)eign用了Ribbon做負(fù)載均衡
- 關(guān)于Feign請(qǐng)求頭的添加,可重寫(xiě)RequestInterceptor的apply方法:
@Configuration public class FeignConfig implements RequestInterceptor { @Override public void apply(RequestTemplate requestTemplate) { //添加token requestTemplate.header("token", "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ4ZGFwYXBwaWQiOiIzNDgxMjU4ODk2OTI2OTY1NzYiLCJleHAiOjE2NjEyMjY5MDgsImlhdCI6MTY2MTIxOTcwOCwieGRhcHRlbmFudGlkIjoiMzAwOTgxNjA1MTE0MDUyNjA5IiwieGRhcHVzZXJpZCI6IjEwMDM0NzY2MzU4MzM1OTc5NTIwMCJ9.fZAO4kJSv2rSH0RBiL1zghdko8Npmu_9ufo6Wex_TI2q9gsiLp7XaW7U9Cu7uewEOaX4DTdpbFmMPvLUtcj_sQ"); } }
- 要做降級(jí)邏輯的話(huà):如下,調(diào)用消息中心服務(wù)
// @FeignClient的fallbackFactory指定下降級(jí)邏輯的類(lèi) @Component @FeignClient(contextId = "remoteMessageService", value = ServiceNameConstants.MESSAGE_SERVICE, fallbackFactory = RemoteMessageFallbackFactory.class) public interface RemoteMessageService { /** * 發(fā)送定時(shí)消息任務(wù):每分鐘掃描發(fā)送消息 * * @return 結(jié)果 */ @GetMapping("/inner/message/sendTimingMessage") public R<Void> sendTimingMessage(); /** * 發(fā)送系統(tǒng)消息 * * @return 結(jié)果 */ @PostMapping("/inner/message/sendSystemMessage") public R<Void> sendSystemMessage(@RequestBody MessageSendSystemDto messageSendSystemDto); }
// 降級(jí)邏輯 @Component public class RemoteMessageFallbackFactory implements FallbackFactory<RemoteMessageService>{ private static final Logger log = LoggerFactory.getLogger(RemoteMessageFallbackFactory.class); @Override public RemoteMessageService create(Throwable throwable) { throwable.printStackTrace(); log.error("消息服務(wù)調(diào)用失敗:{}", throwable.getMessage()); return new RemoteMessageService() { @Override public R<Void> sendTimingMessage() { return R.fail("調(diào)用發(fā)送定時(shí)消息接口失敗:" + throwable.getMessage()); } @Override public R<Void> sendSystemMessage(MessageSendSystemDto messageSendSystemDto) { return R.fail("調(diào)用發(fā)送消息接口失敗:" + throwable.getMessage()); } }; } }
5、Hutool的HttpUtil
還是對(duì) java.net的封裝,引入依賴(lài):
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.16</version> <!-- 請(qǐng)檢查最新版本 --> </dependency>
處理GET和POST:
/** * @param url baseUrl * @param requestMethod 請(qǐng)求方式 * @param headerMap 請(qǐng)求頭參數(shù)key-value * @param paramMap 路徑參數(shù)key-value,形如?name=Tom&country=Chain * @param bodyJsonStr post的body傳參,json字符串 * @return 響應(yīng)體 */ public static String sendRequest(String url, Method requestMethod, Map<String, String> headerMap, Map<String, Object> paramMap, String bodyJsonStr) { // 路徑參數(shù)不為空時(shí),拼接URL if (paramMap != null) { UrlBuilder urlBuilder = UrlBuilder.of(url); paramMap.forEach((k, v) -> urlBuilder.addQuery(k, v)); url = urlBuilder.toString(); } //發(fā)送請(qǐng)求 HttpResponse httpResponse = HttpUtil.createRequest(requestMethod, url) .addHeaders(headerMap) .body(bodyJsonStr) .execute(); return httpResponse.body(); }
測(cè)試下:
@Test void testHuTool() { String url = "http://localhost:8080/svc1/t1"; Map<String, Object> paramMap = new HashMap<>(); paramMap.put("name", "Tom"); Map<String, String> headerMap = new HashMap<>(); headerMap.put("Authorization", "Bear xx"); String response = sendRequest(url, Method.GET, headerMap, paramMap, null); System.out.println(response); } @Test void testHuTool2() { String url = "http://localhost:8080/svc1/t2"; Map<String, Object> paramMap = new HashMap<>(); paramMap.put("key", "Tom"); Map<String, String> headerMap = new HashMap<>(); headerMap.put("Authorization", "Bear xx"); RequestBodyDto dto = new RequestBodyDto("Tom", "A"); String bodyJsonStr = JSON.toJSONString(dto); String response = sendRequest(url, Method.POST, headerMap, paramMap, bodyJsonStr); System.out.println(response); }
6、失敗后重試
考慮到遠(yuǎn)程調(diào)用可能失敗,失敗后重試三次,以上面的hutool為例來(lái)實(shí)現(xiàn),其余的都一樣,主要還是一個(gè)是否成功標(biāo)記位 + 一個(gè)計(jì)數(shù),successFlag不用voilate,并發(fā)安全也不用考慮,線(xiàn)程內(nèi)部調(diào)用的,用到的數(shù)存棧里了都。
/** * @param url baseUrl * @param requestMethod 請(qǐng)求方式 * @param headerMap 請(qǐng)求頭參數(shù)key-value * @param paramMap 路徑參數(shù)key-value,形如?name=Tom&country=Chain * @param bodyJsonStr post的body傳參,json字符串 * @return 響應(yīng)體 */ public static String sendRequest(String url, Method requestMethod, Map<String, String> headerMap, Map<String, Object> paramMap, String bodyJsonStr) { // 是否成功標(biāo)記位 boolean successFlag = false; // 重試次數(shù)累計(jì) int retryCount = 1; HttpResponse httpResponse = null; while (!successFlag && retryCount <= 3) { try { // 路徑參數(shù)不為空時(shí),拼接URL if (paramMap != null) { UrlBuilder urlBuilder = UrlBuilder.of(url); paramMap.forEach((k, v) -> urlBuilder.addQuery(k, v)); url = urlBuilder.toString(); } // 發(fā)送請(qǐng)求 httpResponse = HttpUtil.createRequest(requestMethod, url) .addHeaders(headerMap) .body(bodyJsonStr) .execute(); if (httpResponse.getStatus() != 200) { retryCount++; } else { successFlag = true; } } catch (Exception e) { e.printStackTrace(); retryCount++; } } return httpResponse == null ? null : httpResponse.body(); }
總結(jié)
到此這篇關(guān)于Java中調(diào)用第三方接口的文章就介紹到這了,更多相關(guān)Java調(diào)用第三方接口內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java調(diào)用第三方接口示范的實(shí)現(xiàn)
- 實(shí)例詳解Java調(diào)用第三方接口方法
- Java調(diào)用第三方接口封裝實(shí)現(xiàn)
- Java發(fā)送http請(qǐng)求調(diào)用第三方接口獲取token方式
- java后端如何調(diào)用第三方接口(往header和body中的參數(shù)傳參)
- 舉例說(shuō)明JAVA調(diào)用第三方接口的GET/POST/PUT請(qǐng)求方式
- java后端調(diào)用第三方接口返回圖片流給前端的具體代碼實(shí)現(xiàn)
- Java中調(diào)用第三方接口的幾種方法詳細(xì)指南
相關(guān)文章
Mybatis之foreach標(biāo)簽內(nèi)傳入list為空的問(wèn)題
這篇文章主要介紹了Mybatis之foreach標(biāo)簽內(nèi)傳入list為空的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03java ThreadPoolExecutor使用方法簡(jiǎn)單介紹
這篇文章主要介紹了java ThreadPoolExecutor使用方法簡(jiǎn)單介紹的相關(guān)資料,需要的朋友可以參考下2017-02-02Java中的break和continue關(guān)鍵字的使用方法總結(jié)
下面小編就為大家?guī)?lái)一篇Java中的break和continue關(guān)鍵字的使用方法總結(jié)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11什么是springMVC?視圖和視圖解析器實(shí)例代碼
在 springMVC 中的目標(biāo)方法最終返回都是一個(gè)視圖,返回的視圖都會(huì)由一個(gè)視圖解析器來(lái)處理,這篇文章主要介紹了什么是springMVC?視圖和視圖解析器,需要的朋友可以參考下2023-09-09Redis原子計(jì)數(shù)器incr,防止并發(fā)請(qǐng)求操作
這篇文章主要介紹了Redis原子計(jì)數(shù)器incr,防止并發(fā)請(qǐng)求操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11Spring Boot應(yīng)用監(jiān)控的實(shí)戰(zhàn)教程
Spring Boot 提供運(yùn)行時(shí)的應(yīng)用監(jiān)控和管理功能,下面這篇文章主要給大家介紹了關(guān)于Spring Boot應(yīng)用監(jiān)控的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-05-05詳解Java TCC分布式事務(wù)實(shí)現(xiàn)原理
這篇文章主要介紹了詳解Java TCC分布式事務(wù)實(shí)現(xiàn)原理,對(duì)分布式事務(wù)感興趣的同學(xué),一定要看一下2021-04-04