一、前言
在目前流行的前后端分离的软件项目中,JSON格式的数据交互是业界标准,后端开发一般要和前端约定好返回的数据格式,提高接口联调及整个软件项目的开发效率。
二、JSON格式
{ "code":200#响应代码"message": "成功", #响应信息"data": { #返回的数据 } }
三、代码实现
定义接口
packagecom.example.jenkins.entity; /*** @Author : * @Description :* @Date 2022-3-15 23:05**/publicinterfaceBaseResultInterface { /*** 响应码* @return*/StringgetResultCode(); /*** 错误描述* @return*/StringgetResultMsg(); }
定义枚举类
枚举类实现上面接口,统一定义返回状态码,和返回信息一一对应,我们可以约定xxx~xxx 为什么错误码,防止后期错误码重复,使用混乱不清楚
packagecom.example.jenkins.entity; /*** @Author : guo yong* @Description :* @Date 2022-3-17 21:19**/publicenumResultCodeimplementsBaseResultInterface { SUCCESS(200, "成功"),//成功//FAIL(400, "失败"),//失败BAD_REQUEST(400, "Bad Request"), UNAUTHORIZED(401, "认证失败"),//未认证NOT_FOUND(404, "接口不存在"),//接口不存在INTERNAL_SERVER_ERROR(500, "系统繁忙"),//服务器内部错误METHOD_NOT_ALLOWED(405,"方法不被允许"), /*参数错误:1001-1999*/PARAMS_IS_INVALID(1001, "参数无效"), PARAMS_IS_BLANK(1002, "参数为空"); /*用户错误2001-2999*/privateIntegercode; privateStringmessage; ResultCode(intcode, Stringmessage) { this.code=code; this.message=message; } publicStringgetResultCode() { returnthis.code.toString(); } publicStringgetResultMsg() { returnthis.message; } }
定义返回对象
定义统一的返回对象包括code、message、data,其中code,和message都从定义的状态枚举中获取
这里有两个需要注意地方数据类型T data返回的是泛型类型而不是object类型,并且返回对象实现了Serializable接口
packagecom.example.jenkins.entity; importlombok.AllArgsConstructor; importlombok.Data; importlombok.NoArgsConstructor; importjava.io.Serializable; /*** @Author : * @Description :* @Date 2022-3-15 23:04**/publicclassResultResponse<T>implementsSerializable { /*** 响应代码*/privateStringcode; /*** 响应消息*/privateStringmessage; /*** 响应结果*/privateTdata; publicResultResponse(BaseResultInterfaceerrorInfo) { this.code=errorInfo.getResultCode(); this.message=errorInfo.getResultMsg(); } publicstaticResultResponsesuccess(){ ResultResponseresultResponse=newResultResponse(ResultCode.SUCCESS); returnresultResponse; } publicstatic<T>ResultResponsesuccess(Tt){ ResultResponseresultResponse=success(); resultResponse.setData(t); returnresultResponse; } publicstaticResultResponsefailure(BaseResultInterfaceresultCode){ ResultResponseresultResponse=newResultResponse(resultCode); returnresultResponse; } publicstatic<T>ResultResponsefailure(BaseResultInterfaceresultCode, Tt){ ResultResponseresultResponse=failure(resultCode); resultResponse.setData(t); returnresultResponse; } }
这样在controller中很方便返回统一api格式了,如下所示:
//默认全部返回json"/user") (publicclassUserController { "/list") (publicResultgetUserInfo(){ Useru=newUser(); u.setUserId("1"); u.setUsername("apple"); u.setPassword("abcd1234"); returnResultResponse.success(u); } }
如果按照这样开发,每个controller中的方法如果需要返回都写 ResultResponse.success(u)
这句代码,能否进一步优化,对controller中的返回信息统一处理,controller中返回实际对象,对响应信息统一包装返回ResultResponse,答案是肯定的
四、优化处理
自定义注解
/*** @Author :* @Description :* @Date 2022-3-17 22:26**/ElementType.TYPE,ElementType.METHOD}) ({RetentionPolicy.RUNTIME) (public@interfaceSpringBootRestController { }
实现接口
实现ResponseBodyAdvice接口,在响应信息返回之前对响应进行统一包装
/*** @Author : * @Description :* @Date 2022-3-17 22:04**/publicclassResponseResultHandlerimplementsResponseBodyAdvice { publicbooleansupports(MethodParametermethodParameter, ClassaClass) { System.out.println(aClass.getName()); //判断是否使用了自定义注解if(methodParameter.getDeclaringClass().isAnnotationPresent(SpringBootRestController.class)){ returntrue; } returnfalse; } publicObjectbeforeBodyWrite(Objecto, MethodParametermethodParameter, MediaTypemediaType, ClassaClass, ServerHttpRequestserverHttpRequest, ServerHttpResponseserverHttpResponse) { if (oinstanceofResultResponse) { returno; } elseif (oinstanceofString) { // string类型返回要单独json序列化返回一下,不然会报转换异常returnJSON.toJSONString(ResultResponse.success(o)); } else { returnResultResponse.success(o); } } }
使用自定义注解
在controller中使用自定义注解,无需每个方法都返回ResultResponse
//默认全部返回json"/user") (publicclassUserController { "/list") (publicUsergetUserInfo(){ Useru=newUser(); u.setUserId("1"); u.setUsername("apple"); u.setPassword("abcd1234"); returnu; //返回user对象,无需每次都把返回的对象进行封装 } }