ModelAndViewContainer, ModelMap, Model Details [Learning Spring MVC]

Every sentence

How well an open source technology product does depends on how many non-functional problems you can solve (because functional problems are conceivable for all products).

Preface

Writing this article is not my original intention, because I think the understanding of these categories is still a relatively basic and simple piece of content, until more than two students asked me some questions: through chat found that small partners have heard of these categories, but for their use, functional positioning is silly and unclear. Chu's (because there are many similarities in names).
So writing this article is just like a popular science article. It's not necessary to continue reading this article because I'm already familiar with my little buddies, because it's not too difficult (of course, I'm just suggesting).

ModelAndViewContainer

I put this class first because it is a little more logical and helpful in understanding the processing of processor ReturnValue returns.

ModelAndViewContainer: It can be defined as a container for the ModelAndView context, which is responsible for data transfer throughout the request process - > Preserving Models and Views. The official doc interprets it as follows:

Records model and view related decisions made by {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers} and
{@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers} during the course of invocation of a controller method.

Translated into "Mandarin" is to record the model model and view information used by Handler Method ArgumentResolver and Handler Method Return Value Handler in handling handler method of Controller.

Of course, besides saving Model and View, it also provides some other functions. Now let's familiarize ourselves with its API and source code.

// @since 3.1
public class ModelAndViewContainer {
// ================= The attributes it holds are still important.=================
// Whether the defaultModel default value is false when redirect is ignored: not ignored
private boolean ignoreDefaultModelOnRedirect = false;
// This view may be a View or just a logical view String
@Nullable
private Object view;
// Default Model
// Note: ModelMap is just a Map, but the implementation class BindingAware ModelMap implements the org. spring framework. ui. Model interface.
private final ModelMap defaultModel = new BindingAwareModelMap();
// Model used for redirection (provide set method settings)
@Nullable
private ModelMap redirectModel;
// Does the controller return redirection instructions?
// For example, the prefix "redirect:xxx.jsp" is used, and this value is true. And then ultimately a RedirectView
private boolean redirectModelScenario = false;
// Http status code
@Nullable
private HttpStatus status;
private final Set<String> noBinding = new HashSet<>(4);
private final Set<String> bindingDisabled = new HashSet<>(4);
// It's easy to imagine that it's related to the @SessionAttributes tag element
private final SessionStatus sessionStatus = new SimpleSessionStatus();
// This property is always important: whether the tag handler has completed ** request processing
// In chain operation, this markup is very important.
private boolean requestHandled = false;
...
public void setViewName(@Nullable String viewName) {
this.view = viewName;
}
public void setView(@Nullable Object view) {
this.view = view;
}
// Is it a reference to a view?
public boolean isViewReference() {
return (this.view instanceof String);
}
// Whether to use the default Model
private boolean useDefaultModel() {
return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect));
}
// Notice the difference between the submethod and the following getDefaultModel() method
public ModelMap getModel() {
if (useDefaultModel()) { // Use the default view
return this.defaultModel;
} else {
if (this.redirectModel == null) { // If the redirected view is null, an empty new return is made
this.redirectModel = new ModelMap();
}
return this.redirectModel;
}
}
// @since 4.1.4
public ModelMap getDefaultModel() {
return this.defaultModel;
}
// @ since 4.3 can set the response code, which will eventually be used with ModelAndView when rendered by View.
public void setStatus(@Nullable HttpStatus status) {
this.status = status;
}
// Programmatically registering a property that ** should not ** have data binding, and for subsequently declared @ModelAttribute it cannot be bound
// Although the method is set, the inside is add.~~~~
public void setBindingDisabled(String attributeName) {
this.bindingDisabled.add(attributeName);
}
public boolean isBindingDisabled(String name) {
return (this.bindingDisabled.contains(name) || this.noBinding.contains(name));
}
// Whether registration should be data binding for the corresponding model attributes
public void setBinding(String attributeName, boolean enabled) {
if (!enabled) {
this.noBinding.add(attributeName);
} else {
this.noBinding.remove(attributeName);
}
}
// This method needs to focus on whether the request has been fully processed in the handler.
// For example, the @ResponseBody annotated method returns a value that does not require View to continue processing, so you can set the value to true.
// Explanation: This property can achieve the same effect through the source ServletResponse and OutputStream.
public void setRequestHandled(boolean requestHandled) {
this.requestHandled = requestHandled;
}
public boolean isRequestHandled() {
return this.requestHandled;
}
// ========= Here's how Model works==========
// addAttribute/addAllAttributes/mergeAttributes/removeAttributes/containsAttribute
}

After reading the source code intuitively, at least I can get the following conclusions to share with you:

It maintains model models: defaultModle and redirectModel

defaultModel is the default Model, and redirectModel is the Model used to pass redirect.

When the Controller processor enters the Model or ModelMap type, the defaultModel is actually passed in.
- defaultModel is actually a Binding Aware Model, a Map. It also inherits ModelMap and implements the Model interface, so when you use Model or ModelMap in a processor, you actually use the same object.~~~
- Refer to MapMethodProcessor, which ultimately calls the mavContainer.getModel() method

If the processor input type is RedirectAttributes type, the redirectModel is eventually passed in.
- As for why is defaultModel actually passed in? Reference: Redirect Attributes Method ArgumentResolver, using the new Redirect Attributes Model Map (data Binder).

HttpEntityMethodProcessor: The return value type is the method of HttpEntity

// As you can see, this return value is marked as processed so that the view (rendering) is no longer needed.
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
mavContainer.setRequestHandled(true); // The first sentence is this code.
if (returnValue == null) {
return;
}
... // Give it to the message processor to write
outputMessage.flush();
}

The same principle applies to HttpHeaders Return Value Handler/RequestResponseBodyMethod Processor/ResponseBodyEmitter Return Value Handler and so on.

ServletInvocableHandlerMethod/HandlerMethod sometimes annotates that true has been processed when handling Handler methods (e.g. get request NotModified/HttpStatus status code/isRequestHandled()==true and so on). In addition to these case s, when the method method is executed, it will display the false settings (because after the handler method is executed, it needs to be rendered to the view ~)

Servlet Response Method ArgumentResolver: This is the only one that handles entry time. If the input type is ServletResponse/OutputStream/Writer, and mavContainer!= null, it is set to true (because Spring MVC thinks that since you have introduced response yourself, you can do it yourself, so when you use it, here is the detail that needs special attention ~)

resolveArgument()Method:
if (mavContainer != null) {
mavContainer.setRequestHandled(true); // It's equivalent to saying you need `ServletResponse', so the return value should be handled by yourself.~~~~
}

This is the most important class in this article: Model AndViewContainer. Next, the introduction is very simple, relaxed and pleasant.

Model

The concept of org. spring framework. ui. Model is often mentioned in both MVC design patterns and Spring MVC: it is used by the control layer to return the required data (data needed for rendering) to the front end.

// @ since 2.5.1 It is an interface
public interface Model {
...
// addAttribute/addAllAttributes/mergeAttributes/containsAttribute
...
// Return the current set of model attributes as a Map.
Map<String, Object> asMap();
}

Its succession tree is as follows:
The most important one must be the Extended Model Map, which is left to go into detail when introducing the Model Map, and simply look at the rest of the subclasses.

RedirectAttributes

As you can see from the naming, it is related to redirection, which extends the Model interface:

// @since 3.1
public interface RedirectAttributes extends Model {
...
// The three methods it extends are all related to flash attributes
RedirectAttributes addFlashAttribute(String attributeName, @Nullable Object attributeValue);
// There is no key specified here, because the key is automatically generated according to Conventions#getVariableName().
RedirectAttributes addFlashAttribute(Object attributeValue);
// Return the attributes candidate for flash storage or an empty Map.
Map<String, ?> getFlashAttributes();
}

RedirectAttributesModelMap

It implements the RedirectAttributes interface and inherits from ModelMap, so it "indirectly" implements all the methods of the Model interface.

I think the only thing that makes sense is that it uses DataBinder to convert the added attribute parameter to String type (why to String type, have you ever thought??) ~

ConcurrentModel

It came only after Spring 5.0. It's a thread-safe Model, and it doesn't provide anything new, just for scenarios with thread-safe problems.

ModelMap

ModelMap inherits from LinkedHashMap, so its essence is just a Map.
Its characteristic is that it indirectly implements the interface method of org. spring framework. ui. model with the help of Map's ability, which is more worthy of our reference and study.
so, just look at the Extended Model Map. It inherits itself from ModelMap. It has no features. It's all a copy of the interface method completed by calling the method of the parent class. Meow his subclass.~

BindingAwareModelMap

Note: It differs from ordinary ModelMap in that it can perceive data validation results (if the keys put in have the corresponding binding results, and your value is not the binding result itself). Then remove the key pair ~ of MODEL_KEY_PREFIX + key.

Spring MVC uses this ModelMap by default, but most of the perception capabilities it provides are not needed. But you don't need to take care of it anyway.

ModelAndView

As the name implies, ModelAndView refers to a collection of models and views that contain both models and views; ModelAndView can generally be used as a return value for Controller, so its instance is manually created by the developer itself, which is also the main difference between it and the above (all containers are created above, and then injected to us for use) .

Because this class is directly for developers, it is recommended that some of the API s should be familiar with:

Many people wonder: Why can Controller not only return ModelAndView, but also pass values directly to the page by returning Map/Model/ModelMap, etc? If the return value is the last three, how do you find the view to render?

I'll throw out this question, but I won't give you an answer in this article. Because we have all talked about this, this problem should not be difficult, it is suggested that small partners must understand the reasons for their own (please do not let go of useful knowledge points). If there's something I really don't understand, leave a message and I'll answer it for you.~
Answer Reference Tips: Refer to Model Method Processor and ModelMethod Processor's Processing Module for Return Value

In most cases, I recommend returning to Model AndView instead of the other Nago III. Because the third brother didn't specify the view name, the view name generated by Dispatcher Servlet. applyDefaultViewName () is generally not what we need. (Unless your catalogue, naming, and so on are all very specific, it can save a lot of work by the way.)

ModelFactory

About Model Factory, This article I've explained it in detail. Here are two more sentences about its function.Model Factory is used to maintain Model, which contains two functions.

Initialization Model

After the processor executes, the corresponding parameters in Model are updated to Session Attributes (processing @ModelAttribute and @Session Attributes)

summary

I thought this article would not be very long, but I did not expect to write more than 10,000 words in the middle of the article. I hope this article can help you understand the core content of model and view in Spring MVC, and help you clear some obstacles on the way.~
== If you are interested in Spring, Spring Boot, MyBatis and other source code analysis, you can add me wx: fsx641385712, invite you to join the group and fly together manually.==