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

news2024/12/23 19:39:15

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

目录

1 项目初始化(实现 MVC)

① 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 类进行访问测试。

① Spring Boot 项目初始化

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

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

③ 导入 mybatis-plus 依赖

路径:pom.xml

        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>

④ 连接数据库配置

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

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

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

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

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

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

package com.visitwebdemo.pojo;

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @TableId(type = IdType.AUTO)//新增记录时未命名id时id自增
    private Long id;

    private String name;
    private  Integer age;
    private  String email;
}

1.2 编写 Dao层、service层和 controller层

① Dao 层的 Mapper 接口

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

package com.visitwebdemo.mapper;

//在对应的接口上面继承一个基本的接口 BaseMapper
@Mapper
public interface UserMapper extends BaseMapper<User> {
    //mybatisplus 将所有CRUD操作都编写完成了,不用像以前一样配置一大堆文件

}

在主启动类添加@MapperScan注解

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

package com.visitwebdemo;

@MapperScan("com.visitwebdemo.mapper")
@SpringBootApplication
public class VisitwebdemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(VisitwebdemoApplication.class, args);
    }
}

② Service层的 Iservice 接口和实现类

编写实体类对应的 UserBaseService 接口

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

package com.visitwebdemo.service;

//如有需要用以重写IService里的抽象方法,如不需要重写也可去掉该文件,将IService<User>写在UserServiceImpl文件
public interface UserBaseService extends IService<User> {

}

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

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

package com.visitwebdemo.service.impl;

@Service
public class UserServiceImpl  extends ServiceImpl<UserMapper, User> implements UserBaseService {

    @Autowired
    private UserMapper userMapper;

    /*
    Iservice CRUD(增删改查)
    */

    //增加一个User
    public boolean addUser(User user){
        return save(user);
    }

    //根据id删除一个User
    public boolean deleteUserById(int id){
        return removeById(id);
    }

    //更新User
    public boolean updateUser(User user){
        return updateById(user);
    }

    //根据id查询,返回一个User
    public User queryUser(int id){
        return getById(id);
    }

    //查询全部User,返回list集合
    public List<User> queryAllUser(){
        return list();
    }


    /*
    Mapper CRUD(增删改查)
    */

    //增加一个User
    public int addUser_ByMapper(User user){
        return userMapper.insert(user);
    }

    //根据id删除一个User
    public int deleteUserById_ByMapper(int id){
        return userMapper.deleteById(id);
    }

    //更新User
    public boolean updateUser_ByMapper(User user){
        userMapper.updateById(user);
        return true;
    }

    //根据id查询,返回一个User
    public User queryUser_ByMapper(int id){
        return userMapper.selectById(id);
    }

    //查询全部User,返回list集合
    public List<User> queryAllUser_ByMapper(){
        return userMapper.selectList(new QueryWrapper<>());//QueryWrapper没有任何条件
    }
}

③ 编写 controller 层的接口

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

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

package com.visitwebdemo.controller;

@Slf4j
@RestController
@RequestMapping("/web")
public class UserController {

    @Autowired
    private UserServiceImpl userService;
    
    @RequestMapping("/allUser")
    public List<User> allUser() {
        return userService.queryAllUser();
    }

    //@PathVariable路径参数
    @RequestMapping("/query/{userId}")
    public User queryUser(@PathVariable("userId") int id) {
        return userService.queryUser(id);
    }

    //绑定请求参数到实体类对象
    @RequestMapping("/body")
    public boolean updateUser(User user) {
        return userService.updateUser(user);
    }
    
}

以上准备工作就完成了~

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

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

构造含有变量值的 URI

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

③ 构造指向 Controller 的 URI

URI uri = MvcUriComponentsBuilder
        .fromMethodCall(MvcUriComponentsBuilder.on(UserController.class).allUser())
        .build()
        .toUri();

④ 获取当前请求的URI

URI uri = ServletUriComponentsBuilder
        .fromCurrentRequest()
        .build()
        .toUri();

2.3  RestTemplate 代码实现

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

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

① getForObject() / getForEntity()

//new 一个RestTemplate ,后面也会用到
RestTemplate restTemplate = new RestTemplate();

@Test
public void queryOneUser(){
    //构建 uri
    URI uri = UriComponentsBuilder
            .fromUriString("http://localhost:8080/web/query/{userId}")
            .build(1);
    //执行rest请求,ResponseEntity封装了返回信息,若将getForEntity 替换成 getForObject,则不需要 ResponseEntity
    ResponseEntity<User> user = restTemplate.getForEntity(uri,User.class);
    //打印返回信息
    System.out.printf("Response Status: {%s}"+"\n"+"Response Headers: {%s}"+"\n", user.getStatusCode(), user.getHeaders().toString());
    System.out.printf("Users: {%s}", user.getBody());
}

通过RestTemplate 查询成功 👇

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

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

@Test
public void updateUser11(){
    //请求地址
    String url = "http://localhost:8080/web/body";

    // 请求头设置,x-www-form-urlencoded格式的数据
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

    //提交参数设置
    MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
    map.add("id", 2L);
    map.add("name", "jack");
    map.add("age", 16);
    map.add("email", "yinyu@baomidou.com");

    // 组装请求体
    HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(map, headers);

    // 发送post请求,并打印结果,以String类型接收响应结果JSON字符串
    String result = restTemplate.postForObject(url, request, String.class);
    System.out.println(result);
}

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

数据表更新成功 👇

③ exchange 实现泛型

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

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

返回成功👇

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 相关内容~

//创建一个 webClient
WebClient webClient = WebClient.create("http://localhost:8080");

@Test
public void queryOneUser(){
    Mono<User> mono = webClient.get()//创建一个get请求
            .uri("/web/query/1/") //也可写成 uri("/web/query/{userId}",1)
            .retrieve() // 获取结果 可以用exchange代替  返回的上一个 User
            .bodyToMono(User.class);//处理单个对象
    System.out.println(mono.block());
}

查询成功 👇

② get --  返回 user 列表

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

查询成功 👇

③ post

@Test
public void updateUser(){
    MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
                map.add("id", 2L);
                map.add("name", "jack");
                map.add("age", 18);
                map.add("email", "yinyu@baomidou.com");

    Mono<Boolean> mono = webClient.post()//创建一个get请求
            .uri("/web/body")
            .body(BodyInserters.fromValue(map))
            .retrieve() // 获取结果 可以用exchange代替  返回的上一个 User 的list
            .bodyToMono(Boolean.class);//处理多个对象 即多组数据
    System.out.println(mono.block());
}

未执行前:

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

控制台输出:


参考文章

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/59178.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android 使用元数据

Android 使用元数据 前提介绍Metadata 有时候为安全起见&#xff0c;某个参数要给某个活动专用&#xff0c;并不希望其他活动也能获取该参数&#xff0c;也就是要使用第三方SDK时。Activity提供了元数据&#xff08;Metadata&#xff09;的概念&#xff0c;元数据是一种描述其…

C++类和对象(二)构造函数、析构函数、拷贝构造函数

目录 1.类的6个默认成员函数 2. 构造函数 2.1 概念 2.2 特性 3.析构函数 3.1 概念 3.2 特性 4. 拷贝构造函数 4.1 概念 4.2 特征 1.类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;…

【菜菜的sklearn课堂笔记】聚类算法Kmeans-聚类算法的模型评估指标

视频作者&#xff1a;菜菜TsaiTsai 链接&#xff1a;【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili 可以只看轮廓系数和卡林斯基-哈拉巴斯指数 不同于分类模型和回归&#xff0c;聚类算法的模型评估不是一件简单的事。在分类中&#xff0c;有直接结…

【尚硅谷】Java数据结构与算法笔记02 - 队列

文章目录一、使用场景二、队列介绍三、数组模拟队列3.1 思路分析3.2 Java代码实现3.3 问题分析与优化四、数组模拟环形队列4.1 思路分析4.2 Java代码实现一、使用场景 银行排队&#xff0c;先到先得测核酸&#xff0c;先到先测 二、队列介绍 队列是一个有序列表, 可以用数组…

硬盘压缩将C盘拓展成D盘和E盘

硬盘压缩将C盘拓展成D盘和E盘1. 现状2. 硬盘压缩2.1 进入计算机管理2.2 磁盘管理压缩卷3. 分配新盘符3.1 查看盘符是否被占用3.2 新建D盘刚安装好系统的电脑有可能只有一个C盘&#xff0c;我们工作学习的时候远远不够&#xff0c;那怎么拓展其他盘符呢&#xff1f; 接下来让我们…

PyQt5基础练习1

0. 本文学习地址 1. PyQt5是由一系列Python模块组成 超过620个类&#xff0c;6000函数和方法。能在诸如Unix、Windows和Mac OS等主流操作系统上运行。 1.1 PyQt5有两种证书 GPL商业证书 2. 实验1 实现简单的窗体 2.1 完整代码 #!/usr/bin/python3 # -*- coding: utf-8 -*…

专业尖端远心光学,高精度视觉检测解决者

随着机器视觉系统在精密检测领域的广泛应用&#xff0c;在精密光学测量系统中&#xff0c;由于普通光学镜头会存在一定的制约因素&#xff0c;如影像的变形、视角选择而造成的误差、不适当光源干扰下造成边界的不确定性等问题&#xff0c;进而影响测量的精度。为弥补普通镜头应…

155. RESTframe的请求和响应

1.请求和响应 REST framework引入了2个新的对象&#xff1a;Request和Response 1.1 Request 包结构&#xff1a;rest_framework.request.Request 该对象扩展了常规的HttpRequest &#xff0c;增加了对REST框架灵活的请求解析和请求认证的支持 主要属性&#xff1a; data 这个…

基于PHP+MySQL毕业生档案管理系统

毕业生档案管理系统是信息时代的产物&#xff0c;它是学校档案管理部门的一个好帮手。有了它不再需要繁重的纸质登记&#xff0c;有了它档案管理员不在需要繁重的工作&#xff0c;一些成绩信息和奖惩等基本信息可以由管理人员及时的对信息进行查询、更新、修改和删除&#xff0…

SpringBoot_启动原理分析

一共分为三部分来解析: 一 依赖导入原理 二 springboot 包扫描原理三 springboot自动配置原理一 依赖导入原理 父项目进行版本控制 ctrl 点击spring-boot-starter-parent 进入 继续点击,进入spring-boot-dependencies 这里管理着springboot中所有依赖的版本,版本…

38 | Linux 磁盘空间异常爆满

1 场景 收到告警 找到对应的服务器&#xff1a;df -hl 要找到导致磁盘空间满的目录或文件。 2 找占用空间大的目录或文件 2.1方式一 在根目录下&#xff0c;通过du -hs命令&#xff0c;列出各目录所占空间大小 命令&#xff1a;du -hs * 之后再用同样的方法继续到对应目…

[附源码]计算机毕业设计springboot医学图像管理平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

EXSI-NFS实验

A-EXSI-NFS实验 2022年3月25日 8:20 iptables -F iptables-save systemctl stop firewalld #setenforce [0|1]命令修改SELinux当前的运行模式&#xff08;0为禁用&#xff0c;1为启用&#xff09; getenforce Enforcing setenforce 0 getenforce Permissive NFS 两台CentOS 7即…

【车载开发系列】UDS诊断---读取内存($0x23)

【车载开发系列】UDS诊断—读取内存&#xff08;$0x23&#xff09; UDS诊断---读取内存&#xff08;$0x23&#xff09;【车载开发系列】UDS诊断---读取内存&#xff08;$0x23&#xff09;一.概念定义二.注意事项三.报文格式1&#xff09;报文请求2&#xff09;肯定响应3&#x…

一、Node.js 环境安装 (详)

1. 下载Node.js 首先进入node.js官网&#xff0c;选择下载这一项&#xff0c;此时映入眼帘的可以看到有两项LTS(长期维护版本)和Current(最新的版本)&#xff0c;一般在开发会选择左边进行下载安装&#xff0c;具稳定性以及有长期维护。那么下面演示的是64位的Windows操作系统&…

PCI bar 解析

只要是接入系统的 pci 设备就需要和系统软件进行交互&#xff0c;设备和系统之间的交流主要包含以下两部分&#xff1a; 1&#xff0c;系统要能访问到设备的寄存器 用于控制设备行为&#xff0c;包括DMA&#xff0c;数据收发等&#xff1b;设备通过寄存器报告自身的状态&…

Nginx部署vue项目和配置代理

Nginx部署vue项目和配置代理目录概述需求&#xff1a;实现思路分析1.一般前后端分离的项目需要进行跨域2.微服务代理3.vuenginx实现服务端跨域4.网页解析器参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&am…

【问题解决】Android JDK版本不匹配导致崩溃踩坑记录

【问题解决】Android JDK版本不匹配导致崩溃踩坑记录部分机型反馈崩溃问题谷歌回复与解决方案Android打包脱糖操作对比与排查总结前几天同事遇到一个非常诡异的报错&#xff0c;紧急处理后&#xff0c;趁着周末仔细研究了一下原因&#xff0c;觉得还挺有意思的&#xff0c;所以…

制作一个谷歌浏览器插件,实现网页数据爬虫

一、什么是浏览器插件 浏览器插件&#xff0c;基于浏览器的原有功能&#xff0c;另外增加新功能的工具&#xff0c;是可定制浏览体验的小型软件程序&#xff0c;让用户可以根据个人需要或偏好来定制浏览器。 如拦截网页中的广告、划词翻译、倍速视频等等。 Chrome、edge等浏…

WEB前端网页设计 网页代码参数(背景、图片)类

目录 设置圆角 旋转属性&#xff1a; box-sizing属性&#xff1a; 设置背景图像固定background-attachment 设置多重背景图像 鼠标光标形状&#xff1a;cursor ”图片背景“ background-size 背景图片的大小 背景图像的位置 px 无序列表 &#xff1a; 标签 项目符…