java flux api,SpringBoot学习系列-WebFlux REST API 全局异常处理

本文内容

为什么要全局异常处理?

WebFlux REST 全局异常处理实战

小结

摘录:只有不断培养好习惯,同时不断打破坏习惯,我们的行为举止才能够自始至终都是正确的。

一、为什么要全局异常处理?

前后端分离开发,一般提供 REST API,正常返回会有响应体,异常情况下会有对应的错误码响应。

挺多人咨询的,Spring Boot MVC 异常处理用切面 @RestControllerAdvice 注解去实现去全局异常处理。那 WebFlux 如何处理异常?如何实现统一错误码异常处理?

全局异常处理的好处:

异常错误码等统一维护

避免一些重复代码

二、WebFlux REST 全局异常处理实战

下面介绍如何统一拦截异常,进行响应处理。

2.1 工程信息

运行环境:JDK 7 或 8,Maven 3.0+

技术栈:SpringBoot 2.1.3

模块工程名: 2-x-spring-boot-webflux-handling-errors

工程结构:

├── pom.xml

└── src

└── main

├── java

│ └── org

│ └── spring

│ └── springboot

│ ├── Application.java

│ ├── error

│ │ ├── GlobalErrorAttributes.java

│ │ ├── GlobalErrorWebExceptionHandler.java

│ │ └── GlobalException.java

│ ├── handler

│ │ └── CityHandler.java

│ └── router

│ └── CityRouter.java

└── resources

└── application.properties

复制代码

application.properties 无须配置,默认即可

Application Spring Boot 应用启动类,是可以用来启动 Spring Boot 应用。其包含了 @SpringBootApplication 注解和 SpringApplication 类,并调用 SpringApplication 类的 run() 方法,就可以启动该应用。

具体实现类的关系图如下:

39a133bcd343f5c1b1a563142a5a9bd9.png

2.2 CityRouter 路由器类

城市路由器代码如下:

@Configuration

public class CityRouter {

@Bean

public RouterFunction routeCity(CityHandler cityHandler) {

return RouterFunctions.route(RequestPredicates.GET("/hello").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), cityHandler::helloCity);

}

}

复制代码

RouterFunctions 对请求路由处理类,即将请求路由到处理器,这将一个 GET 请求 /hello 路由到处理器 cityHandler 的 helloCity 方法上。跟 Spring MVC 模式下的 HandleMapping 类似。

RouterFunctions.route(RequestPredicate, HandlerFunction) 方法,对应的 参是请求参数和处理函数,如果请求匹配,就调 对应的处理器函数。

2.3 CityHandler 服务处理类

城市服务器处理类,代码如下:

@Component

public class CityHandler {

public Mono helloCity(ServerRequest request) {

return ServerResponse.ok().body(sayHelloCity(request), String.class);

}

private Mono sayHelloCity(ServerRequest request) {

Optional cityParamOptional = request.queryParam("city");

if (!cityParamOptional.isPresent()) {

throw new GlobalException(HttpStatus.INTERNAL_SERVER_ERROR, "request param city is ERROR");

}

return Mono.just("Hello," + cityParamOptional.get());

}

}

复制代码

Mono:实现发布者,并返回 0 或 1 个元素,即单对象。Mono 是响应流 Publisher 具有基础 rx 操作符。可以成功发布元素或者错误。用 Mono 作为返回对象,是因为返回包含了一个 ServerResponse 对象,而不是多个元素。

ServerResponse 是对响应的封装,可以设置响应状态,响应头,响应正文。比如 ok 代表的是 200 响应码、MediaType 枚举是代表这文本内容类型、返回的是 String 的对象。

ServerRequest 是对请求的封装。从请求中拿出 city 的值,如果没有的话则抛出对应的异常。GlobalException 是封装的全局异常。

Mono.justOrEmpty():从一个 Optional 对象或 null 对象中创建 Mono。

2.4 GlobalError 处理类

如图:

011913bb979a6d174831776179adfa5e.png

GlobalException 全局异常类,代码如下:

public class GlobalException extends ResponseStatusException {

public GlobalException(HttpStatus status, String message) {

super(status, message);

}

public GlobalException(HttpStatus status, String message, Throwable e) {

super(status, message, e);

}

}

复制代码

GlobalErrorAttributes 全局异常属性值类,代码如下:

@Component

public class GlobalErrorAttributes extends DefaultErrorAttributes {

@Override

public Map getErrorAttributes(ServerRequest request, boolean includeStackTrace) {

Map map = super.getErrorAttributes(request, includeStackTrace);

if (getError(request) instanceof GlobalException) {

GlobalException ex = (GlobalException) getError(request);

map.put("exception", ex.getClass().getSimpleName());

map.put("message", ex.getMessage());

map.put("status", ex.getStatus().value());

map.put("error", ex.getStatus().getReasonPhrase());

return map;

}

map.put("exception", "SystemException");

map.put("message", "System Error , Check logs!");

map.put("status", "500");

map.put("error", " System Error ");

return map;

}

}

复制代码

重写了父类 DefaultErrorAttributes 默认错误属性类的 getErrorAttributes 获取错误属性方法,从服务请求封装 ServerRequest 中获取对应的异常。

然后判断是否是 GlobalException,如果是 CityHandler 服务处理类抛出的 GlobalException,则返回对应的异常的信息。

GlobalErrorWebExceptionHandler 全局异常处理类,代码如下:

@Component

@Order(-2)

public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {

public GlobalErrorWebExceptionHandler(GlobalErrorAttributes g, ApplicationContext applicationContext,

ServerCodecConfigurer serverCodecConfigurer) {

super(g, new ResourceProperties(), applicationContext);

super.setMessageWriters(serverCodecConfigurer.getWriters());

super.setMessageReaders(serverCodecConfigurer.getReaders());

}

@Override

protected RouterFunction getRoutingFunction(final ErrorAttributes errorAttributes) {

return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);

}

private Mono renderErrorResponse(final ServerRequest request) {

final Map errorPropertiesMap = getErrorAttributes(request, false);

return ServerResponse.status(HttpStatus.BAD_REQUEST)

.contentType(MediaType.APPLICATION_JSON_UTF8)

.body(BodyInserters.fromObject(errorPropertiesMap));

}

}

复制代码

代码解析如下:

AbstractErrorWebExceptionHandler 抽象类是用来处理全局错误时进行扩展和实现

@Order 注解标记 AspectJ 的切面排序,值越小拥有越高的优先级,这里设置优先级偏高。

构造函数将 GlobalErrorAttributes 全局异常属性值类设置到 AbstractErrorWebExceptionHandler 抽象类的局部变量中。

重写 getRoutingFunction 方法,设置对应的 RequestPredicates 和 Mono 服务响应对象

将 GlobalErrorAttributes 的全局异常属性值 map,设置到新的 ServerResponse 即可。

到此基本结束。Spring Boot MVC 错误码如何实战,参考地址:www.bysocket.com/archives/16…

2.5 运行验证

在 IDEA 中执行 Application 类启动,任意正常模式或者 Debug 模式。然后打开浏览器访问:

http://localhost:8080/hello

复制代码

异常界面如下:

851d281e23c00d9d6edd86eb40f755ee.png

可见,这是在 CityHandler 城市服务处理类逻辑中抛出的全局异常信息。那么正常情况会是如何?

改下 URL ,访问如下:

http://localhost:8080/hello?city=WenLing

复制代码

正常界面如下:

e3cd20d0888784e150f47709a2f70ff2.png

三、小结

在 Spring 框架中没有代表错误响应的类,只是返回响应对象,一个 Map。如果需要定义业务的错误码返回体,参考错误码如何实战,参考地址:www.bysocket.com/archives/16…

本文重点还是有别于 Spring Boot 传统 MVC 模式统一异常处理,实战了 WebFlux 全局异常处理机制。实战中这块扩展需要考虑:

异常分层,从基类中扩展出来

错误码设计分层,易扩展,比如在错误码中新增调用量字段…

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

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

相关文章

使您的Java 8方法引用生效

方法参考 众所周知,我们可以使用Java 8中的方法引用 (例如String::isEmpty来引用例如在元素上流式传输时使用的方法。 看一下以下代码片段: Stream.of("A", "", "B").filter(Stream::isEmpty).count();它将产…

down.php无法打开,php下载文件 图片不能打开,该怎么解决

php下载文件 图片不能打开function fileDown($file_name){$file_name iconv("utf-8","gb2312",$file_name);$file_path "E:/php/down/".$file_name;if(!file_exists($file_path)){echo "文件不存在";return;}$fp fopen($file_path,…

【转】Linux如何在系统启动时自动加载模块

1、Linux安装驱动程序 tar zxf ixgbe-<x.x.x>.tar.gz cd ixgbe-<x.x.x>/src/ make install modprobe <ixgbe> 卸载驱动 cd ixgbe-<x.x.x>/src/ make uninstall 2、Linux如何在系统启动时自动加载模块 原文&#xff1a;http://www.cnblogs.com/image-ey…

MATLAB小记_fread的用法

“fread”以二进制形式&#xff0c;从文件读出数据。语法1&#xff1a;[a,count]fread(fid,size,precision)语法2&#xff1a;[a,count]fread(fid,size,precision,skip)size: 不指定 &#xff1a;到尾返回读。N : 读出N个数据&#xff0c;构成列向量。inf …

mvvm 后端_ZK实际应用:MVVM –与ZK客户端API一起使用

mvvm 后端在以前的文章中&#xff0c;我们已经使用ZK的MVVM实现了以下功能&#xff1a; 将数据加载到表中 使用表单绑定保存数据 删除条目并以编程方式更新视图 ZK MVVM和ZK MVC实现方式之间的主要区别是&#xff0c;我们不直接在controller&#xff08;ViewModel&#xff0…

微信分享朋友圈固定缩略图 php,微信转发或分享朋友圈带缩略图、标题和描述的实现方法...

自己做博客以来&#xff0c;很早之前分享过文章至朋友圈&#xff0c;那个时候分享过去的文章自动获取页面的比例适合的图片为所缩略图&#xff1a;后期就很少分享至朋友圈&#xff0c; 近来分享文章给朋友后&#xff0c;发现不带缩略图和简介了&#xff0c;觉得这样很不好看&am…

Oracle 用户、表空间、授权、备份、导入等操作相关

一、基础操作 闲来无事&#xff0c;整理oracle数据库相关操作&#xff0c;以后备用。。。。。 ps&#xff1a; satp 为用户 satp_data 为表空间 1 1.删除表空间2 DROP TABLESPACE satp_data INCLUDING CONTENTS AND DATAFILES;3 4 2.删除用户5 drop user satp cascade;6 …

看一下即将发布的JSF 2.3 Push支持

如前几篇文章所述&#xff0c;下一版本的JavaServer Faces&#xff08;Mojarra&#xff09;已添加了许多增强功能。 JSF 2.3计划于2017年与Java EE 8一起发布&#xff0c;但是您现在可以通过从源代码构建或运行里程碑版本来尝试JSF的一些增强和更新&#xff0c;以进行测试。 对…

java mvc中重复提交表单,spring mvc 防止重复提交表单的两种方法,推荐第二种

第一种方法&#xff1a;判断session中保存的token比较麻烦&#xff0c;每次在提交表单时都必须传入上次的token。而且当一个页面使用ajax时&#xff0c;多个表单提交就会有问题。注解Token代码&#xff1a;package com.thinkgem.jeesite.common.repeat_form_validator;import j…

3415 最小和

3415 最小和 链接&#xff1a;http://codevs.cn/problem/3415/ CodeVS原创 时间限制: 1 s空间限制: 64000 KB题目描述 Description小浣熊松松来到文具店&#xff0c;选择了K支自己喜欢的水彩笔&#xff0c;并抄下了它们的价格。可是到结算时&#xff0c;他发现自己抄价格时抄…

java监控rabbitMq服务状态,SpringCloud-Turbine【RabbitMQ服务监控】

前面我们介绍了通过turbine直接聚合多个服务的监控信息&#xff0c;实现了服务的监控&#xff0c;但是这种方式有个不太好的地方就是turbine和服务的耦合性太强了&#xff0c;针对这个问题&#xff0c;我们可以将服务的监控消息发送到RabbitMQ中&#xff0c;然后turbine中Rabbi…

SVN提示被锁定的解决方法(转)

1、&#xff08;常用&#xff09;出现这个问题后使用“清理”即"Clean up"功能&#xff0c;如果还不行&#xff0c;就直接到上一级目录&#xff0c;再执行“清理”&#xff0c;然后再“更新”。 2、&#xff08;没试过&#xff09;有时候如果看到某个包里面的文件夹没…

jpa 查询 列表_终极JPA查询和技巧列表–第1部分

jpa 查询 列表我们可以在Internet上找到一些JPA“如何做”&#xff0c;在本博客的此处&#xff0c;教您如何使用JPA执行多项任务。 通常&#xff0c;我看到有人问有关使用JPA进行查询的问题。 通常&#xff0c;为了回答此类问题&#xff0c;提供了几个链接以尝试找到该问题的解…

windows下php swoole扩展,Windows 下安装 swoole 图文教程(php)

Windows 下安装 swoole 具体步骤&#xff1a;Swoole,原本不支持在Windows下安装的&#xff0c;所以我们要安装Cygwin来使用。在安装Cygwin下遇到了很多坑&#xff0c;百度经验上的文档不是很全&#xff0c;所以我把自己安装Cygwin和Swoole写下来相当于对自己的沉淀吧。首先准备…

软件工程实践2017第一次作业

&#xff08;1&#xff09;回想一下你初入大学时对计算机专业的畅想 当初你是如何做出选择计算机专业的决定的&#xff1f; 高考之后&#xff0c;综合分数、地理位置、专业考虑&#xff0c;搭上了福州大学这趟动车&#xff0c;不过选报的专业给我打了个折&#xff0c;意外的在生…

将JQGrid与Spring MVC和Gson集成

我在一个单页面应用程序上工作&#xff0c;我想在使用Spring MVC的应用程序的一部分中使用网格功能。 自从我上次使用JQGrid以来已经有一段时间了&#xff0c;找到让我起床所需的信息有点困难。 在这篇文章中&#xff0c;我想整理所有信息并将其放入教程中以供遵循&#xff0c;…

php文件写入加1,PHP关于文件与目录(1) 写入文件 文件权限 三、锁定文件

一、文件权限总之一切都是为了保证目录的安全&#xff0c;保证目录的安全比保证文件的安全更重要。二、写入文件file_put_contents($file,$data); //如果没有的话会创建&#xff0c;有的话覆盖原文件&#xff1b;file_put_contents($file,$data,FILE_APPEND); //没的话会创建&a…

DB2 SQL性能调优秘笈pdf

下载地址&#xff1a;网盘下载 简介编辑《DB2 SQL性能调优秘笈》是一本不可多得的DB2数据库性能调优秘笈&#xff0c;由拥有20余年DB2工作经验的资深数据库专家撰写&#xff0c;Amazon全五星评价畅销书。《DB2 SQL性能调优秘笈》不仅详尽阐述了100余条SQL语句优化的技巧和最佳实…

matlab点到曲线的距离视频,使用MATLAB计算点到直线距离

给定平面上 x1, x2, x3三个点&#xff0c;求x1到x2、x3之间的直线的距离。我是用的是内积的方法求解&#xff0c;依据原理是使用内积求出直线x2x1 与 直线x3x1的夹角cos值&#xff0c;进而求出sin值&#xff0c;再求出x1到x2x3的距离。这种方法的不足之处是&#xff0c;当三点之…

新CalendarFX视图:MonthGridView!

我和我的团队最近开始为CalendarFX创建新视图&#xff0c;其最初目标是在垂直列中显示整年。 该视图的名称是MonthGridView。 像往常一样&#xff0c;编码时目标略有变化。 该视图现在可以显示任意数量的月份&#xff0c;并且可以在前面或后面添加额外的月份。 现在&#xff0c…