HttpExchange是SpringBoot3的新特性.
Spring Boot3 提供了新的 HTTP 的访问能力,封装了Http底层细节. 通过接口简化 HTTP远程访问,类似 Feign 功能。
SpringBoot 中定义接口提供 HTTP 服务 --> 框架生成的代理对象实现此接口 --> 框架生成的代理对象实现 HTTP 的远程访问。
1.1.1 WebClient
- 非阻塞. 阻塞和非阻塞针对被调度者,被调度者收到请求后,做完请求任务之后才给出反馈就是阻塞,收到请求之后马上给
出反馈然后去做事情,就是非阻塞 - 异步请求. 异步和同步针对调度者,调用者发送请求,如果等待对方回应之后才去做其他事情,就是同步,如果发送请求之后不
等着对方回应就去做其他事情就是异步 - 它的响应式编程的基于 Reactor
1.1.2 Http接口的参数列表和返回值
作为 HTTP 服务接口中的方法允许使用的参数列表
作为 HTTP 服务接口中的方法一般可选的返回值
- void、Mono:执行请求并丢弃响应内容。
- HttpHeaders、Mono: 执行请求,丢弃响应体,返回响应头。
- 、Mono:执行请求,并将响应体解码为所声明的类型。
- 、Flux:执行请求,并将响应体解码为所声明类型的数据流。
- ResponseEntity、Mono<ResponseEntity>:执行请求,丢弃响应体,并返回一个包含状态和响应头的
ResponseEntity。 - ResponseEntity、Mono<ResponseEntity>:执行请求,并返回一个包含状态、响应头和解码后的响应体 ResponseEntity。
Mono<ResponseEntity<Flux>:执行请求,并返回一个包含状态、响应头和解码后的响应体 ResponseEntity。
1.2 实例
1.2.1
安装Gsonformat
使用方式: 建好实体类以后, 在类中右键generate - Gsonformat , 然后复制JSON进去即可
1.2.2 需求
需求:
访问 https://jsonplaceholder.typicode.com/ 提供的 todos 服务。
并基于 RESTful 风格,添加新的 todo,修改 todo 中的 title,查询某个 todo。
简单来说, 以往都是我们的电脑充当服务器, 自己编写后端代码, 然后自己在网页模拟发送请求来调用后端服务.
现在我们直接使用在后端中发送请求, 远程调用别人的服务(CRUD数据), 由他人提供服务器.
一个最大的区别就是将解析地址的操作搬到了service层
直接在浏览器中访问该网址, 可以看到里面有许多JSON数据, 每一个都是一个todo, 现在的目标就是操作这些todo.
1.2.3 添加依赖
多添加一个依赖Reactive Web, 以使用WebClient(HttpExchange就封装了WebClient)
1.2.4 实体类
package com.sunsplanter.httpserivce.pojo;import lombok.Data;/*** 根据 https://jsonplaceholder.typicode.com/todos/1 的结构创建的*/
@Data
public class Todo {private Integer userId;private int id;private String title;private boolean completed;}
1.2.5 声明服务接口
//将controller层的工作搬到了服务层
public interface TodoService {//一个方法就是一个远程服务(远程调用)@GetExchange("/todos/{id}")Todo getTodoById(@PathVariable Integer id);@PostExchange(value = "/todos",accept = MediaType.APPLICATION_JSON_VALUE)Todo createTodo(@RequestBody Todo newTodo);@PutExchange("/todos/{id}")ResponseEntity<Todo> modifyTodo(@PathVariable Integer id,@RequestBody Todotodo);@PatchExchange("/todos/{id}")HttpHeaders pathRequest(@PathVariable Integer id, @RequestParam String title);@DeleteExchange("/todos/{id}")void removeTodo(@PathVariable Integer id);
}
1.2.6 创建 HTTP 服务代理对象
package com.sunsplanter.httpserivce.config;@Configuration(proxyBeanMethods = false)
public class HTTPConfig {//每个实体类都要创建一个代理对象@Beanpublic TodoService requestService(){//创建服务接口的代理对象,基于WebClientWebClient webClient =WebClient.builder().baseUrl("https://jsonplaceholder.typicode.com/").build();HttpServiceProxyFactory proxyFactory =HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient)).build();return proxyFactory.createClient(TodoService.class);}
}
1.2.7 单元测试
package com.sunsplanter.httpserivce;@SpringBootTest
class HttpServiceApplicationTests {@Resourceprivate TodoService requestService;@Testvoid testQuery() {Todo todo = requestService.getTodoById(1);System.out.println("todo = " + todo);}@Testvoid testCreateTodo() {Todo todo = new Todo();todo.setId(1001);todo.setCompleted(true);todo.setTitle("录制视频");todo.setUserId(5001);Todo save = requestService.createTodo(todo);System.out.println(save);}@Testvoid testModifyTitle() {
//org.springframework.http.HttpHeadersHttpHeaders entries = requestService.pathRequest(5, "homework");entries.forEach((name, vals) -> {System.out.println(name);vals.forEach(System.out::println);System.out.println("=========================");});}@Testvoid testModifyTodo() {Todo todo = new Todo();todo.setCompleted(true);todo.setTitle("录制视频!!!");todo.setUserId(5002);ResponseEntity<Todo> result = requestService.modifyTodo(2, todo);HttpStatusCode statusCode = result.getStatusCode();HttpHeaders headers = result.getHeaders();Todo modifyTodo = result.getBody();System.out.println("statusCode = " + statusCode);System.out.println("headers = " + headers);System.out.println("modifyTodo = " + modifyTodo);}@Testvoid testRemove() {requestService.removeTodo(2);}
}
但是,没有搞太清楚原理.
例如: 为什么在接口中是用Get方法?为什么是路径传参?是https://jsonplaceholder.typicode.com/todos那边规定的吗?
尝试更改为param传参失败.
@GetExchange("/todos/{id}")Todo getTodoById(@PathVariable Integer id);