轻量级HTTP客户端框架—Forest

简介

Forest 是一个开源的 Java HTTP 客户端框架,它能够将 HTTP 的所有请求信息(包括 URL、Header 以及 Body 等信息)绑定到自定义的 Interface 方法上,能够通过调用本地接口方法的方式发送 HTTP 请求。使用 Forest 就像使用类似 Dubbo 那样的 RPC 框架一样,只需要定义接口,调用接口即可,不必关心具体发送 HTTP 请求的细节。

协议

使用HTTP协议,不需要注册中心

Forest工作原理

Forest会将定义好的接口通过动态代理的方式生成一个具体的实现类

轻量级HTTP客户端框架—Forest_第1张图片

HttpClient HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。虽然JDK 的 java net包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。HttpClient用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议的最新版本。

使用HttpClient发送请求和接收响应一般分为以下几步

(1)创建HttpClient对象;

(2)创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象;

(3)如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用

setEntity(HttpEntity entity)方法来设置请求参数;

(4)调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse;

(5)调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容,程序可通过该对象获取服务器的响应内容;

(6)释放连接。无论执行方法是否成功,都必须释放连接。

Okhttp

Okhttp作为目前Android使用最为广泛的网络框架之一,是一个高效的HTTP Client

Okhttp原理解析:论文级深度长文 OkHttp 原理解析!_retryonconnectionfailure-CSDN博客

Forest优点

使用 Forest 就像使用类似 Dubbo 那样的 RPC 框架一样,只需要定义接口,调用接口即可,不必关心具体发送 HTTP 请求的细节。同时将 HTTP 请求信息与业务代码解耦,方便您统一管理大量 HTTP 的 URL、Header 等信息。而请求的调用方完全不必在意 HTTP 的具体内容,即使该 HTTP 请求信息发生变更,大多数情况也不需要修改调用发送请求的代码。

Forest使用
依赖

    com.dtflys.forest
    forest-spring-boot-starter
    1.5.36
配置
# 在spring上下文中bean的id, 默认值为forestConfiguration
forest.bean-id=forestConfiguration
# 后端HTTP API: 默认使用:okhttp3,也可以替换成:httpclient
forest.backend=okhttp3
# 连接池最大连接数,默认值为500
forest.max-connections=1000
# 每个路由的最大连接数,默认值为500
forest.max-route-connections=500
# 请求超时时间,单位为毫秒, 默认值为3000
forest.timeout=3000
# 连接超时时间,单位为毫秒, 默认值为2000
forest.connect-timeout=3000
# 单向验证的HTTPS的默认SSL协议,默认为SSLv3
forest.ssl-protocol=SSLv3
# 打开或关闭日志,默认为true,也可以在单个方法上加注解是否开启:@LogEnabled
forest.logEnabled=true
用法

构建接口:在 Forest 中,所有的 HTTP 请求信息都要绑定到某一个接口的方法上,不需要编写具体的方法体去发送请求。

@BaseRequest(baseURL="http://localhost:8081/development",connectTimeout = 60000,readTimeout = 60000)
public interface ForestClient {

    @Get(url = "/all")
    List selectAllDepartment(OnError onError);

}

使用:

(1)GET请求
@RestController
@RequestMapping("/forest")
public class ForestController {
    @Resource
    private MyForest myForest;

   @GetMapping("/select")
    public List selectDepartmentList(){
        return forestClient.selectAllDepartment((forestRuntimeException, forestRequest, forestResponse)->{
            int status = forestResponse.getStatusCode(); // 获取请求响应状态码
            String content = forestResponse.getContent(); // 获取请求的响应内容
            Object result = forestResponse.getResult();// 获取方法返回类型对应的最终数据结果
        });
    }
}
(2)POST方式
@BaseRequest(baseURL="http://localhost:8081/development",connectTimeout = 60000,readTimeout = 60000)
public interface ForestClient {

    /**
     * 通过 @Request 注解的 type 参数指定 HTTP 请求的方式。
     */
    @Request(
            url = "http://localhost:8080/hello",
            type = "POST"
    )
    ForestResponse save(@Body Development development);

    /**
     * 使用 @Post 注解,可以去掉 type = "POST" 这行属性
     */
    @Post("http://localhost:8080/hello")
    ForestResponse save(@Body Development development);

    /**
     * 使用 @PostRequest 注解,和上面 @Post 效果等价
     */
    @PostRequest("http://localhost:8080/hello")
    ForestResponse save(@Body Development development);

}

注意

  • @Get@GetRequest两个注解的效果是等价的,@Post@PostRequest@Put@PutRequest等注解也是同理

(3)@DataVariable注解

整个URL都通过 @DataVariable 注解修饰的参数动态传入 => 相当于@RequestParam注解

@GetMapping("/all")
public List getAllDevelopment(@RequestParam("myURL") String myURL){
    return forestClient.selectAllDepartment(myURL);
}

@Request("${myURL}")
List selectAllDepartment(@DataVariable("myURL") String myURL);
/**
 * 通过参数转入的值值作为URL的一部分
 */
@Request("http://${myURL}/abc")
String send2(@DataVariable("myURL") String myURL);
(4) @Header注解

使用 @Header 注解将参数绑定到请求头上@Header 注解的 value 指为请求头的名称,参数值为请求头的值

如:@Header("Accept") String accept将字符串类型参数绑定到请求头 Accept 上

HEAD请求类型没有对应的@Head注解,只有@HeadRequest注解,原因是容易和@Header注解混淆

@GetMapping("/all")
public List getAllDevelopment(HttpServletRequest httpServletRequest){
    String accept = httpServletRequest.getHeader("Accept");
    String accessToken = httpServletRequest.getHeader("AccessToken");
    return forestClient.selectAllDepartment(accept,accessToken);
}
/**
 * 使用 @Header 注解将参数绑定到请求头上
 * @Header("Accept") String accept将字符串类型参数绑定到请求头 Accept 上 即:Accept = accept.value
 * @Header("AccessToken") String accessToken将字符串类型参数绑定到请求头accessToken上 即:accessToken = accessToken.value
 */
@Request("/all")
List selectAllDepartment(@Header("Accept") String accept, @Header("accessToken") String accessToken);

/**
 * 使用 @Header 注解可以修饰 Map 类型的参数
 * Map 的 Key 指为请求头的名称,Value 为请求头的值
 * 通过此方式,可以将 Map 中所有的键值对批量地绑定到请求头中
 */
@Post("http://localhost:8080/hello/user?username=foo")
void headHelloUser(@Header Map headerMap);


/**
 * 使用 @Header 注解可以修饰自定义类型的对象参数
 * 依据对象类的 Getter 和 Setter 的规则取出属性
 * 其属性名为 URL 请求头的名称,属性值为请求头的值
 * 以此方式,将一个对象中的所有属性批量地绑定到请求头中
 */
@Post("http://localhost:8080/hello/user?username=foo")
void headHelloUser(@Header MyHeaderInfo headersInfo);
(5)@Body注解

@Body注解:您可以使用@Body注解修饰参数的方式,将传入参数的数据绑定到 HTTP 请求体中。

/**
 * 默认body格式为 application/x-www-form-urlencoded,即以表单形式序列化数据
 */
@Post(
    url = "http://localhost:8080/user",
    headers = {"Accept:text/plain"}
)
ForestResponse save(@Body Development development);

除此之外还可以使用JSON格式,对象等

@Post(value = "/session/check-batch",timeout = 60000)
Result checkPickItemBatch(@Body User user);

请求体:
{
    "id":"123",
    "name":"zhangsan"
}
(6) @BaseRequest注解

@BaseRequest注解定义在接口类上,在@BaseRequest上定义的属性会被分配到该接口中每一个方法上,但方法上定义的请求属性会覆盖@BaseRequest上重复定义的内容。 因此可以认为@BaseRequest上定义的属性内容是所在接口中所有请求的默认属性。

/**
 * @BaseRequest 为配置接口层级请求信息的注解,其属性会成为该接口下所有请求的默认属性,但可以被方法上定义的属性所覆盖
 */
@BaseRequest(
    baseURL = "http://localhost:8080",     // 默认域名
    headers = {
        "Accept:text/plain"                // 默认请求头
    },
    sslProtocol = "TLS"                    // 默认单向SSL协议
)
public interface MyClient {
    // 方法的URL不必再写域名部分
    @Get("/hello/user")     
    String send1(@Query("username") String username);
    // 若方法的URL是完整包含http://开头的,那么会以方法的URL中域名为准,不会被接口层级中的baseURL属性覆盖
    @Get("http://www.xxx.com/hello/user")
    String send2(@Query("username") String username);
    @Get(
        url = "/hello/user",
        headers = {
            "Accept:application/json"      // 覆盖接口层级配置的请求头信息
        }
    )     
    String send3(@Query("username") String username);
}
(7)@Query的请求
public interface MyClient {

    @Request(
            url = "http://localhost:8080/hello/user",
            headers = "Accept: text/plain"
    )
    String sendRequest(@Query("uname") String username);
}

实际的url地址为:http://localhost:8080/hello/user?uname=username

/**
 * 使用 @Query 注解,可以直接将该注解修饰的参数动态绑定到请求url中
 * 注解的 value 值即代表它在url的Query部分的参数名
 */
@Get("http://localhost:8080/abc")
String send(@Query("a") String a, @Query("b") String b);

url:http://localhost:8080/abc?a=a&b=b


/**
 * 使用 @Query 注解,可以修饰 Map 类型的参数
 * 很自然的,Map 的 Key 将作为 URL 的参数名, Value 将作为 URL 的参数值
 * 这时候 @Query 注解不定义名称
 */
@Get("http://localhost:8080/abc")
String send1(@Query Map map);


/**
 * @Query 注解也可以修饰自定义类型的对象参数
 * 依据对象类的 Getter 和 Setter 的规则取出属性
 * 其属性名为 URL 参数名,属性值为 URL 参数值
 * 这时候 @Query 注解不定义名称
 */
@Get("http://localhost:8080/abc")
String send2(@Query UserInfo user);

则对应的url是:http://localhost:8080/abc?name=zhangsan&password=123456

数据转换
(1)序列化

Forest中对数据进行序列化可以通过指定contentType属性或Content-Type头指定内容格式。

@Request(
        url = "http://localhost:8080/hello/user",
        type = "post",
        contentType = "application/json"    // 指定contentType为application/json
)
String postJson(@Body MyUser user);   // 自动将user对象序列化为JSON格式

同理,指定为application/xml会将参数序列化为XML格式,text/plain则为文本,默认的application/x-www-form-urlencoded则为表格格式。

(2)反序列化

HTTP请求响应后返回结果的数据同样需要转换,Forest则会将返回结果自动转换为您通过方法返回类型指定对象类型。这个过程就是反序列化,您可以通过dataType指定返回数据的反序列化格式。

@Request(
    url = "http://localhost:8080/data",
    dataType = "json"        // 指定dataType为json,将按JSON格式反序列化数据
)
Map getData();               // 请求响应的结果将被转换为Map类型对象
Forest进阶
(1)单向认证

如果访问的目标站点的SSL证书由信任的Root CA发布的,无需做任何事情便可以自动信任

public interface Gitee {
    @Request(url = "https://gitee.com")
    String index();
}

Forest的单向验证的默认协议为SSLv3,如果一些站点的API不支持该协议,可以在全局配置中将ssl-protocol属性修改为其它协议,如:TLSv1.1, TLSv1.2, SSLv2等等。

forest.ssl-protocol=TLSv1.2

全局配置可以配置一个全局统一的SSL协议,但现实情况是有很多不同服务(尤其是第三方)的API会使用不同的SSL协议,这种情况需要针对不同的接口设置不同的SSL协议。

/**
 * 在某个请求接口上通过 sslProtocol 属性设置单向SSL协议
 */
@Get(
    url = "https://localhost:5555/hello/user",
    sslProtocol = "SSL"
)
ForestResponse truestSSLGet();
(2)双向认证

若是需要在Forest中进行双向验证的HTTPS请求,处理如下:

在全局配置中添加keystore配置:

forest:
 ...
 ssl-key-stores:
   - id: keystore1           # id为该keystore的名称,必填
     file: test.keystore     # 公钥文件地址
     keystore-pass: 123456   # keystore秘钥
     cert-pass: 123456       # cert秘钥
     protocols: SSLv3        # SSL协议

接着,在@Request中引入该keystoreid即可

@Request(
    url = "https://localhost:5555/hello/user",
    keyStore = "keystore1"
)
String send();

也可以在全局配置中配多个keystore

forest:
  ...
  ssl-key-stores:
    - id: keystore1          # 第一个keystore
      file: test1.keystore    
      keystore-pass: 123456  
      cert-pass: 123456      
      protocols: SSLv3       

    - id: keystore2          # 第二个keystore
      file: test2.keystore    
      keystore-pass: abcdef  
      cert-pass: abcdef      
      protocols: SSLv3       
      ...
异常处理

发送HTTP请求不会总是成功的,总会有失败的情况。Forest提供多种异常处理的方法来处理请求失败的过程

(1)try-catch方式
@Autowrite
private MyClient myClient;
/**
 * try-catch方式:捕获ForestNetworkException异常类的对象
 */
try {
    String result = myClient.send();
} catch (ForestNetworkException ex) {
    int status = ex.getStatusCode(); 				// 获取请求响应状态码
    ForestResponse response = ex.getResponse(); 	// 获取Response对象
    String content = response.getContent(); 		// 获取请求的响应内容
    String resResult = response.getResult(); 		// 获取方法返回类型对应的最终数据结果
}
(2)回调函数方式
/**
 * 在请求接口中定义OnError回调函数类型参数
 */
@Request(
        url = "http://localhost:8080/hello/user",
        headers = {"Accept:text/plain"},
        data = "username=${username}"
)
String send(@DataVariable("username") String username, OnError onError);

调用的代码如下

// 在调用接口时,在Lambda中处理错误结果
myClient.send("foo",  (exception, request, response) -> {
    int status = response.getStatusCode(); // 获取请求响应状态码
    String content = response.getContent(); // 获取请求的响应内容
    String result = response.getResult(); // 获取方法返回类型对应的最终数据结果
});
(3)ForestResponse

第三种,用ForestResponse类作为请求方法的返回值类型,示例代码如下:

/**
 * 用`ForestResponse`类作为请求方法的返回值类型, 其泛型参数代表实际返回数据的类型
 */
@Request(
        url = "http://localhost:8080/hello/user",
        headers = {"Accept:text/plain"},
        data = "username=${username}"
)
ForestResponse send(@DataVariable("username") String username);

调用和处理的过程如下

ForestResponse response = myClient.send("foo");
// 用isError方法判断请求是否失败, 比如404, 500等情况
if (response.isError()) {
    int status = response.getStatusCode(); // 获取请求响应状态码
    String content = response.getContent(); // 获取请求的响应内容
    String result = response.getResult(); // 获取方法返回类型对应的最终数据结果
}
文件上传
(1)上传:@DataFile注解
/**
 * 用@DataFile注解修饰要上传的参数对象
 * OnProgress参数为监听上传进度的回调函数
 */
@Post(url = "/upload")
Map upload(@DataFile("file") String filePath, OnProgress onProgress);

调用上传接口以及监听上传进度的代码如下:

Map result = myClient.upload("D:\\TestUpload\\xxx.jpg", progress -> {
    System.out.println("total bytes: " + progress.getTotalBytes());   // 文件大小
    System.out.println("current bytes: " + progress.getCurrentBytes());   // 已上传字节数
    System.out.println("progress: " + Math.round(progress.getRate() * 100) + "%");  // 已上传百分比
    if (progress.isDone()) {   // 是否上传完成
        System.out.println("--------   Upload Completed!   --------");
    }
});

在文件上传的接口定义中,除了可以使用字符串表示文件路径外,还可以用以下几种类型的对象表示要上传的文件:

/**
 * File类型对象
 */
@Post(url = "/upload")
Map upload(@DataFile("file") File file, OnProgress onProgress);

/**
 * byte数组
 * 使用byte数组和Inputstream对象时一定要定义fileName属性
 * "${1}"表示将方法的第二个参数filename的值替换到注解参数中的占位符"${1}"的位置上
 */
@Post(url = "/upload")
Map upload(@DataFile(value = "file", fileName = "${1}") byte[] bytes, String filename);

/**
 * Inputstream 对象
 * 使用byte数组和Inputstream对象时一定要定义fileName属性
 */
@Post(url = "/upload")
Map upload(@DataFile(value = "file", fileName = "${1}") InputStream in, String filename);

/**
 * Spring Web MVC 中的 MultipartFile 对象
 */
@PostRequest(url = "/upload")
Map upload(@DataFile(value = "file") MultipartFile multipartFile, OnProgress onProgress);

/**
 * Spring 的 Resource 对象
 */
@Post(url = "/upload")
Map upload(@DataFile(value = "file") Resource resource);
(2)多文件上传
/**
 * 上传Map包装的文件列表
 * 其中 ${_key} 代表Map中每一次迭代中的键值
 */
@PostRequest(url = "/upload")
ForestRequest uploadByteArrayMap(@DataFile(value = "file", fileName = "${_key}") Map byteArrayMap);

/**
 * 上传List包装的文件列表
 * 其中 ${_index} 代表每次迭代List的循环计数(从零开始计)
 */
@PostRequest(url = "/upload")
ForestRequest uploadByteArrayList(@DataFile(value = "file", fileName = "test-img-${_index}.jpg") List byteArrayList);

/**
 * 上传数组包装的文件列表
 * 其中 ${_index} 代表每次迭代List的循环计数(从零开始计)
 */
@PostRequest(url = "/upload")
ForestRequest uploadByteArrayArray(@DataFile(value = "file", fileName = "test-img-${_index}.jpg") byte[][] byteArrayArray);
(3)下载
/**
 * 在方法上加上@DownloadFile注解
 * dir属性表示文件下载到哪个目录
 * filename属性表示文件下载成功后以什么名字保存,如果不填,这默认从URL中取得文件名
 * OnProgress参数为监听上传进度的回调函数
 */
@Get(url = "http://localhost:8888/123.png")
//dir = "${0}"表示将方法的第一个参数dir的值替换到注解参数中的占位符"${0}"的位置上,
// 而filename = "${1}"表示将方法的第二个参数filename的值替换到注解参数中的占位符"${1}"的位置上
@DownloadFile(dir = "${0}", filename = "${1}")
File downloadFile(String dir, String filename, OnProgress onProgress);

调用下载接口以及监听上传进度的代码如下:

@Autowired
private ApiTestClient apiTestClient;

@GetMapping("/download")
public File download(){
    OnProgress onProgress = progress -> {
        System.out.println("total bytes: " + progress.getTotalBytes());   // 文件大小
        System.out.println("current bytes: " + progress.getCurrentBytes());   // 已下载字节数
        System.out.println("progress: " + Math.round(progress.getRate() * 100) + "%");  // 已下载百分比
        if (progress.isDone()) {   // 是否下载完成
            System.out.println("--------   Download Completed!   --------");
        }
    };
    //获取mac根目录
    String downLoadFile =  System.getProperty("user.home") + "/Desktop/";
    return apiTestClient.downloadFile(downLoadFile,"123.png",onProgress);
}

如果您不想将文件下载到硬盘上,而是直接在内存中读取,可以去掉@DownloadFile注解,并且用以下几种方式定义接口

/**
 * 返回类型用byte[],可将下载的文件转换成字节数组
 */
@GetRequest(url = "http://localhost:8080/images/test-img.jpg")
byte[] downloadImageToByteArray();

/**
 * 返回类型用InputStream,用流的方式读取文件内容
 */
@GetRequest(url = "http://localhost:8080/images/test-img.jpg")
InputStream downloadImageToInputStream();
Forest和Feign的区别?

Feign和Forest都是基于注解的声明式HTTP框架,但封装程度和api接口风格不太相同

比如:Feign没有封装SSL证书验证、连接池、正向代理等功能,需要用于手动写代码提供OkHttp或Httpclient等框架的Client对象,而Forest是尽可能封装完整,以形成统一的屏蔽层,所以不要改代码就可以通过配置或注解随意切换OkHttp或Httpclient的底层HTTP框架

轻量级HTTP客户端框架-RestTemplate

1定义

使用Springboot提供的RestTemplateBuilder构造类来构造一个RestTemplate,自定义一些连接参数

/**
 * 使用Springboot提供的RestTemplateBuilder构造类来构造一个RestTemplate,自定义一些连接参数
 * */
@Configuration
public class WebConfiguration {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder){
        return builder
                //设置连接超时时间(Duration.ofSeconds(5000) 创建了5000秒的持续时间对象)
                .setConnectTimeout(Duration.ofSeconds(5000))
                //设置读取超时时间
                .setReadTimeout(Duration.ofSeconds(5000))
                //设置认证信息
                .basicAuthentication("username","password")
                //设置根路径
                .rootUri("http://localhost:8081/provider/depart")
                //构建
                .build();
    }
}
2 RestTemplate API使用
(1) GET

发送GET请求的方法有两种

  • public T getForObject(...)

  • public ResponseEntity getForEntity(...)

getForEntity() 后缀带有Entity的方法都代表返回一个ResponseEntity,ResponseEntity是Spring对HTTP请求响应的封装,包括了几个重要的元素,如响应码,contentType、contentLength、响应消息体等

@AutoWrite
private RestTemplate restTemplate;

@GetMapping("/select/{id}")
public ResponseEntity getUserInfo(@PathVariable String id) {
  String url = "/select/"+id;
  //发送请求
  ResponseEntity forEntity = restTemplate.getForEntity(url, Department.class);
  //响应
  System.out.println("状态码:"+forEntity.getStatusCode());
  System.out.println("状态码内容:"+forEntity.getStatusCodeValue());
  HttpHeaders headers = forEntity.getHeaders();
  System.out.println("响应头:"+headers);
  Object body = forEntity.getBody();
  System.out.println("响应内容:"+body);
}

getForObject()

相比于前者getForEntity()该方法则是,更偏向于直接获取响应内容的,因为他直接返回响应实体的body(响应内容)

(2)POST

POST请求有如下三种方法

  • public URI postForLocation(...)

  • public T postForObject(...)

  • public ResponseEntity postForEntity(...)

postForEntity():该方法有三个参数

第一个为调用服务的地址(URL)

第二个参数表示上传的参数(json格式提交)

第三个表示返回响应内容的具体类型

postForObject()

使用方法与postForEntity()类似只是多了一个传入对象参数(传入方式与postForEntity()相同)

@GetMapping("/select/list")
public List selectDepartmentList() {
  String url = "/select/list";
  List forObject = restTemplate.getForObject(url, List.class);
  return (List)forObject;
}

postForLocation()

postForLocation传参用法与前两者一致,只不过返回从实体变成了一个URL,因此它不需要指定返回响应内容的类型。

 URI uri = restTemplate.postForLocation("https://httpbin.org/post", user);
(3)使用POST以表单方式提交

自己封装一个请求体,需要用到如下几个类

  • HttpHeaders

  • MultiValueMap

  • HttpEntity

HttpHeaders

故名思意,就是用来封装Http请求的请求头的,这里我们要设置他的ContentTypeMediaType.APPLICATION_FORM_URLENCODED以使得我们提交的参数是以Form(表单)的形式提交。

MultiValueMap

该类是用来封装请求参数的,是以key-value的形式封装但是以单个key对应多个value的格式传输(也就是是以单个key:[value...]的格式传输的)。

HttpEntity

该类是用来封装请求的,主要作用就是将请求头和请求体封装在一起成为一个请求实体 T用来指定用来封装参数的容器的类型。

@Test
void contextLoads() {
        //请求地址
        String url = "https://httpbin.org/post";
        //设置请求头, x-www-form-urlencoded格式的数据
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //提交参数设置
        MultiValueMap map = new LinkedMultiValueMap<>();
        map.add("name","鲁大师");
        //组装请求体
        HttpEntity> request = new HttpEntity<>(map, httpHeaders);
  
        //发送post请求并打印结果 以String类型接收响应结果JSON字符串
        String s = restTemplate.postForObject(url, request, String.class);
        System.out.println(s);
    }
(5)PUT()

使用方法与postForEntity()参数基本一致,只是put方法没有返回值(也就不必去设置响应内容的类型了)。

(6)delete()

delete()可以指定url中的中的参数,但是RestTemplatedelete()方法是不支持上传requestBody的。

**(7)optionsForAllow(url)

该方法的主要用来判断该服务地址,能够使用那种方法去执行

@Test
void contextLoads() {
  //请求地址
  String url = "http://httpbin.org/get";
  Set httpMethods = restTemplate.optionsForAllow(url);
  System.out.println(httpMethods);
}
(8)exchange()
  • ResponseEntity exchange()

该方法允许用户指定请求的方法(get,post,put等) 可以在请求中增加body以及头信息,其内容通过参数HttpEntity requestEntity描述 exchange支持’含参数的类型(即泛型)'作为返回类型,该特性通过ParameterizedTypeReferenceresponseType 描述

该方法支持五个参数

  • 第一个是服务地址

  • 第二个是请求方法

  • 第三个是写入的请求实体

  • 第四个是响应内容的类型

  • 第五个是扩展模板的变量或包含URI模板变量的映射

@Test
void contextLoads() {
    //请求地址
    String url = "http://httpbin.org/post";
    User user = new User();
    user.setName("彭于晏");
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    HttpEntity userHttpEntity = new HttpEntity<>(user, httpHeaders);
  
    ResponseEntity exchange = restTemplate.exchange(url, HttpMethod.POST, userHttpEntity, Object.class);
    System.out.println(exchange);
} 
  
(9)EXECUTE
  • T execute()

该方法就是执行请求的方法,我们可以发现上述的所有方法的最后执行都是调用的该方法执行,所以他在RestTemplate中十分重要

该方法有五个参数

  • 服务地址

  • 请求的方法

  • 准备请求的对象(requestCallback

  • 从响应中提取返回值的对象

  • 扩展模板的变量或包含URI模板变量的映射

@Override
	@Nullable
	public  T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,
			@Nullable ResponseExtractor responseExtractor, Object... uriVariables) throws RestClientException {

		URI expanded = getUriTemplateHandler().expand(url, uriVariables);
		return doExecute(expanded, method, requestCallback, responseExtractor);
	}

占位符
  • 当我们传入简单的对象如String,Integer时且路径中有嵌入的占位符时就会代替调用URL中占位符

@Test
void contextLoads() {
    //请求地址
    String url = "http://httpbin.org/{2}/get";
    HashMap map = new HashMap<>();
    Object forObject = restTemplate.getForObject(url, Object.class, 99);
    System.out.println(forObject);
}
===>
  http://httpbin.org/99/get

你可能感兴趣的:(http,网络协议,网络)