Java中调用第三方接口

文章目录

  • 0、测试接口
  • 1、JDK的HttpURLConnection
  • 2、Apache的HttpClient
  • 3、SpringBoot的RestTemplate
    • 3.1 GET
    • 3.2 POST
  • 4、SpringCloud的Feign
  • 5、Hutool的HttpUtil
  • 6、失败后重试

0、测试接口

写两个测试接口,一个GET,一个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请求:

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 {// 创建URL对象URL url = new URL("http://localhost:8080/svc1/t1");// 打开连接HttpURLConnection connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");// 读取响应reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));// 处理响应String inputLine;StringBuilder response = new StringBuilder();while ((inputLine = reader.readLine()) != null) {response.append(inputLine);}System.out.println(response);} catch (Exception e) {log.error("调用失败");e.printStackTrace();} finally {if (reader != null) {try {reader.close();} catch (IOException e) {e.printStackTrace();}}}}
}

URL类是JDK java.net包下的一个类,表示一个统一资源标识符(Uniform Resource Identifier)引用

POST请求:

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 {// 创建URL对象URL url = new URL("http://localhost:8080/svc1/t2?key=abc");// 打开连接HttpURLConnection connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("POST");// 设置请求头与数据格式connection.setRequestProperty("Content-Type", "application/json; utf-8");connection.setRequestProperty("Accept", "application/json");// 允许向服务器写入数据connection.setDoOutput(true);RequestBodyDto dto = new RequestBodyDto("Tom", "A");String json = JSON.toJSONString(dto);// 写入JSON到请求体try (OutputStream os = connection.getOutputStream()) {BufferedOutputStream bos = new BufferedOutputStream(os);bos.write(json.getBytes(StandardCharsets.UTF_8));bos.flush();}// 读取响应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

后续这些方式,本质上就是对java.net包的一个封装了。先引入Apache做http请求的依赖坐标:

<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()) {// 创建POST请求对象HttpPost httpPost = new HttpPost("http://localhost:8080/svc1/t2?key=abc");// 设置请求头httpPost.setHeader("Content-Type", "application/json; utf-8");httpPost.setHeader("Accept", "application/json");// 设置请求体RequestBodyDto dto = new RequestBodyDto("Tom", "A");String json = JSON.toJSONString(dto);StringEntity entity = new StringEntity(json);httpPost.setEntity(entity);// 执行请求并获取响应CloseableHttpResponse response = httpClient.execute(httpPost);HttpEntity responseEntity = response.getEntity();// 处理响应if (null != responseEntity) {String responseStr = EntityUtils.toString(responseEntity);System.out.println(responseStr);// 也可按需把json串反序列化成Java对象,略}} catch (IOException e) {e.printStackTrace();}}
}

3、SpringBoot的RestTemplate

使用SpringBoot封装的RestTemplate,依赖写web的:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

把RestTemplate的Bean放到IoC容器中:

@Configuration
public class RestTemplateConfig {@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}

3.1 GET

发送Get请求,常用方法:

  • getForObject
  • getForEntity
/**
* url为请求的地址
* responseType为请求响应body的类型
* urlVariables为url中的参数绑定
* 
*/
getForEntity(Stringurl,Class responseType,Object…urlVariables)/**
* URI对象来替代之前getForEntity的url和urlVariables参数来指定访问地址和参数绑定
* URI是JDK java.net包下的一个类
* 
*/
getForEntity(URI url,Class responseType)

示例:

@SpringBootTest
class LearningApplicationTests {@Resourceprivate RestTemplate restTemplate;@Testvoid contextLoads() {String url = "http://localhost:8080/svc1/t1?name={name}";// 参数Map<String, String> paramMap = new HashMap<>();paramMap.put("name", "Tom");ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, paramMap);// 状态码HttpStatus statusCode = responseEntity.getStatusCode();// 响应String body = responseEntity.getBody();System.out.println(statusCode + body);}}

接口路径不用字符串,改为URI对象:

@Testvoid testTemplate() {String url = "http://localhost:8080/svc1/t1";String name = "Tom";// 使用 UriComponentsBuilder 构建 URLURI uri = UriComponentsBuilder.fromHttpUrl(url).queryParam("name", name).build().toUri();ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);// 状态码HttpStatus statusCode = responseEntity.getStatusCode();// 响应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的区别是,getForObject只有一个响应的内容,响应码、响应头等没有

在这里插入图片描述

3.2 POST

常用方法:

  • postForEntity
  • postForObject
  • postForLocation

以postForEntity为例,其参数可选:(重载)

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();// 请求头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");// 创建请求体对象并放入数据HttpEntity<RequestBodyDto> requestData = new HttpEntity<>(new RequestBodyDto("Tom", "A"), headers);// 和postForEntity一个意思ResponseEntity<String> responseEntity = restTemplate.exchange(url,HttpMethod.POST,requestData,String.class);// 获取响应状态码和响应体HttpStatus statusCode = responseEntity.getStatusCode();String responseBody = responseEntity.getBody();System.out.println(statusCode + " " + responseBody);
}

4、SpringCloud的Feign

上面的RestTemplate,在调三方接口时挺好用的,但微服务架构下,各个微服务之间调用时,url就不好写,由此,用Feign:一个声明式的http客户端

核心思路是声明出:

  • 你调谁
  • 用什么方式
  • 请求参数是啥
  • 返回类型是啥

引入依赖:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

启动类上加上@EnableFeignClients

//在order的启动类中开启Feign
@EnableFeignClients
@MapperScan("com.llg.order.mapper")
@SpringBootApplication
public class OrderApplication{public static void main(String[] args){SpringApplication.run(OrderApplication.class,args);}
}
  • 以order服务调用user服务为例,编写调用方:
// 远程调用userservice服务
@FeignClient("userservice")
public interface UserClient {@GetMapping("/user/{id}")User findById(@PathVariable("id") Long id);// 后续接口自行添加
}!!findById这个方法名随便起
!!调用的接口路径、调用的服务名、请求参数、返回类型声明正确就行
主要是基于SpringMVC的注解来声明远程调用的信息,比如:➢服务名称:userservice➢请求方式:GET➢请求路径:/user/{id}➢请求参数:Long id➢返回值类型:User
  • 注入上面定义的FeignClient类,也就是UserClient,直接调用声明的那个方法
@Autowired
private UserClient userClient;public Order queryOrderById(Long orderId){//查询订单Order order = orderMapper.findById(orderId);//利用feign发起http请求,查用户User user = userClient.findById(order.getUserId());//封装,对象的某个属性也是个对象,即引用类型order.setUser(user);return order;
} 
  • 被调用方有多个实例时,负载均衡也不用考虑,Feign用了Ribbon做负载均衡
  • 关于Feign请求头的添加,可重写RequestInterceptor的apply方法:
@Configuration
public class FeignConfig implements RequestInterceptor {@Overridepublic void apply(RequestTemplate requestTemplate) {//添加tokenrequestTemplate.header("token", "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ4ZGFwYXBwaWQiOiIzNDgxMjU4ODk2OTI2OTY1NzYiLCJleHAiOjE2NjEyMjY5MDgsImlhdCI6MTY2MTIxOTcwOCwieGRhcHRlbmFudGlkIjoiMzAwOTgxNjA1MTE0MDUyNjA5IiwieGRhcHVzZXJpZCI6IjEwMDM0NzY2MzU4MzM1OTc5NTIwMCJ9.fZAO4kJSv2rSH0RBiL1zghdko8Npmu_9ufo6Wex_TI2q9gsiLp7XaW7U9Cu7uewEOaX4DTdpbFmMPvLUtcj_sQ");}
}
  • 要做降级逻辑的话:如下,调用消息中心服务
// @FeignClient的fallbackFactory指定下降级逻辑的类
@Component
@FeignClient(contextId = "remoteMessageService", value = ServiceNameConstants.MESSAGE_SERVICE, fallbackFactory = RemoteMessageFallbackFactory.class)
public interface RemoteMessageService {/*** 发送定时消息任务:每分钟扫描发送消息** @return 结果*/@GetMapping("/inner/message/sendTimingMessage")public R<Void> sendTimingMessage();/*** 发送系统消息** @return 结果*/@PostMapping("/inner/message/sendSystemMessage")public R<Void> sendSystemMessage(@RequestBody MessageSendSystemDto messageSendSystemDto);
}
// 降级逻辑
@Component
public class RemoteMessageFallbackFactory implements FallbackFactory<RemoteMessageService>{private static final Logger log = LoggerFactory.getLogger(RemoteMessageFallbackFactory.class);@Overridepublic RemoteMessageService create(Throwable throwable) {throwable.printStackTrace();log.error("消息服务调用失败:{}", throwable.getMessage());return new RemoteMessageService() {@Overridepublic R<Void> sendTimingMessage() {return R.fail("调用发送定时消息接口失败:" + throwable.getMessage());}@Overridepublic R<Void> sendSystemMessage(MessageSendSystemDto messageSendSystemDto) {return R.fail("调用发送消息接口失败:" + throwable.getMessage());}};}
}

5、Hutool的HttpUtil

还是对 java.net的封装,引入依赖:

<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version> <!-- 请检查最新版本 -->
</dependency>

处理GET和POST:

/*** @param url           baseUrl* @param requestMethod 请求方式* @param headerMap     请求头参数key-value* @param paramMap      路径参数key-value,形如?name=Tom&country=Chain* @param bodyJsonStr   post的body传参,json字符串* @return 响应体*/
public static String sendRequest(String url, Method requestMethod, Map<String, String> headerMap, Map<String, Object> paramMap, String bodyJsonStr) {// 路径参数不为空时,拼接URLif (paramMap != null) {UrlBuilder urlBuilder = UrlBuilder.of(url);paramMap.forEach((k, v) -> urlBuilder.addQuery(k, v));url = urlBuilder.toString();}//发送请求HttpResponse httpResponse = HttpUtil.createRequest(requestMethod, url).addHeaders(headerMap).body(bodyJsonStr).execute();return httpResponse.body();}

测试下:

@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、失败后重试

考虑到远程调用可能失败,失败后重试三次,以上面的hutool为例来实现,其余的都一样,主要还是一个是否成功标记位 + 一个计数,successFlag不用voilate,并发安全也不用考虑,线程内部调用的,用到的数存栈里了都。

/*** @param url           baseUrl* @param requestMethod 请求方式* @param headerMap     请求头参数key-value* @param paramMap      路径参数key-value,形如?name=Tom&country=Chain* @param bodyJsonStr   post的body传参,json字符串* @return 响应体*/public static String sendRequest(String url, Method requestMethod, Map<String, String> headerMap, Map<String, Object> paramMap, String bodyJsonStr) {// 是否成功标记位boolean successFlag = false;// 重试次数累计int retryCount = 1;HttpResponse httpResponse = null;while (!successFlag && retryCount <= 3) {try {// 路径参数不为空时,拼接URLif (paramMap != null) {UrlBuilder urlBuilder = UrlBuilder.of(url);paramMap.forEach((k, v) -> urlBuilder.addQuery(k, v));url = urlBuilder.toString();}// 发送请求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();}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1523104.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

关于IDEA的快捷键不能使用的原因

有时候IDEA的快捷键用不了&#xff0c;这时应该是快捷键发生冲突了&#xff0c;重新设置一下即可。以批量修改变量名称的shift f6为例&#xff08;我的这个快捷键用不了&#xff09;&#xff1a; 初始的rename的快捷键为shift f6 这个快捷键是冲突的&#xff0c;所以我们需要…

Centos7安装FFmpeg详细步骤(已验证成功)

最近我们需要使用FFmpeg来合成视频功能&#xff0c;这就需要用到服务器必须安装FFmpeg了。 FFmpeg 是一款功能强大的跨平台命令行工具&#xff0c;可以处理各种音频和视频文件&#xff0c;包括转换视频和音频格式、剪辑、合并视频和音频、提取音频、添加字幕、添加水印、调整视…

【Linux跬步积累】—— 环境变量、程序地址空间、进程地址空间、Linux2.6内核进程调度队列

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;Linux跬步积累 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日一题 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0…

什么?!新版 Node.js V22.5 自带 SQLite 模块啦

前言 2024年7月&#xff0c;Node.js V22.5.0 版本发布&#xff0c;自带了 SQLite 模块&#xff0c;意味着开发者可以直接在程序中使用 SQLite 数据库&#xff0c;而无需引入第三方库&#x1f44d;。 话不多说&#xff0c;感觉来体验一波✈。 安装/升级 我现在用的是21.4.0版…

Trm理论 3(ELMo)

LSTM模型 如图&#xff0c;LSTM模型是rnn模型的改良版&#xff0c;通过ft来选择性的保留上一次得到的信息 ELMo模型&#xff08;双向LSTM&#xff09; ELMo模型是对word2vec的改良&#xff0c;改良了word2vec的二义性 对比上下两图&#xff0c;可以发现&#xff0c;WE对预测…

【qt】qss使用

1.按钮设置颜色 ui->pushButton->setStyleSheet("QPushButton { color : red;}");也可以通过rgb来设置 ff表示红色拉满&#xff0c;gb为0当然是红色 这只是针对pushbutton对象的控件设置的&#xff0c;如果我想设置所有的按钮空间都是一个颜色 这是通过设置界…

【无标题】【Datawhale X 李宏毅苹果书 AI夏令营】批量归一化

1、批量归一化的作用 批量归一化&#xff08;Batch Normalization&#xff0c;BN&#xff09;的把误差曲面变得平滑&#xff0c;使训练能够得到快速收敛&#xff1b; 训练过程的优化&#xff1a;使用自适应学习率等比较进阶的优化训练方法&#xff1b; 训练对象的优化&#xf…

Linux 服务器下非root用户安装CUDA完整流程(多次踩雷经验总结)

参考博客&#xff1a; linux下安装cuda和cudnn&#xff08;非root权限&#xff09;_cuda下载安装 远程服务器 linux-CSDN博客 Linux下非root用户安装CUDA_linux下cuda-toolkit-archive-CSDN博客 非root用户安装cuda10.1&#xff0c;以及CUDA不同版本间切换_非root用户.run文…

android kotlin基础复习—if when

1、新建kt并运行 新建文件kt 运行文件kt 2、kotlin语句 if when的使用 var x 5val y 9if (x in 1..8) {println("x 在区间内")} 说明&#xff1a; var&#xff1a;定义变量 val定义常量。 代码中会看到那个<&#xff0c;也就是说包括1&#xff0c;8。 3、输…

glsl着色器学习(二)

书接上文&#xff0c;第一篇文章已经将顶点着色器和片段着色器的内容编写好了&#xff0c;这篇文章就创建着色器并编译 创建顶点着色器对象 const vertexShader gl.createShader(gl.VERTEEX_SHADER); gl.shaderSource(vertexShader,vsGLSL); gl.compileShader(vertexShader …

J.U.C Review - 阻塞队列原理/源码分析

文章目录 阻塞队列的由来BlockingQueue的操作方法BlockingQueue的实现类ArrayBlockingQueueLinkedBlockingQueueDelayQueuePriorityBlockingQueueSynchronousQueue 阻塞队列原理深入分析1. 构造器和监视器初始化2. put操作的实现3. take操作的实现4. 注意事项小结 线程池中的阻…

qmt量化交易策略小白学习笔记第57期【qmt编程之期权数据--获取指定期权品种的详细信息--内置Python】

qmt编程之获取期权数据 qmt更加详细的教程方法&#xff0c;会持续慢慢梳理。 也可找寻博主的历史文章&#xff0c;搜索关键词查看解决方案 &#xff01; 获取指定期权品种的详细信息 该函数能帮助用户获取指定期权品种的详细信息&#xff0c;如期权代码、市场、涨跌停价、期…

c++返回一个pair类型

前言 Under the new standard we can list initialize the return value. 代码测试 #include<iostream> #include<string> #include<vector>std::pair<std::string, int> process(std::vector<std::string>& v) {if (!v.empty()){return …

窖藏之秘:白酒在窖藏过程中经历了哪些变化?

在中华五千年的文明史中&#xff0c;白酒一直扮演着举足轻重的角色。它不仅是文人墨客笔下的灵感源泉&#xff0c;更是亲朋好友间传递情感的桥梁。在众多白酒品牌中&#xff0c;豪迈白酒&#xff08;HOMANLISM&#xff09;以其不同的酿造工艺和窖藏技艺&#xff0c;成为了酒中翘…

【前端面试】设计循环双端队列javascript

题目 https://leetcode.cn/problems/design-circular-deque/description/ 存储循环队列的向量空间是循环的&#xff0c;用通俗的话来讲&#xff0c;就是我们在做next或者prev操作时&#xff0c;不会发生溢出 取模、或者直接判断是否为0/size返回一个值。 数组实现 用函数来…

Python文件自动分类

假如这样的步骤全部手动做下来耗时是6秒&#xff0c;在文件数量不多的情况下&#xff0c;比如10个文件&#xff0c;总共耗时一分钟其实是能够接受的。 但当文件数量特别多时&#xff0c;或者这个操作特别频繁每天都要做十几二十次时&#xff0c;手动操作就会变得耗时又繁琐…

【Agent】Agent Q: Advanced Reasoning and Learning for Autonomous AI Agents

1、问题背景 传统的训练Agent方法是在静态数据集上进行监督预训练&#xff0c;这种方式对于要求Agent能够自主的在动态环境中可进行复杂决策的能力存在不足。例如&#xff0c;要求Agent在web导航等动态设置中执行复杂决策。 现有的方式是用高质量数据进行微调来增强Agent在动…

SpringBoot3.x+MyBatisPlus+druid多数据源配置

1 引言 本章主要介绍SpringBoot3.x多数据源配置&#xff0c;以及在此基础上配置分页拦截&#xff0c;自动填充功等功能&#xff0c;源码链接在文章最后。下面列出几个重要文件进行介绍。 2 项目结构 整体项目结构如下&#xff0c;主要介绍配置文件和配置类。 3 主要代码 …

Android Telephony总结

1、Telephony 业务介绍 Android telephony涉及较多模块 1.1、STK业务介绍 1.1.1、STK域选 1.1.2、是否支持STK Telephon STK-CSDN博客 1.1.3、STK应用的安装卸载 1.2、SS补充业务 1.3、通话业务 1.3.1、紧急号码 ECC 号码总结_ecc号码-CSDN博客 1.4、SMS 1.4.1 短信发送方式…

Datawhale X 李宏毅苹果书 AI夏令营-深度学习入门task3:实践方法论

在应用机器学习算法时&#xff0c;实践方法论能够帮助我们更好地训练模型。 1.模型偏差 模型偏差可能会影响模型训练。举个例子&#xff0c;假设模型过于简单&#xff0c;即使找到的最好的函数也不能满足需求。这种情况就是想要在大海里面捞针&#xff08;一个损失低的函数&am…