Spring Boot 中如何统一 API 接口响应格式?( 二 )

AsyncTaskMethodReturnValueHandler
这个用来处理返回值类型为 WebAsyncTask 的情况 。
HandlerMethodReturnValueHandlerComposite
看 Composite 就知道,这是一个组合处理器,没啥好说的 。
这个就是系统默认定义的 HandlerMethodReturnValueHandler 。
那么在上面的介绍中,大家看到反复涉及到一个组件 mavContainer,这个我也要和大家介绍一下 。
2.ModelAndViewContainerModelAndViewContainer 就是一个数据穿梭巴士,在整个请求的过程中承担着数据传送的工作,从它的名字上我们可以看出来它里边保存着 Model 和 View 两种类型的数据,但是实际上可不止两种,我们来看下 ModelAndViewContainer 的定义:
public class ModelAndViewContainer { private boolean ignoreDefaultModelOnRedirect = false; @Nullable private Object view; private final ModelMap defaultModel = new BindingAwareModelMap(); @Nullable private ModelMap redirectModel; private boolean redirectModelScenario = false; @Nullable private HttpStatus status; private final Set<String> noBinding = new HashSet<>(4); private final Set<String> bindingDisabled = new HashSet<>(4); private final SessionStatus sessionStatus = new SimpleSessionStatus(); private boolean requestHandled = false;}把这几个属性理解了,基本上也就整明白 ModelAndViewContainer 的作用了:

  • defaultModel:默认使用的 Model 。当我们在接口参数重使用 Model、ModelMap 或者 Map 时,最终使用的实现类都是 BindingAwareModelMap,对应的也都是 defaultModel 。
  • redirectModel:重定向时候的 Model,如果我们在接口参数中使用了 RedirectAttributes 类型的参数,那么最终会传入 redirectModel 。
可以看到,一共有两个 Model,两个 Model 到底用哪个呢?这个在 getModel 方法中根据条件返回合适的 Model:
public ModelMap getModel() { if (useDefaultModel()) {  return this.defaultModel; } else {  if (this.redirectModel == null) {   this.redirectModel = new ModelMap();  }  return this.redirectModel; }}private boolean useDefaultModel() { return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect));}这里 redirectModelScenario 表示处理器是否返回 redirect 视图;ignoreDefaultModelOnRedirect 表示是否在重定向时忽略 defaultModel,所以这块的逻辑是这样:
  1. 如果 redirectModelScenario 为 true,即处理器返回的是一个重定向视图,那么使用 redirectModel 。如果 redirectModelScenario 为 false,即处理器返回的不是一个重定向视图,那么使用 defaultModel 。
  2. 如果 redirectModel 为 null,并且 ignoreDefaultModelOnRedirect 为 false,则使用 redirectModel,否则使用 defaultModel 。
接下来还剩下如下一些参数:
  • view:返回的视图 。
  • status:HTTP 状态码 。
  • noBinding:是否对 @ModelAttribute(binding=true/false) 声明的数据模型的相应属性进行绑定 。
  • bindingDisabled:不需要进行数据绑定的属性 。
  • sessionStatus:SessionAttribute 使用完成的标识 。
  • requestHandled:请求处理完成的标识(例如添加了 @ResponseBody 注解的接口,这个属性为 true,请求就不会再去找视图了) 。
?
这个 ModelAndViewContainer 小伙伴们权且做一个了解,松哥在后面的源码分析中,还会和大家再次聊到这个组件 。
接下来我们也来自定义一个 HandlerMethodReturnValueHandler,来感受一下 HandlerMethodReturnValueHandler 的基本用法 。
3.API 接口数据包装假设我有这样一个需求:我想在原始的返回数据外面再包裹一层,举个简单例子,本来接口是下面这样:
@RestControllerpublic class UserController {    @GetMApping("/user")    public User getUserByUsername(String username) {        User user = new User();        user.setUsername(username);        user.setAddress("www.JAVAboy.org");        return user;    }}


推荐阅读