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博客