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
因为文章尽可能想写的详尽基础一些,所以内容可能会有点多,熟练者可直接看2、3章内容
因为访问 Web 资源的前提是存在 Web 资源可供访问,因此本文的逻辑是在本地创建一个 Web 环境(写 controller),然后由 test 类进行访问测试。
Spring Boot 版本是 2.7.6 ,建议将版本控制在 2-3 之间,超出范围的话会容易产生兼容问题
路径:pom.xml
com.baomidou mybatis-plus-boot-starter 3.5.2
前提是连接的数据库存在与实体类相对应的数据表,数据表初始搭建详解在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;
}
路径:src/main/java/com/visitwebdemo/mapper/UserMapper.java
package com.visitwebdemo.mapper;//在对应的接口上面继承一个基本的接口 BaseMapper
@Mapper
public interface UserMapper extends BaseMapper {//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);}
}
编写实体类对应的 UserBaseService 接口
路径:src/main/java/com/visitwebdemo/service/UserBaseService.java
package com.visitwebdemo.service;//如有需要用以重写IService里的抽象方法,如不需要重写也可去掉该文件,将IService写在UserServiceImpl文件
public interface UserBaseService extends IService {}
编写 Service 层的实现类,以下就是具体的增删改查操作 👇
路径:src/main/java/com/visitwebdemo/service/impl/UserServiceImpl.java
package com.visitwebdemo.service.impl;@Service
public class UserServiceImpl extends ServiceImpl implements UserBaseService {@Autowiredprivate UserMapper userMapper;/*Iservice CRUD(增删改查)*///增加一个Userpublic boolean addUser(User user){return save(user);}//根据id删除一个Userpublic boolean deleteUserById(int id){return removeById(id);}//更新Userpublic boolean updateUser(User user){return updateById(user);}//根据id查询,返回一个Userpublic User queryUser(int id){return getById(id);}//查询全部User,返回list集合public List queryAllUser(){return list();}/*Mapper CRUD(增删改查)*///增加一个Userpublic int addUser_ByMapper(User user){return userMapper.insert(user);}//根据id删除一个Userpublic int deleteUserById_ByMapper(int id){return userMapper.deleteById(id);}//更新Userpublic boolean updateUser_ByMapper(User user){userMapper.updateById(user);return true;}//根据id查询,返回一个Userpublic User queryUser_ByMapper(int id){return userMapper.selectById(id);}//查询全部User,返回list集合public List queryAllUser_ByMapper(){return userMapper.selectList(new QueryWrapper<>());//QueryWrapper没有任何条件}
}
写了三个具有代表性的接口 👇
路径:src/main/java/com/visitwebdemo/controller/UserController.java
package com.visitwebdemo.controller;@Slf4j
@RestController
@RequestMapping("/web")
public class UserController {@Autowiredprivate UserServiceImpl userService;@RequestMapping("/allUser")public List 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);}}
以上准备工作就完成了~
RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,它提供了很多可以方便访问远程 http 服务的方法,这些方法可以帮助开发人员减少编写客户端代码的工作量。
其实最主要还是 Get 和 Post 请求:
xxxForObject() 和 xxxForEntity() 二者区别主要在于:xxxForObject() 的返回值是HTTP协议的响应体;而 xxxForEntity() 返回的是 ResponseEntity(ResponseEntity是对HTTP响应的封装),除了包含响应体,还包含HTTP状态码、contentType、contentLength、Header等信息。
发送请求需要携带 URI 👇,以下是几个常见的构造方式,UriComponentsBuilder 最为常用
URI uri = UriComponentsBuilder.fromUriString("http://localhost:8080/web/query").build().toUri();
URI uri = UriComponentsBuilder.fromUriString("http://localhost:8080/web/query/{userId}").build(1);
URI uri = MvcUriComponentsBuilder.fromMethodCall(MvcUriComponentsBuilder.on(UserController.class).allUser()).build().toUri();
④ 获取当前请求的URI
URI uri = ServletUriComponentsBuilder.fromCurrentRequest().build().toUri();
注意由于是请求本地项目的 web 资源,因此需要在先启动项目 👇,然后再对测试类进行测试
路径均在:src/test/java/com/visitwebdemo/restemplateTests.java
//new 一个RestTemplate ,后面也会用到
RestTemplate restTemplate = new RestTemplate();@Test
public void queryOneUser(){//构建 uriURI uri = UriComponentsBuilder.fromUriString("http://localhost:8080/web/query/{userId}").build(1);//执行rest请求,ResponseEntity封装了返回信息,若将getForEntity 替换成 getForObject,则不需要 ResponseEntityResponseEntity 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 查询成功 👇
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 map = new LinkedMultiValueMap<>();map.add("id", 2L);map.add("name", "jack");map.add("age", 16);map.add("email", "yinyu@baomidou.com");// 组装请求体HttpEntity> request = new HttpEntity<>(map, headers);// 发送post请求,并打印结果,以String类型接收响应结果JSON字符串String result = restTemplate.postForObject(url, request, String.class);System.out.println(result);
}
post 请求成功 👇,由于没用 postForEntity + ResponseEntity,所以直接输出内容
数据表更新成功 👇
主要是用到了 exchange + ParameterizedTypeReference,最后返回 User 列表
@Test
public void queryAllUser(){//构建 uriURI uri = UriComponentsBuilder.fromUriString("http://localhost:8080/web/allUser").build().toUri();//解析泛型对象ParameterizedTypeReference> ptr = new ParameterizedTypeReference>() {};ResponseEntity> 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());
}
返回成功👇
WebClient 是从 Spring WebFlux 5.0 版本开始提供的一个非阻塞的基于响应式编程的进行 Http 请求的客户端工具。它的响应式编程的基于 Reactor 的。WebClient 中提供了标准Http请求方式对应的 get、post、put、delete 等方法,可以用来发起相应的请求。
关于 Reactor 的相关内容-> Spring 05 :Project Reactor 响应式流框架
Ⅰ 创建 WebClient
WebClient.create()
WebClient.builder()
Ⅱ 发起请求
Ⅲ 获得结果
Ⅳ 处理 HTTP Status
Ⅴ 应答正文
还是一样,需要在先启动项目 👇,然后再对测试类进行测试
路径均在:src/test/java/com/visitwebdemo/webclientTests.java
返回的是 Mono 封装的 User ,然后对他做进一步处理,这是 Reactor 相关内容~
//创建一个 webClient
WebClient webClient = WebClient.create("http://localhost:8080");@Test
public void queryOneUser(){Mono mono = webClient.get()//创建一个get请求.uri("/web/query/1/") //也可写成 uri("/web/query/{userId}",1).retrieve() // 获取结果 可以用exchange代替 返回的上一个 User.bodyToMono(User.class);//处理单个对象System.out.println(mono.block());
}
查询成功 👇
@Test
public void queryAllUser(){Flux flux = webClient.get()//创建一个get请求.uri("/web/allUser/").retrieve() // 获取结果 可以用exchange代替 返回的上一个 User 的list.bodyToFlux(User.class);//处理多个对象 即多组数据flux.toStream().forEach(System.out::println);
}
查询成功 👇
@Test
public void updateUser(){MultiValueMap map = new LinkedMultiValueMap<>();map.add("id", 2L);map.add("name", "jack");map.add("age", 18);map.add("email", "yinyu@baomidou.com");Mono 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博客
下一篇:使用awk聚合和排序