• 【Java开发】 Spring 08 :访问 Web 资源( 借助 RestTemplate or WebClient )


    web 资源就是运行在服务器上的资源,比如放到 web 下的页面  js 文件、图片、css等,web资源分为静态web资源和动态web资源两类,接下来访问的就是动态资源(页面返回的数据是动态的,由后端程序产生),本文主要借助 RestTemplate 和 WebClient 两个工具。

    目录

    1 项目初始化(实现 MVC)

    1.1 Spring Boot 项目初始化

    ① 添加 Spring Web(最关键)等依赖

    ② 导入 mybatis-plus 依赖

    ③ 连接数据库配置

    ④ 编写数据库对应的实体类

    1.2 编写 Dao层、service层和 controller层

    ① Dao 层的 Mapper 接口

    ② Service层的 Iservice 接口和实现类

    ③ 编写 controller 层的接口

    2 通过 RestTemplate 访问

    2.1 常用请求方法

    2.2  URI 的构造

    ① 普通构造 URI

    ② 构造含有变量值的 URI

    ③ 构造指向 Controller 的 URI

    2.3  RestTemplate 代码实现

    ① getForObject() / getForEntity()

    ② postForObject() /postForEntity()—HTTP请求

    ③ exchange 实现泛型

    3 通过 WebClient 访问

    3.1 基本用法

    2.3  WebClient 代码实现

    ① get --  返回 user

    ② get --  返回 user 列表

    ③ post


    项目源码:尹煜 / visitwebdemo · GitCode

    1 项目初始化(实现 MVC)

    因为文章尽可能想写的详尽基础一些,所以内容可能会有点多,熟练者可直接看2、3章内容

    因为访问 Web 资源的前提是存在 Web 资源可供访问,因此本文的逻辑是在本地创建一个 Web 环境(写 controller),然后由 test 类进行访问测试。

    1.1 Spring Boot 项目初始化

    ① 添加 Spring Web(最关键)等依赖

    Spring Boot 版本是 2.7.6 ,建议将版本控制在 2-3 之间,超出范围的话会容易产生兼容问题

    ② 导入 mybatis-plus 依赖

    路径:pom.xml

    1. com.baomidou
    2. mybatis-plus-boot-starter
    3. 3.5.2

    ③ 连接数据库配置

    前提是连接的数据库存在与实体类相对应的数据表,数据表初始搭建详解在Spring MVC 实践详解文章的【2/2.1Mysql 数据库初始化】小节

    路径:src/main/resources/application.properties

    1. #数据库连接配置
    2. spring.datasource.username=root
    3. spring.datasource.password=root
    4. #mysql5~8 驱动不同driver-class-name 8需要增加时区的配置serverTimezone=UTC,放在url最后
    5. #useSSL=false 安全连接
    6. spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    7. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

    ④ 编写数据库对应的实体类

    使用 lombok 和 mybatisplus 的实体类注释,加大开发效率

    路径:src/main/java/com/visitwebdemo/pojo/User.java

    1. package com.visitwebdemo.pojo;
    2. @Builder
    3. @Data
    4. @AllArgsConstructor
    5. @NoArgsConstructor
    6. public class User {
    7. @TableId(type = IdType.AUTO)//新增记录时未命名id时id自增
    8. private Long id;
    9. private String name;
    10. private Integer age;
    11. private String email;
    12. }

    1.2 编写 Dao层、service层和 controller层

    ① Dao 层的 Mapper 接口

    路径:src/main/java/com/visitwebdemo/mapper/UserMapper.java

    1. package com.visitwebdemo.mapper;
    2. //在对应的接口上面继承一个基本的接口 BaseMapper
    3. @Mapper
    4. public interface UserMapper extends BaseMapper {
    5. //mybatisplus 将所有CRUD操作都编写完成了,不用像以前一样配置一大堆文件
    6. }

    在主启动类添加@MapperScan注解

    路径:src/main/java/com/visitwebdemo/VisitwebdemoApplication.java

    1. package com.visitwebdemo;
    2. @MapperScan("com.visitwebdemo.mapper")
    3. @SpringBootApplication
    4. public class VisitwebdemoApplication {
    5. public static void main(String[] args) {
    6. SpringApplication.run(VisitwebdemoApplication.class, args);
    7. }
    8. }

    ② Service层的 Iservice 接口和实现类

    编写实体类对应的 UserBaseService 接口

    路径:src/main/java/com/visitwebdemo/service/UserBaseService.java

    1. package com.visitwebdemo.service;
    2. //如有需要用以重写IService里的抽象方法,如不需要重写也可去掉该文件,将IService写在UserServiceImpl文件
    3. public interface UserBaseService extends IService {
    4. }

    编写 Service 层的实现类,以下就是具体的增删改查操作 👇

    路径:src/main/java/com/visitwebdemo/service/impl/UserServiceImpl.java

    1. package com.visitwebdemo.service.impl;
    2. @Service
    3. public class UserServiceImpl extends ServiceImpl implements UserBaseService {
    4. @Autowired
    5. private UserMapper userMapper;
    6. /*
    7. Iservice CRUD(增删改查)
    8. */
    9. //增加一个User
    10. public boolean addUser(User user){
    11. return save(user);
    12. }
    13. //根据id删除一个User
    14. public boolean deleteUserById(int id){
    15. return removeById(id);
    16. }
    17. //更新User
    18. public boolean updateUser(User user){
    19. return updateById(user);
    20. }
    21. //根据id查询,返回一个User
    22. public User queryUser(int id){
    23. return getById(id);
    24. }
    25. //查询全部User,返回list集合
    26. public List queryAllUser(){
    27. return list();
    28. }
    29. /*
    30. Mapper CRUD(增删改查)
    31. */
    32. //增加一个User
    33. public int addUser_ByMapper(User user){
    34. return userMapper.insert(user);
    35. }
    36. //根据id删除一个User
    37. public int deleteUserById_ByMapper(int id){
    38. return userMapper.deleteById(id);
    39. }
    40. //更新User
    41. public boolean updateUser_ByMapper(User user){
    42. userMapper.updateById(user);
    43. return true;
    44. }
    45. //根据id查询,返回一个User
    46. public User queryUser_ByMapper(int id){
    47. return userMapper.selectById(id);
    48. }
    49. //查询全部User,返回list集合
    50. public List queryAllUser_ByMapper(){
    51. return userMapper.selectList(new QueryWrapper<>());//QueryWrapper没有任何条件
    52. }
    53. }

    ③ 编写 controller 层的接口

    写了三个具有代表性的接口 👇

    路径:src/main/java/com/visitwebdemo/controller/UserController.java

    1. package com.visitwebdemo.controller;
    2. @Slf4j
    3. @RestController
    4. @RequestMapping("/web")
    5. public class UserController {
    6. @Autowired
    7. private UserServiceImpl userService;
    8. @RequestMapping("/allUser")
    9. public List allUser() {
    10. return userService.queryAllUser();
    11. }
    12. //@PathVariable路径参数
    13. @RequestMapping("/query/{userId}")
    14. public User queryUser(@PathVariable("userId") int id) {
    15. return userService.queryUser(id);
    16. }
    17. //绑定请求参数到实体类对象
    18. @RequestMapping("/body")
    19. public boolean updateUser(User user) {
    20. return userService.updateUser(user);
    21. }
    22. }

    以上准备工作就完成了~

    2 通过 RestTemplate 访问

    RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,它提供了很多可以方便访问远程 http 服务的方法,这些方法可以帮助开发人员减少编写客户端代码的工作量。

    2.1 常用请求方法

    其实最主要还是 Get 和 Post 请求:

    • GET请求:getForObject() / getForEntity()
    • POST请求:postForObject() /postForEntity()
    • PUT请求:put()
    • DELETE请求:delete()

    xxxForObject() 和 xxxForEntity()  二者区别主要在于:xxxForObject() 的返回值是HTTP协议的响应体;而 xxxForEntity()  返回的是 ResponseEntity(ResponseEntity是对HTTP响应的封装),除了包含响应体,还包含HTTP状态码、contentType、contentLength、Header等信息。

    2.2  URI 的构造

    发送请求需要携带 URI 👇,以下是几个常见的构造方式,UriComponentsBuilder 最为常用

    ① 普通构造 URI

    1. URI uri = UriComponentsBuilder
    2. .fromUriString("http://localhost:8080/web/query")
    3. .build()
    4. .toUri();

    构造含有变量值的 URI

    1. URI uri = UriComponentsBuilder
    2. .fromUriString("http://localhost:8080/web/query/{userId}")
    3. .build(1);

    ③ 构造指向 Controller 的 URI

    1. URI uri = MvcUriComponentsBuilder
    2. .fromMethodCall(MvcUriComponentsBuilder.on(UserController.class).allUser())
    3. .build()
    4. .toUri();

    ④ 获取当前请求的URI

    1. URI uri = ServletUriComponentsBuilder
    2. .fromCurrentRequest()
    3. .build()
    4. .toUri();

    2.3  RestTemplate 代码实现

    注意由于是请求本地项目的 web 资源,因此需要在先启动项目 👇,然后再对测试类进行测试

    路径均在:src/test/java/com/visitwebdemo/restemplateTests.java

    ① getForObject() / getForEntity()

    1. //new 一个RestTemplate ,后面也会用到
    2. RestTemplate restTemplate = new RestTemplate();
    3. @Test
    4. public void queryOneUser(){
    5. //构建 uri
    6. URI uri = UriComponentsBuilder
    7. .fromUriString("http://localhost:8080/web/query/{userId}")
    8. .build(1);
    9. //执行rest请求,ResponseEntity封装了返回信息,若将getForEntity 替换成 getForObject,则不需要 ResponseEntity
    10. ResponseEntity user = restTemplate.getForEntity(uri,User.class);
    11. //打印返回信息
    12. System.out.printf("Response Status: {%s}"+"\n"+"Response Headers: {%s}"+"\n", user.getStatusCode(), user.getHeaders().toString());
    13. System.out.printf("Users: {%s}", user.getBody());
    14. }

    通过RestTemplate 查询成功 👇

    ② postForObject() /postForEntity()—HTTP请求

    HTTP 请求方式更为常见,同时也更为稳定,本质上来说是模拟 HTTP 请求的形式,将请求信息最后封装在 HttpEntity

    1. @Test
    2. public void updateUser11(){
    3. //请求地址
    4. String url = "http://localhost:8080/web/body";
    5. // 请求头设置,x-www-form-urlencoded格式的数据
    6. HttpHeaders headers = new HttpHeaders();
    7. headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    8. //提交参数设置
    9. MultiValueMap map = new LinkedMultiValueMap<>();
    10. map.add("id", 2L);
    11. map.add("name", "jack");
    12. map.add("age", 16);
    13. map.add("email", "yinyu@baomidou.com");
    14. // 组装请求体
    15. HttpEntity> request = new HttpEntity<>(map, headers);
    16. // 发送post请求,并打印结果,以String类型接收响应结果JSON字符串
    17. String result = restTemplate.postForObject(url, request, String.class);
    18. System.out.println(result);
    19. }

    post 请求成功 👇,由于没用 postForEntity + ResponseEntity,所以直接输出内容

    数据表更新成功 👇

    ③ exchange 实现泛型

    主要是用到了 exchange + ParameterizedTypeReference,最后返回 User 列表

    1. @Test
    2. public void queryAllUser(){
    3. //构建 uri
    4. URI uri = UriComponentsBuilder.fromUriString("http://localhost:8080/web/allUser").build().toUri();
    5. //解析泛型对象
    6. ParameterizedTypeReference> ptr = new ParameterizedTypeReference>() {};
    7. ResponseEntity> userlist = restTemplate.exchange(uri, HttpMethod.GET,null,ptr);
    8. //打印返回信息
    9. System.out.printf("Response Status: {%s}"+"\n"+"Response Headers: {%s}"+"\n", userlist.getStatusCode(), userlist.getHeaders().toString());
    10. System.out.printf("Users: {%s}", userlist.getBody());
    11. }

    返回成功👇

    3 通过 WebClient 访问

    WebClient 是从 Spring WebFlux 5.0 版本开始提供的一个非阻塞的基于响应式编程的进行 Http 请求的客户端工具。它的响应式编程的基于 Reactor 的。WebClient 中提供了标准Http请求方式对应的 get、post、put、delete 等方法,可以用来发起相应的请求。

    关于 Reactor 的相关内容-> Spring 05 :Project Reactor 响应式流框架

    3.1 基本用法

    Ⅰ 创建 WebClient

    • WebClient.create()

    • WebClient.builder()

    Ⅱ 发起请求

    • get() / post() / put() / delete() / patch()

    Ⅲ 获得结果

    • retrieve() / exchange()

    Ⅳ 处理 HTTP Status

    • onStatus()

    Ⅴ 应答正文

    • bodyToMono() / bodyToFlux()

    2.3  WebClient 代码实现

    还是一样,需要在先启动项目 👇,然后再对测试类进行测试

    路径均在:src/test/java/com/visitwebdemo/webclientTests.java

    ① get --  返回 user

    返回的是 Mono 封装的 User ,然后对他做进一步处理,这是 Reactor 相关内容~

    1. //创建一个 webClient
    2. WebClient webClient = WebClient.create("http://localhost:8080");
    3. @Test
    4. public void queryOneUser(){
    5. Mono mono = webClient.get()//创建一个get请求
    6. .uri("/web/query/1/") //也可写成 uri("/web/query/{userId}",1)
    7. .retrieve() // 获取结果 可以用exchange代替 返回的上一个 User
    8. .bodyToMono(User.class);//处理单个对象
    9. System.out.println(mono.block());
    10. }

    查询成功 👇

    ② get --  返回 user 列表

    1. @Test
    2. public void queryAllUser(){
    3. Flux flux = webClient.get()//创建一个get请求
    4. .uri("/web/allUser/")
    5. .retrieve() // 获取结果 可以用exchange代替 返回的上一个 User 的list
    6. .bodyToFlux(User.class);//处理多个对象 即多组数据
    7. flux.toStream().forEach(System.out::println);
    8. }

    查询成功 👇

    ③ post

    1. @Test
    2. public void updateUser(){
    3. MultiValueMap map = new LinkedMultiValueMap<>();
    4. map.add("id", 2L);
    5. map.add("name", "jack");
    6. map.add("age", 18);
    7. map.add("email", "yinyu@baomidou.com");
    8. Mono mono = webClient.post()//创建一个get请求
    9. .uri("/web/body")
    10. .body(BodyInserters.fromValue(map))
    11. .retrieve() // 获取结果 可以用exchange代替 返回的上一个 User 的list
    12. .bodyToMono(Boolean.class);//处理多个对象 即多组数据
    13. System.out.println(mono.block());
    14. }

    未执行前:

    执行后,可以看到 age 变更 👇 ,说明执行 post 请求成功

    控制台输出:


    参考文章

    Web资源_你啊我啊你好的博客-CSDN博客_web资源

    通过 RestTemplate 访问 Web 资源_L# S@的博客-CSDN博客

  • 相关阅读:
    哪些人适合学习Python?
    Web前端大作业:基于bootstrap响应式页面,家具装修公司网站
    Leetcode29:两数相除
    软件测试笔试题1
    某汽车金融企业:搭建SDLC安全体系,打造智慧金融服务样本
    一百八十、Linux——服务器时间比实际时间快2分钟
    [国产MCU]-W801开发实例-用户报文协议(UDP)数据接收和发送
    什么是自我接纳?如何提高自我接纳度?
    第05、WireShark抓包-协议分析
    获得淘宝商品快递费用接口调用展示
  • 原文地址:https://blog.csdn.net/weixin_51407397/article/details/128155887