分享一个优雅处理 Spring Boot 接口响应的 Java 库,提供一站式统一返回值封装、全局异常处理、自定义异常错误码等功能,求 star - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
feiniaojin
V2EX    程序员

分享一个优雅处理 Spring Boot 接口响应的 Java 库,提供站式统一返回值封装、全局异常处理、自定义异常错误码等功能,求 star

  •  1
     
  •   feiniaojin 2023-11-23 00:15:59 +08:00 1168 次点击
    这是一个创建于 703 天前的主题,其中的信息可能已经有所发展或是发生改变。

    简介

    Graceful Response 是一个 Spring Boot 体系下的优雅响应处理器,提供一站式统一返回值封装、全局异常处理、自定义异常错误码等功能,使用 Graceful Response 进行 web 接口开发不仅可以节省大量的时间,还可以提高代码质量,使代码逻辑更清晰。

    零学习门槛,十秒钟上手!

    GitHub 仓库地址: https://github.com/feiniaojin/graceful-response

    欢迎试用和 star!

    Spring Boot 接口开发现状

    目前,业界使用 Spring Boot 进行接口开发时,往往存在效率底下、重复劳动、可读性差等问题。以下伪代码相信大家非常熟悉,我们大部分项目的 Controller 接口都是这样的。

    @Controller public class Controller { @GetMapping("/query") @ResponseBody public Response query(Map<String,Object> paramMap) { Response res = new Response(); try { //1.校验 params 参数合法性,包括非空校验、长度校验等 if (illegal(paramMap)) { res.setCode(1); res.setMsg("error"); return res; } //2.调用 Service 的一系列操作,得到查询结果 Object data = service.query(params); //3.将操作结果设置到 res 对象中 res.setData(data); res.setCode(0); res.setMsg("ok"); return res; }catch (Exception e) { //4.异常处理:一堆丑陋的 try...catch ,如果有错误码的,还需要手工填充错误码 res.setCode(1); res.setMsg("error"); return res; } } } 

    这段伪代码存在什么样的问题呢?

    第一个问题,效率低下。Controller 层的代码应该尽量简洁,上面的伪代码其实只是为了将数据查询的结果进行封装,使其以统一的格式进行返回。例如以下格式的响应体:

    { "code": 0, "msg": "ok", "data": { "id": 1, "name": "username" } } 

    查询过程中如果发生异常,需要在 Controller 进行手工捕获,根据捕获的异常人工地设置错误码,当然,也用同样的格式封装错误码进行返回。

    可以看到,除了调用 service 层的 query 方法这一行,其他大部分的代码都执行进行结果的封装,大量的冗余、低价值的代码导致我们的开发活动效率很低。

    第二个问题,重复劳动。以上捕获异常、封装执行结果的操作,每个接口都会进行一次,因此造成大量重复劳动。

    第三个问题,可读性低。上面的核心代码被淹没在许多冗余代码中,很难阅读,如同大海捞针。

    我们可以通过 Graceful Response 这个组件解决这样的问题。

    快速入门

    引入 Graceful Response 组件

    Graceful Response 已发布至 maven 中央仓库,我们可以直接引入到项目中。

    maven 依赖如下:

    <dependency> <groupId>com.feiniaojin</groupId> <artifactId>graceful-response</artifactId> <version>{latest.version}</version> </dependency> 
    Spring Boot 版本 Graceful Response 版本
    2.x 3.2.0-boot2
    3.x 3.2.0-boot3

    启用 Graceful Response

    在启动类中引入 @EnableGracefulResponse 注解,即可启用 Graceful Response 组件。

    @EnableGracefulResponse @SpringBootApplication public class ExampleApplication { public static void main(String[] args) { SpringApplication.run(ExampleApplication.class, args); } } 

    Controller 层

    引入 Graceful Response 后,我们不需要再手工进行查询结果的封装,直接返回实际结果即可,Graceful Response 会自动完成封装的操作。

    Controller 层示例如下。

    @Controller public class Controller { @RequestMapping("/get") @ResponseBody public UserInfoView get(Long id) { log.info("id={}", id); return UserInfoView.builder().id(id).name("name" + id).build(); } } 

    在示例代码中,Controller 层的方法直接返回了 UserInfoView 对象,没有进行封装的操作,但经过 Graceful Response 处理后,我们还是得到了以下的响应结果。

    { "status": { "code": "0", "msg": "ok" }, "payload": { "id": 1, "name": "name1" } } 

    而对于命令操作( Command )尽量不返回数据,因此 command 操作的方法的返回值应该是 void ,Graceful Response 对于对于返回值类型 void 的方法,也会自动进行封装。

    public class Controller { @RequestMapping("/command") @ResponseBody public void command() { //业务操作 } } 

    成功调用该接口,将得到:

    { "status": { "code": "200", "msg": "success" }, "payload": {} } 

    Service 层

    在引入 Graceful Response 前,有的开发者在定义 Service 层的方法时,为了在接口中返回异常码,干脆直接将 Service 层方法定义为 Response ,淹没了方法的正常返回值。

    Response 的代码如下。

    //lombok 注解 @Data public class Response { private String code; private String msg; private Object data; } 

    直接返回 Response 的 Service 层方法:

    /** * 直接返回 Reponse 的 Service * 不规范 */ public interface Service{ public Reponse commandMethod(Command command); } 

    Graceful Response 引入 @ExceptionMapper 注解,通过该注解将异常和错误码关联起来,这样 Service 方法就不需要再维护 Response 的响应码了,直接抛出业务异常,由 Graceful Response 进行异常和响应码的关联。 @ExceptionMapper 的用法如下。

    /** * NotFoundException 的定义,使用 @ExceptionMapper 注解修饰 * code:代表接口的异常码 * msg:代表接口的异常提示 */ @ExceptionMapper(code = "1404", msg = "找不到对象") public class NotFoundException extends RuntimeException { } 

    Service 接口定义:

    public interface QueryService { UserInfoView queryOne(Query query); } 

    Service 接口实现:

    public class QueryServiceImpl implements QueryService { @Resource private UserInfoMapper mapper; public UserInfoView queryOne(Query query) { UserInfo userInfo = mapper.findOne(query.getId()); if (Objects.isNull(userInfo)) { //这里直接抛自定义异常 throw new NotFoundException(); } //……后续业务操作 } } 

    当 Service 层的 queryOne 方法抛出 NotFoundException 时,Graceful Response 会进行异常捕获,并将 NotFoundException 对应的异常码和异常信息封装到统一的响应对象中,最终接口返回以下 JSON 。

    { "status": { "code": "1404", "msg": "找不到对象" }, "payload": {} } 

    参数校验

    Graceful Response 对 JSR-303 数据校验规范和 Hibernate Validator 进行了增强,Graceful Response 自身不提供参数校验的功能,但是用户使用了 Hibernate Validator 后,Graceful Response 可以通过 @ValidationStatusCode 注解为参数校验结果提供响应码,并将其统一封装返回。

    例如以下的 UserInfoQuery 。

    @Data public class UserInfoQuery { @NotNull(message = "userName is null !") @Length(min = 6, max = 12) @ValidationStatusCode(code = "520") private String userName; } 

    UserInfoQuery 对象中定义了 @NotNull 和 @Length 两个校验规则,在未引入 Graceful Response 的情况下,会直接抛出异常;

    在引入 Graceful Response 但是没有加入 @ValidationStatusCode 注解的情况下,会以默认的错误码进行返回;

    在上面的 UserInfoQuery 中由于使用了 @ValidationStatusCode 注解,并指定异常码为 520 ,则当 userName 字段任意校验不通过时,都会使用异常码 520 进行返回,如下。

    { "status": { "code": "520", "msg": "userName is null !" }, "payload": {} } 

    而对于 Controller 层直接校验方法入参的场景,Graceful Response 也进行了增强,如以下 Cntroller 。

    public class Controller { @RequestMapping("/validateMethodParam") @ResponseBody @ValidationStatusCode(code = "1314") public void validateMethodParam( @NotNull(message = "userId 不能为空") Long userId, @NotNull(message = "userName 不能为空") Long userName){ //省略业务逻辑 } } 

    如果该方法入参校验触发了 userId 和 userName 的校验异常,将以错误码 1314 进行返回,如下。

    { "status": { "code": "1314", "msg": "userId 不能为空" }, "payload": {} } 

    自定义 Response 格式

    Graceful Response 内置了两种风格的响应格式,并通过 graceful-response.response-style 进行配置。

    graceful-response.response-style=0 ,或者不配置(默认情况),将以以下的格式进行返回:

    { "status": { "code": 1007, "msg": "有内鬼,终止交易" }, "payload": { } } 

    graceful-response.response-style=1 ,将以以下的格式进行返回:

    { "code": "1404", "msg": "not found", "data": { } } 

    如果这两种格式均不满足业务需要,Graceful Response 也支持用户自定义响应体,关于自定义响应体的技术实现,请到 https://github.com/feiniaojin/graceful-response 进行了解。

    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2502 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 09:51 PVG 17:51 LAX 02:51 JFK 05:51
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86