-
springboot 默认情况下的返回数据类型包括以下几种:
-
String型 :返回字符串
@GetMapping(value="/getstr/{id}") public String getstr(@PathVariable("id") Integer id){ ... return "index"; }
-
Object型:返回一个Json表示对象
@GetMapping(value="/getObject") public UserVO getObject(){ UserVO vo=new UserVO(); vo.setUsername("agan"); return vo; }
-
void型:返回空值
@GetMapping(value="/empty") public void empty(){ }
-
Exception型:返回错误信息或异常信息
@GetMapping(value="/error") public void error( ){ int i=9/0; }
如下:
{ "timestamp": "2019-09-07T10:35:56.658+0000", "status": 500, "error": "Internal Server Error", "message": "/ by zero", "path": "/user/error" }
-
若是所有的接口按照以上四种方式实现,当你和客户端开发人员联调接口,会造成很大的麻烦,因为这些接口返回值没有统一的格式,客户端开发人员处理返回值将无从下手。
所以我们应该统一 response 标准格式。
-
对 response 代码封装(使用一个网上的常用案例)
-
创建用于统一处理返回值的 ApiResult 类
// 这是我们需要返回的内容 { "status":0, // 状态码 "desc":"成功", // 状态信息 "data":"test" // 返回值 }
开始转换后成一个 Result 处理类
public class ApiResult<T>{ // status:状态码 private Integer status; // desc:对状态码的描述 private String desc; // data:采用泛型,表示返回值 private T data; /*构造函数 + getter + setter 太多了,这里我就省略掉了,自己试验的时候记着补上*/ // 成功创建Result,没有data值 public static ApiResult suc(){ ApiResult result = new ApiResult(); result.setResultCode(ResultCode.SUCCESS); return result; } // 成功创建Result,有data值 public static ApiResult suc(Object data){ ApiResult result = new ApiResult(); result.setResultCode(ResultCode.SUCCESS); result.setData(data); return result; } // 失败,指定status,desc public static Result fail(Integer status, String desc) { Result result = new Result(); result.setStatus(status); result.setDesc(desc); return result; } // 失败,指定ResultCode枚举 public static Result fail(ResultCode resultCode) { Result result = new Result(); result.setResultCode(resultCode); return result; } // 把ResultCode枚举转换为ResResult private void setResultCode(ResultCode code) { this.status = code.code(); this.desc = code.message(); } }
创建状态码枚举类:相关的 Code 和 desc 可以自定义一个格式。
public enum ResultCodeEnum { // 成功状态码 SUCCESS("000", "操作成功"), SYSTEM_ERROR("001", "系统异常,请稍后重试"), UNAUTHORIZED("002", "验证失败"), PARAM_IS_INVALID("003", "参数无效"), USER_HAS_EXISTED("004", "用户名已存在"), USER_NOT_FIND("005", "用户名不存在"); private String code; private String message; private ResultCodeEnum(String code, String message) { this.code = code; this.message = message; } public String code() { return this.code; } public String message() { return this.message; } }
测试类:
@RestController @RequestMapping("/user") public class UserController { @GetMapping(value="/getResult") public Result getResult( ){ return Result.suc("test"); } }
-
最终浏览器接收到的结果是一个 JSON 格式的字符串,做相应处理就好。
-
对于这种封装风格的进一步优化:
-
为了方便理解,这里我们可以带入 Spring AOP 的思想,可以看到如果 Controller 中的接口处理方法增多,我们将对每一个接口的返回值手动的调用 Result.suc() 统一处理方法。那么我们可以把这些重复出现的代码当做 AOP 中的 横切逻辑代码通过注解的方式,省去这部分代码。
-
这里我们需要去实现 ResponseBodyAdvice 这个接口,它会拦截 Controller 方法的返回值,统一处理返回值/响应体,一般用来做 response 的统一格式、加解密、签名等等。
-
另外,我们还需要给 ResponseBodyAdvice实现类 加上注解 @ControllerAdvice 这个注解的作用是增强 Controller 的拓展功能类,包括两个方面的增强:
- 对 Controller 的全局数据进行统一处理
- 对 Controller 的全局异常进行统一处理
ResponseBodyAdvice 实现类代码:
@ControllerAdvice(basePackages = "com.miger.module.controller") // backPackages属性是用于定位controller的位置 public class RrsultAdvice implements ResponseBodyAdvice<Object> { // 确认是否支持 advice 功能,true 表示支持,false 表示不支持 @Override public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) { return true; } // 处理 response 的具体业务的方法 @Override public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { if (o instanceof String) { return JSON.toJSONString(ApiResult.suc(o)); } return ApiResult.suc(o); } }
-
参考链接:https://blog.youkuaiyun.com/shenhuxi10000/article/details/104622770/