一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第17天,点击查看活动详情。
一、前言
在目前流行的前后端分离的软件项目中,JSON格式的数据交互是业界标准,后端开发一般要和前端约定好返回的数据格式,提高接口联调及整个软件项目的开发效率。
二、JSON格式
{
"code":200 #响应代码
"message": "成功", # 响应信息
"data": { # 返回的数据
}
}
三、代码实现
定义接口
package com.example.jenkins.entity;
/**
* @Author :
* @Description :
* @Date 2022-3-15 23:05
**/
public interface BaseResultInterface {
/**
* 响应码
* @return
*/
String getResultCode();
/**
* 错误描述
* @return
*/
String getResultMsg();
}
定义枚举类
枚举类实现上面接口,统一定义返回状态码,和返回信息一一对应,我们可以约定xxx~xxx 为什么错误码,防止后期错误码重复,使用混乱不清楚,
package com.example.jenkins.entity;
/**
* @Author : guo yong
* @Description :
* @Date 2022-3-17 21:19
**/
public enum ResultCode implements BaseResultInterface {
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*/
private Integer code;
private String message;
ResultCode(int code, String message) {
this.code = code;
this.message = message;
}
@Override
public String getResultCode() {
return this.code.toString();
}
@Override
public String getResultMsg() {
return this.message;
}
}
定义返回对象
定义统一的返回对象包括code、message、data,其中code,和message都从定义的状态枚举中获取
这里有两个需要注意地方数据类型T data返回的是泛型类型而不是object类型,并且返回对象实现了Serializable接口
package com.example.jenkins.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @Author :
* @Description :
* @Date 2022-3-15 23:04
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResultResponse <T> implements Serializable {
/**
* 响应代码
*/
private String code;
/**
* 响应消息
*/
private String message;
/**
* 响应结果
*/
private T data;
public ResultResponse(BaseResultInterface errorInfo) {
this.code = errorInfo.getResultCode();
this.message = errorInfo.getResultMsg();
}
public static ResultResponse success(){
ResultResponse resultResponse = new ResultResponse(ResultCode.SUCCESS);
return resultResponse;
}
public static<T> ResultResponse success(T t){
ResultResponse resultResponse = success();
resultResponse.setData(t);
return resultResponse;
}
public static ResultResponse failure(BaseResultInterface resultCode){
ResultResponse resultResponse = new ResultResponse(resultCode);
return resultResponse;
}
public static<T> ResultResponse failure(BaseResultInterface resultCode, T t){
ResultResponse resultResponse = failure(resultCode);
resultResponse.setData(t);
return resultResponse;
}
}
这样在controller中很方便返回统一api格式了,如下所示:
@RestController //默认全部返回json
@RequestMapping("/user")
public class UserController {
@GetMapping("/list")
public Result getUserInfo(){
User u=new User();
u.setUserId("1");
u.setUsername("apple");
u.setPassword("abcd1234");
return ResultResponse.success(u);
}
}
如果按照这样开发,每个controller中的方法如果需要返回都写 ResultResponse.success(u) 这句代码,能否进一步优化,对controller中的返回信息统一处理,controller中返回实际对象,对响应信息统一包装返回ResultResponse,答案是肯定的
四、优化处理
自定义注解
/**
* @Author :
* @Description :
* @Date 2022-3-17 22:26
**/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface SpringBootRestController {
}
实现接口
实现ResponseBodyAdvice接口,在响应信息返回之前对响应进行统一包装
/**
* @Author :
* @Description :
* @Date 2022-3-17 22:04
**/
@Slf4j
@RestControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
System.out.println(aClass.getName());
//判断是否使用了自定义注解
if(methodParameter.getDeclaringClass().isAnnotationPresent(SpringBootRestController.class)){
return true;
}
return false;
}
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
if (o instanceof ResultResponse) {
return o;
} else if (o instanceof String) {
// string类型返回要单独json序列化返回一下,不然会报转换异常
return JSON.toJSONString(ResultResponse.success(o));
} else {
return ResultResponse.success(o);
}
}
}
使用自定义注解
在controller中使用自定义注解,无需每个方法都返回ResultResponse
@SpringBootRestController //默认全部返回json
@RequestMapping("/user")
public class UserController {
@GetMapping("/list")
public User getUserInfo(){
User u=new User();
u.setUserId("1");
u.setUsername("apple");
u.setPassword("abcd1234");
return u; //返回user对象,无需每次都把返回的对象进行封装
}
}