欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring5 webclient使用指南详解

程序员文章站 2023-12-02 20:53:34
之前写了一篇resttemplate使用实例,由于spring 5全面引入reactive,同时也有了resttemplate的reactive版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);
  }
  1. 可以使用onstatus根据status code进行异常适配
  2. 可以使用doonerror异常适配
  3. 可以使用onerrorreturn返回默认值

小结

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。