spring 5 新框架 Spring webFlux
电商 金融 对 严谨要求高,对于数据的一致性十分重要
并发:通过锁 保证一些重要数据的一致性
游戏 视频 新闻 广告,不需要很高的数据一致性
但 : 对于并发数 和 相应速度 十分在意
传统的模式会引入 一致性的机制,会造成性能瓶颈,所以提出了:响应式编程。
Servlet 3.1 之后,就支持响应式编程
Spring boot 1.x.x 不支持
Spring boot 2.x.x 才能支持
在讨论 WebFlux之前,需要了解 RxJava 和 Reactor
传统的模型
Reactor 反应器模式
客户端1,客户端2 ——每个客户端生成一个event——事件都到 selector中
selector 分发出 n个 Dispatcher——(每个dispatcher对应一个) Request Handler1
上面是,看图的描述,下面是官方的解释:
简单解释:
我的简单理解:
Servlet 3.1 之前 web容器 都是基于 阻塞机制 开发的
高并发 网站,使用函数式 的 编程 就 更为 直观 和 简易
特别是 那些需要高速响应 而 对业务 逻辑 ,要求 并不十分严格的网站。
java 8 之后,引入了 Lambda 和 Functional接口
Spring 5 推出了 Spring WebFlux 新一代的 Web响应式 编程 框架。
分为:
需要能够支持 Servlet 3.1 + 的容器, tomcat jetty undertow
异步编程,使用最多的是 netty , 在 webFlux 的starter中 默认依赖 netty
两种开发模式:
数据流的封装,Reactor提供的 Flux 和 Mono
背压 backpressure ,只对 Flux有意义
mvc 使用 DispatcherServlet
webFlux 使用 WebHandler
WebHandler接口
public Mono<Void> handle(ServerWebExchange exchange) {
if (logger.isDebugEnabled()) {
ServerHttpRequest request = exchange.getRequest();
logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]");
}
return this.handlerMappings == null ? Mono.error(HANDLER_NOT_FOUND_EXCEPTION) :
//框架封装数据流 flux
Flux
.fromIterable(this.handlerMappings)//循环 handlerMappings
.concatMap(
(mapping) -> { //找到合适的处理器
return mapping.getHandler(exchange);
}
)
.next()//处理第一条记录
.switchIfEmpty( //如果找不到处理器的情况
Mono.error(HANDLER_NOT_FOUND_EXCEPTION))
//通过反射运行处理器
.flatMap((handler) -> {
return this.invokeHandler(exchange, handler);
}).flatMap((result) -> {
//解析结果,将其转换 为 对应的数据流 序列
return this.handleResult(exchange, result);
});
}
与 Spring MVC 一样,都是从 HandlerMapping 找到对应 的处理器
getHandler方法找到对应的处理器
invokeHandler方法运行 处理器
找到合适 handlerAdapter去运行处理
handleResult 将结果 转变为 对应的数据流
HandlerMapping 处理映射器 (@Controller @RequestMapping 获得)
到达 DispatcherHandler 分发处理器
HandlerAdapter 处理适配器
Result 处理器结果
分发处理器
handleResult 结果处理,转换为对应的数据流
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency> mongodb-reactive
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-mongodb-reactiveartifactId>
dependency>
<dependency> webflux
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webfluxartifactId>
dependency>
<dependency> tomcat
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-tomcatartifactId>
<scope>providedscope>
dependency>
<dependency> 这里书上没引用
<groupId>io.projectreactorgroupId>
<artifactId>reactor-testartifactId>
<scope>testscope>
dependency>
public class User implements Serializable {
private static final long serialVersionUID = 3923229573077975377L;
@Id
private Long id;
// 性别
private SexEnum sex;
// 在MongoDB中使用user_name保存属性
@Field("user_name")
private String userName;
private String note;
}
public enum SexEnum {
MALE(1, "男"),
FEMALE(0, "女");
private int code;
private String name;
SexEnum(int code, String name) {
this.code = code;
this.name = name;
}
public static SexEnum getSexEnum(int code) {
SexEnum [] emuns = SexEnum.values();
for (SexEnum item : emuns) {
if (item.getCode() == code) {
return item;
}
}
return null;
}
}
@Repository
//请注意这里需要继承ReactiveMongoRepository
public interface UserRepository extends ReactiveMongoRepository<User, Long> {
/**
* 对用户名和备注进行模糊查询
* @param userName —— 用户名称
* @param note —— 备注
* @return 符合条件的用户
*/
public Flux<User> findByUserNameLikeAndNoteLike(
String userName, String note);
}
public interface UserService {
Mono<User> getUser(Long id);
Mono<User> insertUser(User user);
Mono<User> updateUser(User user);
Mono<Void> deleteUser(Long id);
Flux<User> findUsers(String userName, String note);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public Mono<User> getUser(Long id) {
return userRepository.findById(id);
}
@Override
public Mono<User> insertUser( User user) {
return userRepository.save(user);
}
@Override
public Mono<User> updateUser(User user) {
return userRepository.save(user);
}
@Override
public Mono<Void> deleteUser(Long id) {
Mono<Void> result = userRepository.deleteById(id);
return result;
}
@Override
public Flux<User> findUsers(String userName, String note) {
return userRepository.findByUserNameLikeAndNoteLike(userName, note);
}
}
也可用 @Controller @RestController @GetMapping
使用 REST 风格 更合适
public class UserVo {
private Long id;
private String userName;
private int sexCode;
private String sexName;
private String note;
}
// REST风格控制器,
@RestController //返回的内容将转为json对象
public class UserController {
@Autowired
private UserService userService;
// 获取用户
@GetMapping("/user/{id}")
public Mono<UserVo> getUser(@PathVariable Long id) {
return userService.getUser(id)
// 从User对象转换为UserVo对象
.map(u -> translate(u));
}
// 新增用户
@PostMapping("/user")
public Mono<UserVo> insertUser(@RequestBody User user) {
return userService.insertUser(user)
// 从User对象转换为UserVo对象
.map(u -> translate(u));
}
// 更新用户
@PutMapping("/user")
public Mono<UserVo> updateUser(@RequestBody User user) {
return userService.updateUser(user)
// 从User对象转换为UserVo对象
.map(u -> translate(u));
}
// 删除用户
@DeleteMapping("/user/{id}")
public Mono<Void> deleteUser(@PathVariable Long id) {
return userService.deleteUser(id);
}
// 查询用户
@GetMapping("/user/{userName}/{note}")
public Flux<UserVo> findUsers(@PathVariable String userName, @PathVariable String note) {
return userService.findUsers(userName, note)
// 从User对象转换为UserVo对象
.map(u -> translate(u));
}
// 加入局部验证器
@InitBinder
public void initBinder(DataBinder binder) {
binder.setValidator(new UserValidator());
}
/***
* 完成PO到VO的转换
*
* @param user
* ——PO 持久对象
* @return UserVo ——VO 视图对象
*/
private UserVo translate(User user) {
UserVo userVo = new UserVo();
userVo.setUserName(user.getUserName());
userVo.setSexCode(user.getSex().getCode());
userVo.setSexName(user.getSex().getName());
userVo.setNote(user.getNote());
userVo.setId(user.getId());
return userVo;
}
}
# MongoDB服务器
spring.data.mongodb.host=192.168.10.128
# MongoDB用户名。docker默认启动 没有用户名和密码
spring.data.mongodb.username=spring
# MongoDB密码
spring.data.mongodb.password=123456
# MongoDB端口
spring.data.mongodb.port=27017
# MongoDB库名称
spring.data.mongodb.database=springboot
spring.webflux.static-path-pattern=/static/**
// 定义扫描包
@SpringBootApplication(scanBasePackages="com.springboot.chapter14")
// 由于引入JPA,默认的情况下,需要配置数据源,
// 通过@EnableAutoConfiguration排除原有自动配置的数据源
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
// 在WebFlux下,驱动MongoDB的JPA接口
@EnableReactiveMongoRepositories(
// 定义扫描的包
basePackages="com.springboot.chapter14.repository")
public class Chapter14Application {
public static void main(String[] args) {
SpringApplication.run(Chapter14Application.class, args);
}
}
用户请求
网关
一次交易:用户微服务 判断用户等级,财务微服务管理用户的消费款项,产品微服务管理产品的发放,交易微服务记录交易的发生情况。
为了方便微服务之间的调用,webFlux 提供了 WebClient类,比RestTemplate更强大
public class Chapter14WebClient {
public static void main(String[] args) {
// 创建WebClient对象,并且设置请求基础路径
WebClient client = WebClient.create("http://localhost:8080");
getSecurityUser(client, 1L);
updateUserName(client, 1L, "update_user_name");
getUserPojo(client, 1L);
// 一个新的用户
User newUser = new User();
newUser.setId(6L);
newUser.setNote("note_6");
newUser.setUserName("user_name_6");
newUser.setSex(SexEnum.MALE);
insertUser3(client, newUser);
insertUser2(client);
// 一个新的用户
User newUser = new User();
newUser.setId(1L);
newUser.setNote("note_1");
newUser.setUserName("user_name_1");
newUser.setSex(SexEnum.MALE);
// 新增用户
insertUser(client, newUser);
// 获取用户
getUser(client, 1L);
User updUser = new User();
updUser.setId(1L);
updUser.setNote("note_update");
updUser.setUserName("user_name_update");
updUser.setSex(SexEnum.FEMALE);
// 更新用户
updateUser(client, updUser);
// 查询用户
findUsers(client, "user", "note");
// 删除用户
deleteUser(client, 3L);
}
private static void getUser(WebClient client, Long id) {
Mono<UserVo> userMono =
// 定义GET请求
client.get()
// 定义请求URI和参数
.uri("/user/{id}", id)
// 接收请求结果类型
.accept(MediaType.APPLICATION_STREAM_JSON)
// 设置请求结果检索规则
.retrieve()
// 将结果体转换为一个Mono封装的数据流
.bodyToMono(UserVo.class);
// 获取服务器发布的数据流,此时才会发送请求
UserVo user = userMono.block();
System.out.println("【用户名称】" + user.getUserName());
}
//get() .uri .accept(MediaType.APPLICATION_STREAM_JSON)
//.retrieve() .bodyToMono(UserVo.class);
private static void insertUser(WebClient client, User newUser) {
// 注意这只是定义一个时间,并不会发送请求
Mono<UserVo> userMono =
// 定义POST请求
client.post()
// 设置请求URI
.uri("/user")
// 请求体为JSON数据流
.contentType(MediaType.APPLICATION_STREAM_JSON)
// 请求体内容
.body(Mono.just(newUser), User.class)
// 接收请求结果类型
.accept(MediaType.APPLICATION_STREAM_JSON)
// 设置请求结果检索规则
.retrieve()
// 将结果体转换为一个Mono封装的数据流
.bodyToMono(UserVo.class);
// 获取服务器发布的数据流,此时才会发送请求
UserVo user = userMono.block();
System.out.println("【用户名称】" + user.getUserName());
}
// post() .uri("/user") .contentType .body(Mono.just(newUser), User.class)
// .accept .retrieve() .bodyToMono
//userMono.block(); 才会发送请求
private static void insertUser3(WebClient client, User newUser) {
// 注意这只是定义一个时间,并不会发送请求
Mono<UserVo> userMono =
// 定义POST请求
client.post()
// 设置请求URI
.uri("/user3")
// 请求体为JSON数据流
.contentType(MediaType.APPLICATION_STREAM_JSON)
// 请求体内容
.body(Mono.just(newUser), User.class)
// 接收请求结果类型
.accept(MediaType.APPLICATION_STREAM_JSON)
// 设置请求结果检索规则
.retrieve()
// 将结果体转换为一个Mono封装的数据流
.bodyToMono(UserVo.class);
// 获取服务器发布的数据流,此时才会发送请求
UserVo user = userMono.block();
System.out.println("【用户名称】" + user.getUserName());
}
private static void updateUser(WebClient client, User updUser) {
Mono<UserVo> userMono =
// 定义PUT请求
client.put().uri("/user")
// 请求体为JSON数据流
.contentType(MediaType.APPLICATION_STREAM_JSON)
// 请求体内容
.body(Mono.just(updUser), User.class)
// 接收请求结果类型
.accept(MediaType.APPLICATION_STREAM_JSON)
// 设置请求结果检索规则
.retrieve()
// 将结果体转换为一个Mono封装的数据流
.bodyToMono(UserVo.class);
// 获取服务器发布的数据流,此时才会发送请求
UserVo user = userMono.block();
System.out.println("【用户名称】" + user.getUserName());
}
private static void findUsers(WebClient client, String userName, String note) {
// 定义参数map
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("userName", userName);
paramMap.put("note", note);
Flux<UserVo> userFlux =
// 定义PUT请求,使用Map传递多个参数
client.get().uri("/user/{userName}/{note}", paramMap)
// 接收请求结果类型
.accept(MediaType.APPLICATION_STREAM_JSON)
// 设置请求结果检索规则
.retrieve()
// 将结果体转换为一个Mono封装的数据流
.bodyToFlux(UserVo.class);
// 通过Iterator遍历结果数据流,执行后服务器才会响应
Iterator<UserVo> iterator = userFlux.toIterable().iterator();
// 遍历
while (iterator.hasNext()) {
UserVo item = iterator.next();
System.out.println("【用户名称】" + item.getUserName());
}
}
//.bodyToFlux
// userFlux.toIterable().iterator() 才会发送请求
//下来式处理,只在每一次 执行循环 时,才会向服务器 要一个 数据流序列 到 客户端处理。
//当处理完一个数据流序列后,才会执行第二次,获取下一个数据流序列。直到获取所有的数据流序列。
private static void deleteUser(WebClient client, Long id) {
Mono<Void> result = client.delete()
// 设置请求URI
.uri("/user/{id}", id)
// 接收请求结果类型
.accept(MediaType.APPLICATION_STREAM_JSON)
// 设置请求结果检索规则
.retrieve()
// 将结果体转换为一个Mono封装的数据流
.bodyToMono(Void.class);
// 获取服务器发布的数据流,此时才会发送请求
Void voidResult = result.block();
System.out.println(voidResult);
}
//.bodyToMono(Void.class);
private static void insertUser2(WebClient client) {
// 注意这只是定义一个时间,并不会发送请求
Mono<UserVo> userMono =
// 定义POST请求
client.post()
// 设置请求URI,和约定格式的用户信息
.uri("/user2/{user}", "2-convert4-0-note4")
// 接收请求结果类型
.accept(MediaType.APPLICATION_STREAM_JSON)
// 设置请求结果检索规则
.retrieve()
// 将结果体转换为一个Mono封装的数据流
.bodyToMono(UserVo.class);
// 获取服务器发布的数据流,此时才会发送请求
UserVo user = userMono.block();
System.out.println("【用户名称】" + user.getUserName());
}
// 转换方法
private static UserPojo translate(UserVo vo) {
if (vo == null) {
return null;
}
UserPojo pojo = new UserPojo();
pojo.setId(vo.getId());
pojo.setUserName(vo.getUserName());
// 性别转换
pojo.setSex(vo.getSexCode() == 1 ? 1 : 2);
pojo.setNote(vo.getNote());
return pojo;
}
public static void getUserPojo(WebClient client, Long id) {
Mono<UserPojo> userMono =
// HTTP GET请求
client.get()
// 定义请求URI和参数
.uri("/user/{id}", id)
// 接收结果为JSON数据流
.accept(MediaType.APPLICATION_STREAM_JSON)
// 启用交换
.exchange()
// 出现错误则返回空
.doOnError(ex -> Mono.empty())
// 获取服务器发送过来的UserVo对象
.flatMap(response -> response.bodyToMono(UserVo.class))
// 通过自定义方法转换为客户端的UserPojo
.map(user -> translate(user));
// 获取客户端的UserPojo
UserPojo pojo = userMono.block();
// 不为空打印信息
if (pojo != null) {
System.out.println("获取的用户名称为" + pojo.getUserName());
} else {
System.out.println("获取的用户编号为" + id + "失败");
}
}
}
读取请求的http首部所设置内容
新增参数转换器 和 验证规则
错误的处理
实现 WebFluxConfigurer
// 实现Java 8的接口WebFluxConfigurer,该接口都是default方法
@Configuration
public class WebFluxConfig implements WebFluxConfigurer {
// 注册Converter
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(stringToUserConverter());
}
// 定义String --> User类型转换器
// @Bean// 如果定义为Spring Bean,Spring Boot会自动识别为类型转换器
// 这种方法 更加简单
public Converter<String, User> stringToUserConverter() {
Converter<String, User> converter = new Converter<String, User>() {
@Override
public User convert(String src) {
String strArr[] = src.split("-");
User user = new User();
Long id = Long.valueOf(strArr[0]);
user.setId(id);
user.setUserName(strArr[1]);
int sexCode = Integer.valueOf(strArr[2]);
SexEnum sex = SexEnum.getSexEnum(sexCode);
user.setSex(sex);
user.setNote(strArr[3]);
return user;
}
};
return converter;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
// 注册资源,可以通过URI访问
.addResourceHandler("/resources/static/**")
// 注册Spring资源,可以在Spring机制中访问
.addResourceLocations("/public/**", "classpath:/static/")
// 缓存一年(365天)
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS));
}
// // 设置全局性验证器
// @Override
// public Validator getValidator() {
// return new UserValidator();
// }
}
@PostMapping("/user2/{user}")
public Mono<UserVo> insertUser2(@PathVariable("user") User user) {
return userService.insertUser(user)
// 进行PO和VO之间的转换
.map(u -> translate(u));
}
private static void insertUser2(WebClient client) {
// 注意这只是定义一个时间,并不会发送请求
Mono<UserVo> userMono =
// 定义POST请求
client.post()
// 设置请求URI,和约定格式的用户信息
.uri("/user2/{user}", "2-convert4-0-note4")
// 接收请求结果类型
.accept(MediaType.APPLICATION_STREAM_JSON)
// 设置请求结果检索规则
.retrieve()
// 将结果体转换为一个Mono封装的数据流
.bodyToMono(UserVo.class);
// 获取服务器发布的数据流,此时才会发送请求
UserVo user = userMono.block();
System.out.println("【用户名称】" + user.getUserName());
}
public class UserValidator implements Validator {
// 确定支持的验证类型
@Override
public boolean supports(Class<?> clazz) {
return clazz.equals(User.class);
}
// 验证逻辑
@Override
public void validate(Object target, Errors errors) {
User user = (User) target;
// 监测用户名是否为空
if (StringUtils.isEmpty(user.getUserName())) {
errors.rejectValue("userName", null, "用户名不能为空");
}
}
}
@Configuration
public class WebFluxConfig implements WebFluxConfigurer {
// 设置全局性验证器
@Override
public Validator getValidator() {
return new UserValidator();
}
}
@PostMapping("/user3")
public Mono<UserVo> insertUser3(@Valid @RequestBody User user) {
return userService.insertUser(user)
// 进行PO和VO之间的转换
.map(u -> translate(u));
}
//只会在这一个controller生效
// 加入局部验证器
@InitBinder
public void initBinder(DataBinder binder) {
binder.setValidator(new UserValidator());
}
@Configuration
public class WebFluxConfig implements WebFluxConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
// 注册资源,可以通过URI访问
.addResourceHandler("/resources/static/**")
// 注册Spring资源,可以在Spring机制中访问
.addResourceLocations("/public/**", "classpath:/static/")
// 缓存一年(365天)
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS));
}
}
设置请求头
服务端发生了异常处理
之前是通过 retrieve 方法 将 服务端的数据流转换
public static void getUser2(WebClient client, Long id) {
Mono<UserVo> userMono =
// HTTP GET请求
client.get()
// 定义请求URI和参数
.uri("/user/{id}", id)
// 接收结果为JSON数据流
.accept(MediaType.APPLICATION_STREAM_JSON)
// 设置检索
.retrieve().onStatus(
// 发生4开头或者5开头的状态码,4开头是客户端错误,5开头是服务器错误
// 第一个Lambda表达式,返回如果为true,则执行第二个Lambda表达式
status -> status.is4xxClientError() || status.is5xxServerError(),
// 如果发生异常,则用第二个表达式返回作为结果
// 第二个Lambda表达式
response -> Mono.empty())
// 将请求结果转换为Mono数据流
.bodyToMono(UserVo.class);
UserVo user = userMono.block();
// 如果用户正常返回
if (user != null) {
System.out.println("【用户名称】" + user.getUserName());
} else {// 不能正常返回或者用户为空
System.out.println("服务器没有返回编号为:" + id + "的用户");
}
}
//客户端的pojo
public class UserPojo {
private Long id;
private String userName;
// 1-男 2-女
private int sex = 1;
private String note = null;
}
//服务器的pojo
public class UserVo {
private Long id;
private String userName;
private int sexCode;
private String sexName;
private String note;
}
// 转换方法
private static UserPojo translate(UserVo vo) {
if (vo == null) {
return null;
}
UserPojo pojo = new UserPojo();
pojo.setId(vo.getId());
pojo.setUserName(vo.getUserName());
// 性别转换
pojo.setSex(vo.getSexCode() == 1 ? 1 : 2);
pojo.setNote(vo.getNote());
return pojo;
}
public static void getUserPojo(WebClient client, Long id) {
Mono<UserPojo> userMono =
// HTTP GET请求
client.get()
// 定义请求URI和参数
.uri("/user/{id}", id)
// 接收结果为JSON数据流
.accept(MediaType.APPLICATION_STREAM_JSON)
// 启用交换
.exchange()
// 出现错误则返回空
.doOnError(ex -> Mono.empty())
// 获取服务器发送过来的UserVo对象
.flatMap(response -> response.bodyToMono(UserVo.class))
// 通过自定义方法转换为客户端的UserPojo
.map(user -> translate(user));
// 获取客户端的UserPojo
UserPojo pojo = userMono.block();
// 不为空打印信息
if (pojo != null) {
System.out.println("获取的用户名称为" + pojo.getUserName());
} else {
System.out.println("获取的用户编号为" + id + "失败");
}
}
translate(user) 将 服务端对象 转换为 客户端对象
不用 retrieve而是:.exchange() 方法,允许自定义转换
.flatMap(response -> response.bodyToMono(UserVo.class)) 对服务器的方法请求 转换为 Mono对象
.map(user -> translate(user)); 转成 Mono
@PutMapping("/user/name")
public Mono<UserVo> updateUserName(@RequestHeader("id") Long id,
@RequestHeader("userName") String userName) {
Mono<User> userMono = userService.getUser(id);
User user = userMono.block();
if (user == null) { // 查找不到用户信息,抛出运行异常消息......
throw new RuntimeException("找不到用户信息");
}
user.setUserName(userName);
return this.updateUser(user);
}
//这里没用
public static void updateUserName(WebClient client, Long id, String userName) {
Mono<UserVo> monoUserVo = client
// HTTP PUT请求
.put()
// 请求URI
.uri("/user/name", userName)
// 第一个请求头
.header("id", id +"")
// 第二个请求头
.header("userName", userName)
// 设置接收JSON数据流
.accept(MediaType.APPLICATION_STREAM_JSON)
// 检索
.retrieve()
// 根据服务端响应码处理逻辑
.onStatus(
status -> status.is4xxClientError() || status.is5xxServerError(),
response -> Mono.empty())
// 转换为UserVo对象
.bodyToMono(UserVo.class);
UserVo userVo = monoUserVo.block();
// 不为空打印信息
if (userVo != null) {
System.out.println("获取的用户名称为" + userVo.getUserName());
} else {
System.out.println("获取的用户编号为" + id + "失败");
}
}
public static void getSecurityUser(WebClient client, Long id) {
Mono<UserVo> monoUserVo = client
// HTTP PUT请求
.get()
// 请求URI
.uri("/security/user/{id}", id)
// 第一个请求头
.header("header_password", "pwd")
// 第二个请求头
.header("header_user", "user")
// 设置接收JSON数据流
.accept(MediaType.APPLICATION_STREAM_JSON)
// 检索
.retrieve()
// 根据服务端响应码处理逻辑
.onStatus(
status -> status.is4xxClientError() || status.is5xxServerError(),
response -> Mono.empty())
// 转换为UserVo对象
.bodyToMono(UserVo.class);
UserVo userVo = monoUserVo.block();
// 不为空打印信息
if (userVo != null) {
System.out.println("获取的用户名称为" + userVo.getUserName());
} else {
System.out.println("获取的用户编号为" + id + "失败");
}
}
@Service
public class UserHandler {
@Autowired
private UserRepository userRepository = null;
public Mono<ServerResponse> getUser(ServerRequest request) {
// 获取请求URI参数
String idStr = request.pathVariable("id");
Long id = Long.valueOf(idStr);
Mono<UserVo> userVoMono = userRepository.findById(id)
// 转换为UserVo
.map(u -> translate(u));
return ServerResponse
// 响应成功
.ok()
// 响应体类型
.contentType(MediaType.APPLICATION_JSON_UTF8)
// 响应体
.body(userVoMono, UserVo.class);
}
// .cache() 不使用:程序就会在等待数据的接收
public Mono<ServerResponse> insertUser(ServerRequest request) {
Mono<User> userMonoParam = request.bodyToMono(User.class);
Mono<UserVo> userVoMono = userMonoParam
// 缓存请求体
.cache()
// 处理业务逻辑,转变数据流
.flatMap(user ->userRepository.save(user)
// 转换为UserVo对象
.map(u->translate(u)));
return ServerResponse
// 响应成功
.ok()
// 响应体类型
.contentType(MediaType.APPLICATION_JSON_UTF8)
// 响应体
.body(userVoMono, UserVo.class);
}
public Mono<ServerResponse> updateUser(ServerRequest request) {
Mono<User> userMonoParam = request.bodyToMono(User.class);
Mono<UserVo> userVoMono = userMonoParam.cache()
.flatMap(user ->userRepository.save(user)
.map(u->translate(u)));
return ServerResponse
// 响应成功
.ok()
// 响应体类型
.contentType(MediaType.APPLICATION_JSON_UTF8)
// 响应体
.body(userVoMono, UserVo.class);
}
public Mono<ServerResponse> deleteUser(ServerRequest request) {
// 获取请求URI参数
String idStr = request.pathVariable("id");
Long id = Long.valueOf(idStr);
Mono<Void> monoVoid = userRepository.deleteById(id);
return ServerResponse
// 响应成功
.ok()
// 响应体类型
.contentType(MediaType.APPLICATION_JSON_UTF8)
// 响应体
.body(monoVoid, Void.class);
}
public Mono<ServerResponse> findUsers(ServerRequest request) {
String userName = request.pathVariable("userName");
String note = request.pathVariable("note");
Flux<UserVo> userVoFlux =
userRepository.findByUserNameLikeAndNoteLike(userName, note)
.map(u -> translate(u));
// 请参考getUser方法的注释
return ServerResponse
.ok()
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(userVoFlux, UserVo.class);
}
public Mono<ServerResponse> updateUserName(ServerRequest request) {
// 获取请求头数据
String idStr = request.headers().header("id").get(0);
Long id = Long.valueOf(idStr);
String userName = request.headers().header("userName").get(0);
// 获取原有用户信息
Mono<User> userMono = userRepository.findById(id);
User user = userMono.block();
// 修改用户名
user.setUserName(userName);
Mono<UserVo> result = userRepository.save(user).map(u -> translate(u));
// 响应结果
return ServerResponse
.ok()
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(result, UserVo.class);
}
/***
* 完成PO到VO的转换
*
* @param user
* PO 持久对象
* @return UserVo ——VO 视图对象
*/
private UserVo translate(User user) {
UserVo userVo = new UserVo();
userVo.setUserName(user.getUserName());
userVo.setSexCode(user.getSex().getCode());
userVo.setSexName(user.getSex().getName());
userVo.setNote(user.getNote());
userVo.setId(user.getId());
return userVo;
}
}
与 请求URI 对应起来。
http请求 映射到方法上
//静态导入
import static org.springframework.http.MediaType.APPLICATION_STREAM_JSON;
import static org.springframework.web.reactive.function.server.RequestPredicates.DELETE;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.POST;
import static org.springframework.web.reactive.function.server.RequestPredicates.PUT;
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
import static org.springframework.web.reactive.function.server.RequestPredicates.contentType;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
@Configuration
public class RouterConfig {
// 注入用户处理器
@Autowired
private UserHandler userHandler = null;
// 用户路由
@Bean
public RouterFunction<ServerResponse> userRouter() {
RouterFunction<ServerResponse> router =
// 对应请求URI的对应关系
route(
// GET请求和其路径
GET("/router/user/{id}")
// 响应结果为JSON数据流
.and(accept(APPLICATION_STREAM_JSON)),
// 定义处理方法
userHandler::getUser)
// 增加一个路由
.andRoute(
// GET请求和其路径
GET("/router/user/{userName}/{note}").and(accept(APPLICATION_STREAM_JSON)),
// 定义处理方法
userHandler::findUsers)
// 增加一个路由
.andRoute(
// POST请求和其路径
POST("/router/user")
// 请求体为JSON数据流
.and(contentType(APPLICATION_STREAM_JSON)
// 响应结果为JSON数据流
.and(accept(APPLICATION_STREAM_JSON))),
// 定义处理方法
userHandler::insertUser)
// 增加一个路由
.andRoute(
// PUT请求和其路径
PUT("/router/user")
// 请求体为JSON数据流
.and(contentType(APPLICATION_STREAM_JSON))
// 响应结果为JSON数据流
.and(accept(APPLICATION_STREAM_JSON)),
// 定义处理方法
userHandler::updateUser)
.andRoute(
// DELETE请求和其路径
DELETE("/router/user/{id}")
// 响应结果为JSON数据流
.and(accept(APPLICATION_STREAM_JSON)),
// 定义处理方法
userHandler::deleteUser)
.andRoute(
// PUT请求和其路径
PUT("/router/user/name")
// 响应结果为JSON数据流
.and(accept(APPLICATION_STREAM_JSON)),
// 定义处理方法
userHandler::updateUserName);
return router;
}
}
通过验证身份后,才能处理 业务逻辑
请求头上存放用户名和密码,才能访问
在上个类上加入:
// 请求头用户名属性名称
private static final String HEADER_NAME = "header_user";
// 请求头密码属性名称
private static final String HEADER_VALUE = "header_password";
@Bean
public RouterFunction<ServerResponse> securityRouter() {
RouterFunction<ServerResponse> router =
// 对应请求URI的对应关系
route(
// GET请求和其路径
GET("/security/user/{id}")
// 响应结果为JSON数据流
.and(accept(APPLICATION_STREAM_JSON)),
// 定义处理方法
userHandler::getUser)
// 使用过滤器
.filter((request, next) -> filterLogic(request, next));
return router;
}
// 请求过滤器逻辑
private Mono<ServerResponse> filterLogic(ServerRequest request, HandlerFunction<ServerResponse> next) {
// 取出请求头
String userName = request.headers().header(HEADER_NAME).get(0);
String password = request.headers().header(HEADER_VALUE).get(0);
// 验证通过的条件
if (!StringUtils.isEmpty(userName) && !StringUtils.isEmpty(password) && !userName.equals(password)) {
// 接受请求
return next.handle(request);
}
// 请求头不匹配,则不允许请求,返回为未签名错误 401,
return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
}
.filter((request, next) -> filterLogic(request, next));