spring 5 webclient使用指南

之前写了一篇restTemplate使用实例,由于spring 5全面引入reactive,同时也有了restTemplate的reactive版webclient,本文就来对应展示下webclient的基本使用。

请求携带header

  • 携带cookie @Test public void testWithCookie(){ Mono<String> resp = WebClient.create() .method(HttpMethod.GET) .uri("http://baidu.com") .cookie("token","xxxx") .cookie("JSESSIONID","XXXX") .retrieve() .bodyToMono(String.class); LOGGER.info("result:{}",resp.block()); }
  • 携带basic auth @Test public void testWithBasicAuth(){ String basicAuth = "Basic "+ Base64.getEncoder().encodeToString("user:pwd".getBytes(StandardCharsets.UTF_8)); LOGGER.info(basicAuth); Mono<String> resp = WebClient.create() .get() .uri("http://baidu.com") .header(HttpHeaders.AUTHORIZATION,basicAuth) .retrieve() .bodyToMono(String.class); LOGGER.info("result:{}",resp.block()); }
  • 设置全局user-agent @Test public void testWithHeaderFilter(){ WebClient webClient = WebClient.builder() .defaultHeader(HttpHeaders.USER_AGENT, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36") .filter(ExchangeFilterFunctions .basicAuthentication("user","password")) .filter((clientRequest, next) -> { LOGGER.info("Request: {} {}", clientRequest.method(), clientRequest.url()); clientRequest.headers() .forEach((name, values) -> values.forEach(value -> LOGGER.info("{}={}", name, value))); return next.exchange(clientRequest); }) .build(); Mono<String> resp = webClient.get() .uri("https://baidu.com") .retrieve() .bodyToMono(String.class); LOGGER.info("result:{}",resp.block()); }

get请求

  • 使用placeholder传递参数 @Test public void testUrlPlaceholder(){ Mono<String> resp = WebClient.create() .get() //多个参数也可以直接放到map中,参数名与placeholder对应上即可 .uri("http://www.baidu.com/s?wd={key}&other={another}","北京天气","test") //使用占位符 .retrieve() .bodyToMono(String.class); LOGGER.info("result:{}",resp.block()); }
  • 使用uriBuilder传递参数 @Test public void testUrlBiulder(){ Mono<String> resp = WebClient.create() .get() .uri(uriBuilder -> uriBuilder .scheme("http") .host("www.baidu.com") .path("/s") .queryParam("wd", "北京天气") .queryParam("other", "test") .build()) .retrieve() .bodyToMono(String.class); LOGGER.info("result:{}",resp.block()); }

post表单

    @Test
    public void testFormParam(){
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("name1","value1");
        formData.add("name2","value2");
        Mono<String> resp = WebClient.create().post()
                .uri("http://www.w3school.com.cn/test/demo_form.asp")
                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                .body(BodyInserters.fromFormData(formData))
                .retrieve().bodyToMono(String.class);
        LOGGER.info("result:{}",resp.block());
    }

post json

  • 使用bean来post static class Book { String name; String title; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } } @Test public void testPostJson(){ Book book = new Book(); book.setName("name"); book.setTitle("this is title"); Mono<String> resp = WebClient.create().post() .uri("http://localhost:8080/demo/json") .contentType(MediaType.APPLICATION_JSON_UTF8) .body(Mono.just(book),Book.class) .retrieve().bodyToMono(String.class); LOGGER.info("result:{}",resp.block()); }
  • 直接post raw json @Test public void testPostRawJson(){ Mono<String> resp = WebClient.create().post() .uri("http://localhost:8080/demo/json") .contentType(MediaType.APPLICATION_JSON_UTF8) .body(BodyInserters.fromObject("{\n" + " \"title\" : \"this is title\",\n" + " \"author\" : \"this is author\"\n" + "}")) .retrieve().bodyToMono(String.class); LOGGER.info("result:{}",resp.block()); }

post二进制—上传文件

    @Test
    public void testUploadFile(){
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.IMAGE_PNG);
        HttpEntity<ClassPathResource> entity = new HttpEntity<>(new ClassPathResource("parallel.png"), headers);
        MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
        parts.add("file", entity);
        Mono<String> resp = WebClient.create().post()
                .uri("http://localhost:8080/upload")
                .contentType(MediaType.MULTIPART_FORM_DATA)
                .body(BodyInserters.fromMultipartData(parts))
                .retrieve().bodyToMono(String.class);
        LOGGER.info("result:{}",resp.block());
    }

下载二进制

  • 下载图片 @Test public void testDownloadImage() throws IOException { Mono<Resource> resp = WebClient.create().get() .uri("http://www.toolip.gr/captcha?complexity=99&size=60&length=9") .accept(MediaType.IMAGE_PNG) .retrieve().bodyToMono(Resource.class); Resource resource = resp.block(); BufferedImage bufferedImage = ImageIO.read(resource.getInputStream()); ImageIO.write(bufferedImage, "png", new File("captcha.png")); }
  • 下载文件 @Test public void testDownloadFile() throws IOException { Mono<ClientResponse> resp = WebClient.create().get() .uri("http://localhost:8080/file/download") .accept(MediaType.APPLICATION_OCTET_STREAM) .exchange(); ClientResponse response = resp.block(); String disposition = response.headers().asHttpHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION); String fileName = disposition.substring(disposition.indexOf("=")+1); Resource resource = response.bodyToMono(Resource.class).block(); File out = new File(fileName); FileUtils.copyInputStreamToFile(resource.getInputStream(),out); LOGGER.info(out.getAbsolutePath()); }

错误处理

    @Test
    public void testRetrieve4xx(){
        WebClient webClient = WebClient.builder()
                .baseUrl("https://api.github.com")
                .defaultHeader(HttpHeaders.CONTENT_TYPE, "application/vnd.github.v3+json")
                .defaultHeader(HttpHeaders.USER_AGENT, "Spring 5 WebClient")
                .build();
        WebClient.ResponseSpec responseSpec = webClient.method(HttpMethod.GET)
                .uri("/user/repos?sort={sortField}&direction={sortDirection}",
                        "updated", "desc")
                .retrieve();
        Mono<String> mono = responseSpec
                .onStatus(e -> e.is4xxClientError(),resp -> {
                    LOGGER.error("error:{},msg:{}",resp.statusCode().value(),resp.statusCode().getReasonPhrase());
                    return Mono.error(new RuntimeException(resp.statusCode().value() + " : " + resp.statusCode().getReasonPhrase()));
                })
                .bodyToMono(String.class)
                .doOnError(WebClientResponseException.class, err -> {
                    LOGGER.info("ERROR status:{},msg:{}",err.getRawStatusCode(),err.getResponseBodyAsString());
                    throw new RuntimeException(err.getMessage());
                })
                .onErrorReturn("fallback");
        String result = mono.block();
        LOGGER.info("result:{}",result);
    }
  • 可以使用onStatus根据status code进行异常适配
  • 可以使用doOnError异常适配
  • 可以使用onErrorReturn返回默认值

小结

webclient是新一代的async rest template,api也相对简洁,而且是reactive的,非常值得使用。

doc

  • restTemplate使用实例
  • Decode ByteArray with spring 5 WebFlux framework

原文发布于微信公众号 - 码匠的流水账(geek_luandun)

原文发表时间:2018-01-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏GIS讲堂

转换Arcgis Server REST接口实现OL2直接调用

本文讲解如何通过Arcgis Server REST 的导出地图(Export)接口,实现在OL2中直接以WMS的方式调用Arcgis Server REST...

15920
来自专栏岑玉海

RavenDb学习(六)查询补充特性

1、延迟加载 原来的查询方式如下: IEnumerable<User> users = session .Query<User>() .Wher...

30360
来自专栏哲学驱动设计

P of EAA 总结

看了几遍了,就只在书上勾了下,也没什么总结。暂且先把关键内容摘抄如下: Domain Logic Patterns Transaction Script Org...

22250
来自专栏SAP最佳业务实践

SAP最佳业务实践:SD–带变式价格的销售报价(663)-3修改报价

一、 VA23 Outputting Quotation Document After the quotation has been created in th...

36840
来自专栏XAI

SpringMVC+Hibernate +MySql+ EasyUI实现CRUD(一)

最新项目下载地址 访问地址 ? 1.基于easyui的 增 删 改 查 2.基于poi的导出excel 3.基于 SpringMVC HandlerInte...

529110
来自专栏Java面试笔试题

三级下拉选

一级下拉选没有father_id,二级下拉选的father_id是一级下拉选的id,三级下拉选的father_id是二级下拉选的id,以此类推。 2、SQL

16010
来自专栏函数式编程语言及工具

ScalaPB(5):用akka-stream实现reactive-gRPC

23230
来自专栏菩提树下的杨过

silverlight:ListBox中如何取得DateTemplate/ItemsPanelTemplate中的命名控件?

Xaml如下: <UserControl x:Class="ToolsTest.Test"     xmlns="http://schemas.microsof...

20050
来自专栏一个会写诗的程序员的博客

spring-data-jpa + SpringBoot + bootstrapTable 后端分页 模糊查询spring-data-jpa + SpringBoot + bootstrapTab

需要注意的是,bootstrap-table与bootstrap 3是兼容的。但是bootstrap 4还不行。

42710
来自专栏Hongten

HQL 语句

import java.util.Iterator; import java.util.List; import java.util.Map;

27920

扫码关注云+社区

领取腾讯云代金券