首页 文章资讯内容详情

springboot之全局处理统一返回

2026-06-01 4 花语

本文内容纲要:

-springboot之全局处理统一返回 -简介 -配置 -总结

springboot之全局处理统一返回

简介

在REST风格的开发中,避免通常会告知前台返回是否成功以及状态码等信息。这里我们通常返回的时候做一次util的包装处理工作,如:Result类似的类,里面包含succ、code、msg、data等字段。

接口调用返回类似如下:

{ "succ":false,//是否成功 "ts":1566467628851,//时间戳 "data":null,//数据 "code":"CLOUD800",//错误类型 "msg":"业务异常",//错误描述 "fail":true }

当然在每个接口里返回要通过Result的工具类将这些信息给封装一下,这样导致业务和技术类的代码耦合在一起。

接口调用处理类似如下:

@GetMapping("hello") publicResultlist(){ returnResult.ofSuccess("hello"); }

结果:

{ "succ":ture,//是否成功 "ts":1566467628851,//时间戳 "data":"hello",//数据 "code":null,//错误类型 "msg":null,//错误描述 "fail":true }

我们将这些操抽出一个公共starter包,各个服务依赖即可,做一层统一拦截处理的工作,进行技术解耦。

配置

unified-dispose-springboot-starter

这个模块里包含异常处理以及全局返回封装等功能,下面。

完整目录结构如下:

├──pom.xml ├──src │ ├──main │ │ ├──java │ │ │ └──com │ │ │ └──purgetiem │ │ │ └──starter │ │ │ └──dispose │ │ │ ├──GlobalDefaultConfiguration.java │ │ │ ├──GlobalDefaultProperties.java │ │ │ ├──Interceptors.java │ │ │ ├──Result.java │ │ │ ├──advice │ │ │ │ └──CommonResponseDataAdvice.java │ │ │ ├──annotation │ │ │ │ ├──EnableGlobalDispose.java │ │ │ │ └──IgnorReponseAdvice.java │ │ │ └──exception │ │ │ ├──GlobalDefaultExceptionHandler.java │ │ │ ├──category │ │ │ │ └──BusinessException.java │ │ │ └──error │ │ │ ├──CommonErrorCode.java │ │ │ └──details │ │ │ └──BusinessErrorCode.java │ │ └──resources │ │ ├──META-INF │ │ │ └──spring.factories │ │ └──dispose.properties │ └──test │ └──java

统一返回处理

按照一般的模式,我们都需要创建一个可以进行处理包装的工具类以及一个返回对象。

Result(返回类):

创建Result<T>T为data的数据类型,这个类包含了前端常用的字段,还有一些常用的静态初始化Result对象的方法。

/** *返回统一数据结构 * *@authorpurgeyao *@since1.0 */ @Data @ToString @NoArgsConstructor @AllArgsConstructor publicclassResult<T>implementsSerializable{ /** *是否成功 */ privateBooleansucc; /** *服务器当前时间戳 */ privateLongts=System.currentTimeMillis(); /** *成功数据 */ privateTdata; /** *错误码 */ privateStringcode; /** *错误描述 */ privateStringmsg; publicstaticResultofSuccess(){ Resultresult=newResult(); result.succ=true; returnresult; } publicstaticResultofSuccess(Objectdata){ Resultresult=newResult(); result.succ=true; result.setData(data); returnresult; } publicstaticResultofFail(Stringcode,Stringmsg){ Resultresult=newResult(); result.succ=false; result.code=code; result.msg=msg; returnresult; } publicstaticResultofFail(Stringcode,Stringmsg,Objectdata){ Resultresult=newResult(); result.succ=false; result.code=code; result.msg=msg; result.setData(data); returnresult; } publicstaticResultofFail(CommonErrorCoderesultEnum){ Resultresult=newResult(); result.succ=false; result.code=resultEnum.getCode(); result.msg=resultEnum.getMessage(); returnresult; } /** *获取json */ publicStringbuildResultJson(){ JSONObjectjsonObject=newJSONObject(); jsonObject.put("succ",this.succ); jsonObject.put("code",this.code); jsonObject.put("ts",this.ts); jsonObject.put("msg",this.msg); jsonObject.put("data",this.data); returnJSON.toJSONString(jsonObject,SerializerFeature.DisableCircularReferenceDetect); } }

这样已经满足一般返回处理的需求了,在接口可以这样使用:

@GetMapping("hello") publicResultlist(){ returnResult.ofSuccess("hello"); }

当然这样是耦合的使用,每次都需要调用Result里的包装方法。

ResponseBodyAdvice返回统一拦截处理

ResponseBodyAdvice在spring4.1新加入的一个接口,在消息体被HttpMessageConverter写入之前允许Controller中@ResponseBody修饰的方法或ResponseEntity调整响应中的内容,比如做一些返回处理。

ResponseBodyAdvice接口里一共包含了两个方法

supports:该组件是否支持给定的控制器方法返回类型和选择的{@codeHttpMessageConverter}类型 beforeBodyWrite:在选择{@codeHttpMessageConverter}之后调用,在调用其写方法之前调用。

那么我们就可以在这两个方法做一些手脚。

supports用于判断是否需要做处理。 beforeBodyWrite用于做返回处理。

CommonResponseDataAdvice类实现ResponseBodyAdvice两个方法。

filter(MethodParametermethodParameter)私有方法里进行判断是否要进行拦截统一返回处理。

如:

添加自定义注解@IgnorReponseAdvice忽略拦截。 判断某些类不进行拦截. 判断某些包下所有类不进行拦截。如swagger的springfox.documentation包下的接口忽略拦截等。

filter方法: 判断为false就不需要进行拦截处理。

privateBooleanfilter(MethodParametermethodParameter){ Class<?>declaringClass=methodParameter.getDeclaringClass(); //检查过滤包路径 longcount=globalDefaultProperties.getAdviceFilterPackage().stream() .filter(l->declaringClass.getName().contains(l)).count(); if(count>0){ returnfalse; } //检查<类>过滤列表 if(globalDefaultProperties.getAdviceFilterClass().contains(declaringClass.getName())){ returnfalse; } //检查注解是否存在 if(methodParameter.getDeclaringClass().isAnnotationPresent(IgnorReponseAdvice.class)){ returnfalse; } if(methodParameter.getMethod().isAnnotationPresent(IgnorReponseAdvice.class)){ returnfalse; } returntrue; }

CommonResponseDataAdvice类:

最核心的就在beforeBodyWrite方法处理里。

判断Objecto是否为null,为null构建Result对象进行返回。

判断Objecto是否是Result子类或其本身,该情况下,可能是接口返回时创建了Result,为了避免再次封装一次,判断是Result子类或其本身就返回Objecto本身。

判断Objecto是否是为String,在测试的过程中发现String的特殊情况,在这里做了一次判断操作,如果为String就进行JSON.toJSON(Result.ofSuccess(o)).toString()序列号操作。

其他情况默认返回Result.ofSuccess(o)进行包装处理。

/**

{@linkIgnorReponseAdvice}处理解析{@linkResponseBodyAdvice}统一返回包装器 @authorpurgeyao @since1.0 */ @RestControllerAdvice publicclassCommonResponseDataAdviceimplementsResponseBodyAdvice{

privateGlobalDefaultPropertiesglobalDefaultProperties;

publicCommonResponseDataAdvice(GlobalDefaultPropertiesglobalDefaultProperties){ this.globalDefaultProperties=globalDefaultProperties; }

@Override @SuppressWarnings("all") publicbooleansupports(MethodParametermethodParameter, Class