继续Spring Webflux,RouterFunction中处理数据项校验
如何在Spring Webflux RouterFunction方式下实现数据项校验和异常处理呢?还有一些注意事项和补充的内容。
校验处理
定义一个校验工具类
@UtilityClass
public class CheckUtil {
private final static String NO_NAME = "haha";//不允许传入haha作为name
public void checkName(String name){
if (NO_NAME.equals(name)){
throw new RouterException("名称不允许");//抛出异常
}
}
}
自定义异常类
public class RouterException extends RuntimeException {
public RouterException() {
}
public RouterException(String msg) {
super(msg);
}
public RouterException(String message, Throwable cause) {
super(message, cause);
}
public RouterException(Throwable cause) {
super(cause);
}
}
定义异常处理类
@Component
//由于webException 有多个异常处理的handler 如果要让我们的异常处理生效 需要把优先级调高
@Order(-1)
@Configuration
public class ExceptionHandler implements WebExceptionHandler {
@Override
public Mono<Void> handle(ServerWebExchange serverWebExchange, Throwable throwable) {
ServerHttpResponse response = serverWebExchange.getResponse();
//设置400响应头
response.setStatusCode(HttpStatus.BAD_REQUEST);
//设置返回类型
response.getHeaders().setContentType(MediaType.TEXT_PLAIN);
//处理异常
String errMsg = toStr(throwable);
DataBuffer db = response.bufferFactory().wrap(errMsg.getBytes());
return response.writeWith(Mono.just(db));
}
private String toStr(Throwable throwable) {
//已知异常
//这里当然是需要按照实际业务需要 定义异常对象来处理 这里只是拿OOM来充数的
if(throwable instanceof RouterException){
//已知异常可以简单处理
return throwable.toString();
}
//未知异常 需要打印堆栈,方便定位
else {
throwable.printStackTrace();
return throwable.toString();
}
}
}
业务代码改造
我们将新增用户的方法加入name校验
/**
* 新增用户
* @param var1
* @return
*/
public Mono<ServerResponse> putUserHandle(ServerRequest var1){
Mono<User> user = var1.bodyToMono(User.class);
//对于校验
return user.flatMap(u->{
CheckUtil.checkName(u.getName());//校验用户名
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
//save方法不支持Mono对象,因此需要调用saveAll方法,该方法可以传入Publisher对象,而mono和flux都是Publisher对象
.body(this.userRepository.save(u), User.class);
});
}
当传入name=haha的数据时,会抛异常,并由异常处理类捕获进行处理。
注意
任何时候,我们不能直接将mono和flux中的对象获取之后直接处理,这样会导致对应的响应会变成阻塞模式,因此需要将对象交给springboot去消费。
比如我们如果要去校验,我们需要这么去写:
/**
* 新增用户
* @param var1
* @return
*/
public Mono<ServerResponse> putUserHandle(ServerRequest var1){
Mono<User> user = var1.bodyToMono(User.class);
//对于校验
return user.flatMap(u->{
CheckUtil.checkName(u.getName());
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
//save方法不支持Mono对象,因此需要调用saveAll方法,该方法可以传入Publisher对象,而mono和flux都是Publisher对象
.body(this.userRepository.save(u), User.class);
});
}
扩展:
defaultIfEmpty
如果被观察者发射的数据为空,那么就发射defaultIfEmpty中给的那个值
public final Mono<T> defaultIfEmpty(T defaultV) {
if (this instanceof ScalarCallable) {
try {
T v = this.block();
if (v == null) {
return just(defaultV);
}
} catch (Throwable var3) {
}
return this;
} else {
return onAssembly(new MonoDefaultIfEmpty(this, defaultV));
}
}
switchIfEmpty
在被观察者不发送数据时可以发射更多的数据
public final Mono<T> switchIfEmpty(Mono<? extends T> alternate) {
return onAssembly(new MonoSwitchIfEmpty(this, alternate));
}
可能出现的问题:
依赖包要注意,引入webflux的依赖包,不要再引入web的包,否则会冲突。导致routerfunction配置失效,访问url返回404。
由于之前我把servlet、SSE等都是在一个项目中,所以导致了这个问题。
这种情况在传统的Controller中是影响不大的,但是流式的响应是有问题的。
原文始发于微信公众号(云户):RouterFunction中处理数据项校验如何实现
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/25885.html