BindingAwareModelMap
注意:它和普通ModelMap
的区别是:它能感知数据校验结果(如果放进来的key存在对应的绑定结果,并且你的value不是绑定结果本身。那就移除掉MODEL_KEY_PREFIX
+ key这个key的键值对~)
public class BindingAwareModelMap extends ExtendedModelMap { // 注解复写了Map的put方法,一下子就拦截了所有的addAttr方法。。。 @Override public Object put(String key, Object value) { removeBindingResultIfNecessary(key, value); return super.put(key, value); } @Override public void putAll(Map<? extends String, ?> map) { map.forEach(this::removeBindingResultIfNecessary); super.putAll(map); } // 本类处理的逻辑: private void removeBindingResultIfNecessary(Object key, Object value) { // key必须是String类型才会给与处理 if (key instanceof String) { String attributeName = (String) key; if (!attributeName.startsWith(BindingResult.MODEL_KEY_PREFIX)) { String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + attributeName; BindingResult bindingResult = (BindingResult) get(bindingResultKey); // 如果有校验结果,并且放进来的value值不是绑定结果本身,那就移除掉绑定结果(相当于覆盖掉) if (bindingResult != null && bindingResult.getTarget() != value) { remove(bindingResultKey); } } } } }
Spring MVC默认使用的就是这个ModelMap,但它提供的感知功能大多数情况下我们都用不着。不过反正也不用你管,乖乖用着呗
ModelAndView
顾名思义,ModelAndView指模型和视图的集合,既包含模型又包含视图;ModelAndView一般可以作为Controller的返回值,所以它的实例是开发者自己手动创建的,这也是它和上面的主要区别(上面都是容器创建,然后注入给我们使用的~)。
因为这个类是直接面向开发者的,所以建议里面的一些API还是要熟悉点较好:
public class ModelAndView { @Nullable private Object view; // 可以是View,也可以是String @Nullable private ModelMap model; // 显然,你也可以自己就放置好一个http状态码进去 @Nullable private HttpStatus status; // 标记这个实例是否被调用过clear()方法~~~ private boolean cleared = false; // 总共这几个属性:它提供的构造函数非常的多 这里我就不一一列出 public void setViewName(@Nullable String viewName) { this.view = viewName; } public void setView(@Nullable View view) { this.view = view; } @Nullable public String getViewName() { return (this.view instanceof String ? (String) this.view : null); } @Nullable public View getView() { return (this.view instanceof View ? (View) this.view : null); } public boolean hasView() { return (this.view != null); } public boolean isReference() { return (this.view instanceof String); } // protected方法~~~ @Nullable protected Map<String, Object> getModelInternal() { return this.model; } public ModelMap getModelMap() { if (this.model == null) { this.model = new ModelMap(); } return this.model; } // 操作ModelMap的一些方法如下: // addObject/addAllObjects public void clear() { this.view = null; this.model = null; this.cleared = true; } // 前提是:this.view == null public boolean isEmpty() { return (this.view == null && CollectionUtils.isEmpty(this.model)); } // 竟然用的was,歪果仁果然严谨 哈哈 public boolean wasCleared() { return (this.cleared && isEmpty()); } }
很多人疑问:为何Controller的处理方法不仅仅可以返回ModelAndView,还可以通过返回Map/Model/ModelMap等来直接向页面传值呢???如果返回值是后三者,又是如何找到view完成渲染的呢?
这个问题我抛出来,本文不给答案。因为都聊到这了,此问题应该不算难的了,建议小伙伴必须自行弄懂缘由(请不要放过有用的知识点)。若实在有不懂之处可以给留言我会帮你解答的~
答案参考提示:可参阅ModelMethodProcessor和ModelMethodProcessor对返回值的处理模块
绝大多数情况下,我都建议返回ModelAndView,而不是其它那哥三。因为它哥三都没有指定视图名,所以通过DispatcherServlet.applyDefaultViewName()生成的视图名一般都不是我们需要的。(除非你的目录、命名等等都特别特别的规范,那顺便倒是可以省不少事~~~)
ModelFactory
关于ModelFactory它的介绍,这篇文章 里算是已经详细讲解过了,这里再简述两句它的作用。
ModelFactory是用来维护Model的,具体包含两个功能
- 初始化Model
- 处理器执行后将Model中相应的参数更新到SessionAttributes中(处理@ModelAttribute和@SessionAttributes)
总结
本以为本文不会很长的,没想到还是写成了超10000字的中篇文章。希望这篇文章能够帮助你对Spring MVC对模型、视图这块核心内容的理解,帮你扫除途中的一些障碍,共勉~