Java中调用第三方接口的详细代码示例

 更新时间:2024年12月07日 14:33:53   作者:-代号9527  
这篇文章主要介绍了Java中调用第三方接口的详细代码示例,文章总结了多种Java进行HTTP请求的方法,每种方法都有其特点和适用场景,从原生到封装,再到声明式客户端,满足了不同复杂度的HTTP请求需求,需要的朋友可以参考下

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 {

    @Bean
    public 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 {

    @Resource
    private RestTemplate restTemplate;

    @Test
    void 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对象:

@Test
 void testTemplate() {
     String url = "http://localhost:8080/svc1/t1";
     String name = "Tom";
     // 使用 UriComponentsBuilder 构建 URL
     URI 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 {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        //添加token
        requestTemplate.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);

    @Override
    public RemoteMessageService create(Throwable throwable) {
        throwable.printStackTrace();
        log.error("消息服务调用失败:{}", throwable.getMessage());
        return new RemoteMessageService() {
            @Override
            public R<Void> sendTimingMessage() {
                return R.fail("调用发送定时消息接口失败:" + throwable.getMessage());
            }

            @Override
            public 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) {
    // 路径参数不为空时,拼接URL
    if (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 {
             // 路径参数不为空时,拼接URL
             if (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();

 }

总结 

到此这篇关于Java中调用第三方接口的文章就介绍到这了,更多相关Java调用第三方接口内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Maven Plugins报错的解决方法

    Maven Plugins报错的解决方法

    本文主要介绍了Maven Plugins报错的解决方法,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-02-02
  • Mybatis报Type interface *.*Mapper is not known to the MapperRegis

    Mybatis报Type interface *.*Mapper is not&

    本文主要介绍了Mybatis报Type interface *.*Mapper is not known to the MapperRegis,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-07-07
  • mybatis中insert返回值为1,但数据库却没有数据

    mybatis中insert返回值为1,但数据库却没有数据

    这篇文章主要介绍了mybatis中insert返回值为1,但数据库却没有数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • 教你怎么使用hadoop来提取文件中的指定内容

    教你怎么使用hadoop来提取文件中的指定内容

    发现有很多小伙伴不会使用hadoop来提取文件中的指定内容,今天特地整理了这篇文章,文中有非常详细的代码示例,对不会这个方法的小伙伴们有很好地帮助,需要的朋友可以参考下
    2021-05-05
  • 详解JAVA设计模式之适配器模式

    详解JAVA设计模式之适配器模式

    这篇文章主要介绍了JAVA设计模式之适配器模式的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解
    2020-06-06
  • Java 数据流之Broadcast State

    Java 数据流之Broadcast State

    这篇文章主要介绍了Java 数据流之Broadcast State,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • Mybatis应用mysql存储过程查询数据实例

    Mybatis应用mysql存储过程查询数据实例

    下面小编就为大家分享一篇Mybatis应用mysql存储过程查询数据实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12
  • MAC 在类路径或引导类路径中找不到程序包 java.lang问题

    MAC 在类路径或引导类路径中找不到程序包 java.lang问题

    这篇文章主要介绍了MAC 在类路径或引导类路径中找不到程序包 java.lang问题及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • 详解JAVA Spring 中的事件机制

    详解JAVA Spring 中的事件机制

    这篇文章主要介绍了JAVA Spring 中的事件机制的相关资料,文中示例代码非常细致,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • IDEA安装Leetcode插件的教程

    IDEA安装Leetcode插件的教程

    这篇文章主要介绍了IDEA安装Leetcode插件的教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11

最新评论