Spring Cloud gateway通过WebClient异步调用微服务
1、在gateway中创建注入配置类,添加@LoadBalanced注解后才能通过服务名进行远程调用,否则只通过IP调用
@Configuration
public class WebClientConfig {
@Bean
@LoadBalanced
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
}
2、在gateway中的调用方注入webclient,并且创建线程池
@Autowired
private WebClient.Builder webClientBuilder;
//线程池
//ExecutorService executorService = Executors.newFixedThreadPool(2);
ExecutorService executorService = Executors.newCachedThreadPool();
3、通过线程异步调用服务并获取结果,服务名以lb://方式请求,future.get()要设置超时时间,否则有可能一直被阻塞
List<String> list = new ArrayList<>();
try {
Long id = StpUtil.getLoginIdAsLong();
//String url = "http://127.0.0.1:802/user/" + id;
//WebClient webClient = WebClient.create(url); //通过这种方法创建,mono处的uri节点不需要
String url = "lb://" + ServiceNameConstants.USER_SERVICE + "/user/" + id;
WebClient webClient = webClientBuilder.build();
Mono<ResultData<User>> mono = webClient.get().uri(url).header(SaSameUtil.SAME_TOKEN, SaSameUtil.getToken()).retrieve().bodyToMono(new ParameterizedTypeReference<ResultData<User>>() {
});
Future future = executorService.submit((Callable<ResultData<User>>) () -> mono.block());
List<Menu> menus = ((ResultData<User>) future.get(5, TimeUnit.SECONDS)).getData().getMenus();
if (menus != null) {
menus.stream().forEach(r -> list.add(r.getCode()));
}
//超级管理员权限
if (StpUtil.hasRole("administrator")) {
list.add("*");
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
return list;
4、API详解
| build().get() | get请求 | build().method(HttpMethod.GET) |
| build().post() | post请求 | build().method(HttpMethod.POST) |
| build().put() | put请求 | build().method(HttpMethod.PUT) |
| build().delete() | delete请求 | build().method(HttpMethod.DELETE) |
响应类型
| 类型 | 描述 | 方法 |
| Mono | 包含0个或1个元素 | bodyToMono(String.class) |
| Flux | 包含1个或多个元素 | .bodyToFlux(String.class) |
5、忽略SSL证书及Bearer示例
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty-http</artifactId>
</dependency>
import io.netty.handler.ssl.*
import reactor.netty.http.client.HttpClient;
String baseUrl = "https://filez.bba.com:5555/v2";
String appKey = "xxxxxxdfd";
String appSecret = "vvvvvvvxxs";
// Authorization Bearer 64位编码
// String encodeAuthStr = Base64.getEncoder().encodeToString((appKey+":"+appSecret).getBytes());
// 忽略证书
SslContext context = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(context));
var tokenClient = WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient))
// Authorization Bearer 64位编码
.filter(ExchangeFilterFunctions.basicAuthentication(appKey, appSecret))
.baseUrl(baseUrl).build();
MultiValueMap<String, String> tokenFormData = new LinkedMultiValueMap<>();
tokenFormData.add("grant_type", "client_with_su");
tokenFormData.add("scope", "all");
tokenFormData.add("slug", "admin");
JSONObject tokenJson = tokenClient.post().uri("/oauth/token")
.contentType(MediaType.APPLICATION_FORM_URLENCODED).bodyValue(tokenFormData)
.retrieve().bodyToMono(JSONObject.class).block();
var client = WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient))
.defaultHeader("Authorization", "Bearer " + tokenJson.getString("access_token"))
.baseUrl(baseUrl).build();
// /api/user/slug?user_slug=13800013800
JSONObject queryJson = client.get().uri(uriBuilder -> uriBuilder.path("/api/user/slug").queryParam("user_slug", mobile).build())
.retrieve().bodyToMono(JSONObject.class).block();
log.info("查询用户结果:" + queryJson);
if (queryJson.get("uid") != null) {
String uid = queryJson.getString("uid");
if ("0".equals(status)) {
JSONObject userJson = client.delete().uri("/api/user/freeze?uids=" + uid)
.retrieve().bodyToMono(JSONObject.class).block();
if ("0".equals(userJson.getString("errcode"))) {
returnMap.put("flag", true);
returnMap.put("result", "HR数据同步到File冰结成功");
} else {
returnMap.put("result", userJson.getString("errmsg"));
}
} else {
MultiValueMap<String, String> jdFormData = new LinkedMultiValueMap<>();
jdFormData.add("uids", uid);
JSONObject userJson = client.post().uri("/api/user/active").contentType(MediaType.APPLICATION_FORM_URLENCODED)
.bodyValue(jdFormData).retrieve().bodyToMono(JSONObject.class).block();
if ("0".equals(userJson.getString("errcode"))) {
returnMap.put("flag", true);
returnMap.put("result", "HR数据同步到File解结成功");
} else {
returnMap.put("result", userJson.getString("errmsg"));
}
}
} else {
MultiValueMap<String, String> userFormData = new LinkedMultiValueMap<>();
userFormData.add("email", email);
userFormData.add("mobile", mobile);
userFormData.add("password", "bxlfilez.2024");
userFormData.add("quota", "");
userFormData.add("status", status);
userFormData.add("user_name", lastName);
userFormData.add("user_slug", mobile);
JSONObject userJson = client.post().uri("/api/user").contentType(MediaType.APPLICATION_FORM_URLENCODED)
.bodyValue(userFormData).retrieve().bodyToMono(JSONObject.class).block();
log.info("创建用户结果:" + userJson);
if ("0".equals(userJson.getString("errcode"))) {
returnMap.put("flag", true);
returnMap.put("result", "HR数据同步到File成功");
} else {
returnMap.put("result", userJson.getString("errmsg"));
}
}
6、天眼查示例
// 股权穿透455
String url1 = "http://open.api.tianyancha.com/services/v3/open/investtree?flag=4&dir=up&keyword=";
// 董监高信息855
String url2 = "http://open.api.tianyancha.com/services/open/stock/seniorExecutive/2.0?pageSize=20&keyword=";
var client = WebClient.builder()
//修改maxInMemorySize的缓冲值,默认是256KB,修改为10MB
.codecs(item -> item.defaultCodecs().maxInMemorySize(10 * 1024 * 1024))
.defaultHeader("Authorization", "f56896a2-41d3-4b1f-92a9-xxxxxxx").build().get();
String resultString = client.uri(url1 + li.getName()).retrieve().bodyToMono(String.class).block();
resultString = resultString.replace("\"[", "[").replace("]\"", "]").replace("\\\"", "\"");
JSONObject jsonObject = JSON.parseObject(resultString);
7、查询IP示例
JSONObject result = WebClient.builder()
.codecs(item -> item.defaultCodecs().maxInMemorySize(10 * 1024 * 1024))
.baseUrl("https://api.vvhan.com").build()
.get().uri(uriBuilder -> uriBuilder.path("/api/ipInfo").queryParam("ip", ip).build())
.retrieve().bodyToMono(JSONObject.class).block();
8、RestClient查询天气示例:
RestClient client = RestClient.create(URI.create("https://api.vvhan.com"));
JSONObject result = client.get()
.uri("/api/weather?city={0}", city)
.retrieve()
.body(JSONObject.class);
浙公网安备 33010602011771号