WebClient是Spring提供的非阻塞、响应式的Http客户端,提供同步及异步的API,将会代替RestTemplate及AsyncRestTemplate。文中所使用到的软件版本:Java 1.8.0_191、SpringBoot 2.2.1.RELEASE。

1、服务端

参见Java调用Http接口(1)--编写服务端

2、调用

使用WebClient需要用到Reactor Netty,依赖如下:

        <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty</artifactId>
</dependency>

2.1、GET请求

    public static void get() {
String requestPath = "http://localhost:8080/demo/httptest/getUser?userId=1000&userName=李白";
WebClient webClient = WebClient.create();
Mono<String> mono = webClient.get().uri(requestPath).retrieve().bodyToMono(String.class);
//同步方式
System.out.println("get block返回结果:" + mono.block()); //异步方式
final CountDownLatch latch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
requestPath = "http://localhost:8080/demo/httptest/getUser?userId=1000&userName=李白" + i;
mono = webClient.get().uri(requestPath).retrieve().bodyToMono(String.class);
mono.subscribe(new Consumer<String>() {
@Override
public void accept(String s) {
latch.countDown();
System.out.println("get subscribe返回结果:" + s);
}
});
} try {
latch.await();
} catch (Exception e) {
e.printStackTrace();
}
}

2.2、POST请求(发送键值对数据)

    public static void post() {
String requestPath = "http://localhost:8080/demo/httptest/getUser";
WebClient webClient = WebClient.create();
MultiValueMap<String, String> map = new LinkedMultiValueMap <String, String>();
map.add("userId", "1000");
map.add("userName", "李白");
Mono<String> mono = webClient.post().uri(requestPath).bodyValue(map).retrieve().bodyToMono(String.class);
System.out.println("post返回结果:" + mono.block());
}

2.3、POST请求(发送JSON数据)

    public static void post2() {
String requestPath = "http://localhost:8080/demo/httptest/addUser";
WebClient webClient = WebClient.create();
String param = "{\"userId\": \"1001\",\"userName\":\"杜甫\"}";
Mono<String> mono = webClient.post().uri(requestPath).contentType(MediaType.APPLICATION_JSON).bodyValue(param)
.retrieve().bodyToMono(String.class);
System.out.println("post json返回结果:" + mono.block());
}

2.4、上传文件

    public static void upload() {
String requestPath = "http://localhost:8080/demo/httptest/upload";
WebClient webClient = WebClient.create();
Mono<String> mono = webClient.post().uri(requestPath).contentType(MediaType.APPLICATION_OCTET_STREAM)
.bodyValue(new FileSystemResource("d:/a.jpg")).retrieve().bodyToMono(String.class);
System.out.println("upload返回结果:" + mono.block());
}

2.5、上传文件及发送键值对数据

    public static void mulit() {
String requestPath = "http://localhost:8080/demo/httptest/multi";
WebClient webClient = WebClient.create(); MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("param1", "参数1");
builder.part("param2", "参数2");
builder.part("file", new FileSystemResource("d:/a.jpg"));
MultiValueMap<String, HttpEntity<?>> parts = builder.build();
Mono<String> mono = webClient.post().uri(requestPath)
.bodyValue(parts).retrieve().bodyToMono(String.class);
System.out.println("mulit返回结果:" + mono.block());
}

2.6、完整例子

package com.inspur.demo.http.client;

import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer; import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.MediaType;
import org.springframework.http.client.MultipartBodyBuilder;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; /**
*
* 通过WebClient调用Http接口
*
*/
public class WebClientCase {
/**
* GET请求
*/
public static void get() {
String requestPath = "http://localhost:8080/demo/httptest/getUser?userId=1000&userName=李白";
WebClient webClient = WebClient.create();
Mono<String> mono = webClient.get().uri(requestPath).retrieve().bodyToMono(String.class);
//同步方式
System.out.println("get block返回结果:" + mono.block()); //异步方式
final CountDownLatch latch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
requestPath = "http://localhost:8080/demo/httptest/getUser?userId=1000&userName=李白" + i;
mono = webClient.get().uri(requestPath).retrieve().bodyToMono(String.class);
mono.subscribe(new Consumer<String>() {
@Override
public void accept(String s) {
latch.countDown();
System.out.println("get subscribe返回结果:" + s);
}
});
} try {
latch.await();
} catch (Exception e) {
e.printStackTrace();
}
} /**
* POST请求(发送键值对数据)
*/
public static void post() {
String requestPath = "http://localhost:8080/demo/httptest/getUser";
WebClient webClient = WebClient.create();
MultiValueMap<String, String> map = new LinkedMultiValueMap <String, String>();
map.add("userId", "1000");
map.add("userName", "李白");
Mono<String> mono = webClient.post().uri(requestPath).bodyValue(map).retrieve().bodyToMono(String.class);
System.out.println("post返回结果:" + mono.block());
} /**
* POST请求(发送json数据)
*/
public static void post2() {
String requestPath = "http://localhost:8080/demo/httptest/addUser";
WebClient webClient = WebClient.create();
String param = "{\"userId\": \"1001\",\"userName\":\"杜甫\"}";
Mono<String> mono = webClient.post().uri(requestPath).contentType(MediaType.APPLICATION_JSON).bodyValue(param)
.retrieve().bodyToMono(String.class);
System.out.println("post json返回结果:" + mono.block());
} /**
* 上传文件
*/
public static void upload() {
String requestPath = "http://localhost:8080/demo/httptest/upload";
WebClient webClient = WebClient.create();
Mono<String> mono = webClient.post().uri(requestPath).contentType(MediaType.APPLICATION_OCTET_STREAM)
.bodyValue(new FileSystemResource("d:/a.jpg")).retrieve().bodyToMono(String.class);
System.out.println("upload返回结果:" + mono.block());
} /**
* 上传文件及发送键值对数据
*/
public static void mulit() {
String requestPath = "http://localhost:8080/demo/httptest/multi";
WebClient webClient = WebClient.create(); MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("param1", "参数1");
builder.part("param2", "参数2");
builder.part("file", new FileSystemResource("d:/a.jpg"));
MultiValueMap<String, HttpEntity<?>> parts = builder.build();
Mono<String> mono = webClient.post().uri(requestPath)
.bodyValue(parts).retrieve().bodyToMono(String.class);
System.out.println("mulit返回结果:" + mono.block());
} public static void main(String[] args) {
get();
post();
post2();
upload();
mulit();
} }

3、调用Https接口

与调用Http接口不一样的部分主要在设置ssl部分,设置方法是生成合适的ClientHttpConnector;下面用GET请求来演示ssl的设置,其他调用方式类似。

package com.inspur.demo.http.client;

import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer; import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SNIMatcher;
import javax.net.ssl.SNIServerName;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManagerFactory; import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient; import com.inspur.demo.common.util.FileUtil; import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.tcp.SslProvider.SslContextSpec; /**
* 通过WebClient调用Https接口
*/
public class WebClientHttpsCase {
public static void main(String[] args) {
try {
/*
* 请求有权威证书的地址
*/
String requestPath = "https://www.12306.cn/index/";
WebClient webClient = WebClient.create();
Mono<String> mono = webClient.get().uri(requestPath).retrieve().bodyToMono(String.class);
System.out.println("get1返回结果:" + mono.block()); /*
* 请求自定义证书的地址
*/
//获取信任证书库
KeyStore trustStore = getkeyStore("jks", "d:/temp/cacerts", "123456"); //不需要客户端证书
requestPath = "https://10.40.103.48:9010/zsywservice/";
webClient = WebClient.builder().clientConnector(getClientHttpConnector(trustStore)).build();
mono = webClient.get().uri(requestPath).retrieve().bodyToMono(String.class);
System.out.println("get2返回结果:" + mono.block()); //需要客户端证书
requestPath = "https://10.40.103.48:9016/zsywservice/";
KeyStore keyStore = getkeyStore("pkcs12", "d:/client.p12", "123456");
webClient = WebClient.builder().clientConnector(getClientHttpConnector(keyStore, "123456", trustStore)).build();
mono = webClient.get().uri(requestPath).retrieve().bodyToMono(String.class);
System.out.println("get3返回结果:" + mono.block());
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 获取Connector
* @param keyStore
* @param password
* @return
* @throws Exception
*/
private static ClientHttpConnector getClientHttpConnector(KeyStore keyStore, String keyStorePassword, KeyStore trustStore) throws Exception {
SslContextBuilder builder = SslContextBuilder.forClient();
if (keyStore != null) {
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
builder.keyManager(keyManagerFactory);
}
if (trustStore != null) {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
trustManagerFactory.init(trustStore);
builder.trustManager(trustManagerFactory);
} else {
builder.trustManager(InsecureTrustManagerFactory.INSTANCE);
}
SslContext sslContext = builder.build();
HttpClient httpClient = HttpClient.create().secure(new Consumer<SslContextSpec>() {
@Override
public void accept(SslContextSpec t) {
t.sslContext(sslContext).handlerConfigurator(handler -> {
SSLEngine engine = handler.engine();
List<SNIMatcher> matchers = new LinkedList<SNIMatcher>();
SNIMatcher matcher = new SNIMatcher(0) {
@Override
public boolean matches(SNIServerName serverName) {
//if ("xxx".equals(serverName)) {
// return true;
//} else {
// return false;
//}
return true;
}
};
matchers.add(matcher);
SSLParameters params = new SSLParameters();
params.setSNIMatchers(matchers);
engine.setSSLParameters(params);
});
}
}); ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
return connector;
} private static ClientHttpConnector getClientHttpConnector(KeyStore trustStore) throws Exception {
return getClientHttpConnector(null, null, trustStore);
} /**
* 获取证书
* @param type
* @param filePath
* @param password
* @return
*/
private static KeyStore getkeyStore(String type, String filePath, String password) {
KeyStore keySotre = null;
FileInputStream in = null;
try {
keySotre = KeyStore.getInstance(type);
in = new FileInputStream(new File(filePath));
keySotre.load(in, password.toCharArray());
} catch (Exception e) {
e.printStackTrace();
} finally {
FileUtil.close(in);
}
return keySotre;
}
}

Java调用Http/Https接口(7,end)--WebClient调用Http/Https接口的更多相关文章

  1. java编程(1)——servlet和Ajax异步请求的接口编程(没有调用数据库的数据)

    编程应用背景: 使用HttpServlet接口来编写一个动态登录的接口(需要在Tomcat容器发布) 登录的 LoginSample 类代码: package com.zhang.java; publ ...

  2. Golang、Php、Python、Java基于Thrift0.9.1实现跨语言调用

    目录: 一.什么是Thrift? 1) Thrift内部框架一瞥 2) 支持的数据传输格式.数据传输方式和服务模型 3) Thrift IDL 二.Thrift的官方网站在哪里? 三.在哪里下载?需要 ...

  3. Java HttpClient伪造请求之简易封装满足HTTP以及HTTPS请求

    HttpClient简介 HTTP 协议可能是现在 Internet 上使用得最多.最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源.虽然在 JDK 的 jav ...

  4. 夯实Java基础系列6:一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别!

    目录 抽象类介绍 为什么要用抽象类 一个抽象类小故事 一个抽象类小游戏 接口介绍 接口与类相似点: 接口与类的区别: 接口特性 抽象类和接口的区别 接口的使用: 接口最佳实践:设计模式中的工厂模式 接 ...

  5. Java工作笔记:工作中使用JNA调用C++库的一些细节(转载)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/zjutzmh/article/detai ...

  6. java方法句柄-----1.方法句柄类型、调用

    目录 方法句柄 1.方法句柄的类型 1.1MethodType类的对象实例的创建 1.1.1 通过指定参数和返回值的类型来创建MethodType.[显式地指定返回值和参数的类型] 1.1.2 通过静 ...

  7. Java(JCo3)与SAP系统相互调用

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  8. 五:用JAVA写一个阿里云VPC Open API调用程序

    用JAVA写一个阿里云VPC Open API调用程序 摘要:用JAVA拼出来Open API的URL 引言 VPC提供了丰富的API接口,让网络工程是可以通过API调用的方式管理网络资源.用程序和软 ...

  9. JAVA基础第三章-类与对象、抽象类、接口

    业内经常说的一句话是不要重复造轮子,但是有时候,只有自己造一个轮子了,才会深刻明白什么样的轮子适合山路,什么样的轮子适合平地! 我将会持续更新java基础知识,欢迎关注. 往期章节: JAVA基础第一 ...

随机推荐

  1. Redis中删除过期Key的三种策略

    转载自:http://blog.csdn.net/a_bang/article/details/52986935?locationNum=9&fps=1 项目中有个接口要频繁调用查询数据库中的 ...

  2. Emotion Recognition Using Graph Convolutional Networks

    Emotion Recognition Using Graph Convolutional Networks 2019-10-22 09:26:56 This blog is from: https: ...

  3. hive删除空分区

    当hive中分区字段有NULL值时,hive会使用dynamic partition,数据会放到一个特殊的分区,这个分区由参数“hive.exec.default.partition.name”控制, ...

  4. RockBrain USB Server外设虚拟化高可用解决方案(银企直联虚拟化解决方案)

    技术指标: 单.双千兆网络界面(支持链路冗余与链路热备.支持双网口均衡负载) 原生USB2.0接口(USB2.0与USB3.0接口均对所有USB版本设备兼容,支持混插) 技术优势: RockBrain ...

  5. css---【vw,vh】进行自适应布局单位

    在进行CSS3自适应布局,会用到 vw 和 vh 进行布局 视口单位(Viewport units) 什么是视口? 在桌面端,视口指的是在桌面端,指的是浏览器的可视区域:而在移动端,它涉及3个视口:L ...

  6. CentOS7静默安装Oracle 18g数据库(无图形化界面)

    说明: 因为是静默安装,所以我们不需要安装图形界面 准备:下载Oracle软件 官方网站:http://www.oracle.com/technetwork/database/enterprise-e ...

  7. java 欢迎页 主页 设置为servlet的方法

    [参考]Java Web 设置默认首页 [参考]设置servlet或action作为欢迎页面 1. 使用HTML<meta>标签跳转至servlet  <META HTTP-EQUI ...

  8. 解决IDEA中导入新的maven依赖后Language Level自动重置问题

    问题: 弄了个测试项目,因为有涉及JDK1.8的代码,所以将IDEA中默认的Language Level 5(即对应JDK1.5),修改为了8(即对应JDK1.8),但是每次引入新的maven依赖,自 ...

  9. Prometheus监控实战day2——监控主机和容器

    Prometheus使用exporter工具来暴露主机和应用程序上的指标,目前有很多exporter可供利用.对于收集各种主机指标数据(包括CPU.内存和磁盘),我们使用Node Exporter即可 ...

  10. Centos7根据yum源安装指定版本docker

    yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo https://mi ...