When we use Spring MVC, we must know that for security reasons, our JSP files will be placed under WEB-INF.
But we don't have direct access to resources in / WEB-INF / directory outside, do we?
Access can only be carried out through internal server in the form of forwarding, so the bottom of the Internal ResourceViewResolver can help us solve this problem by forwarding!
In order to use the Internal ResourceViewResolver, we will configure it in the Spring MVC configuration file as follows
<!-- Custom View Parser --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"/> <property name="suffix" value=".jsp"/> </bean>
Then we want to access a file in the WEB-INF directory and enter the name of the file directly.
For example:
View. View parser will help us resolve to / WEB-INF/view.jsp at the bottom.
So, how does the bottom of it actually come true?
Internal ResourceViewResolver: It's a subclass of UrlBasedViewResolver, so it supports all the features of UrlBasedViewResolver.
What are the features of Internal ResourceViewResolver? In its literal sense, we can understand it as an internal resource view parser, which is also the most widely used view parser.
Let's take a look at its underlying source code
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.web.servlet.view; import org.springframework.util.ClassUtils; public class InternalResourceViewResolver extends UrlBasedViewResolver { private static final boolean jstlPresent = ClassUtils.isPresent("javax.servlet.jsp.jstl.core.Config", InternalResourceViewResolver.class.getClassLoader()); private Boolean alwaysInclude; public InternalResourceViewResolver() { Class<?> viewClass = this.requiredViewClass(); if (viewClass.equals(InternalResourceView.class) && jstlPresent) { viewClass = JstlView.class; } this.setViewClass(viewClass); } protected Class<?> requiredViewClass() { return InternalResourceView.class; } public void setAlwaysInclude(boolean alwaysInclude) { this.alwaysInclude = alwaysInclude; } protected AbstractUrlBasedView buildView(String viewName) throws Exception { InternalResourceView view = (InternalResourceView)super.buildView(viewName); if (this.alwaysInclude != null) { view.setAlwaysInclude(this.alwaysInclude); } view.setPreventDispatchLoop(true); return view; } }
Internal ResourceViewResolver passes back the request or viewname we returned by executing the buildView method and calling the vuildView method of the parent class. Let's look at the implementation of this method.
//Delete the unimportant part of the code
protected AbstractUrlBasedView buildView(String viewName) throws Exception { AbstractUrlBasedView view = (AbstractUrlBasedView)BeanUtils.instantiateClass(this.getViewClass());//Getting a view class has inheritance view.setUrl(this.getPrefix() + viewName + this.getSuffix());//Get prefix and suffix that we configure in the configuration file and the incoming viewName String contentType = this.getContentType(); if (contentType != null) { view.setContentType(contentType);//View type } return view;//Return to our view }
Through this method, we can find that the preferred method creates a view. Although we don't know it, they have an indirect inheritance relationship. We can look at the inheritance structure by ourselves.
Then we get the prefix and suffix of the Internal ResourceViewResolver we configured in Spring MVC and the viewName name to form a complete url, such as: / WEB-INF/a.jsp, and finally return the constructed view to form a complete url.
Internal Resource View view. Then the Internal ResourceView view puts all the model attributes returned by the Controller processor into the HttpServletRequest, so let's look at the underlying execution.
//What is called is InternalResourceView Object Method protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { this.exposeModelAsRequestAttributes(model, request);//By invoking this method and executing the code placed in request, see the following snippet this.exposeHelpers(request); String dispatcherPath = this.prepareForRendering(request, response); RequestDispatcher rd = this.getRequestDispatcher(request, dispatcherPath); if (rd == null) { throw new ServletException("Could not get RequestDispatcher for [" + this.getUrl() + "]: Check that the corresponding file exists within your web application archive!"); } else { if (this.useInclude(request, response)) { response.setContentType(this.getContentType()); if (this.logger.isDebugEnabled()) { this.logger.debug("Including resource [" + this.getUrl() + "] in InternalResourceView '" + this.getBeanName() + "'"); } rd.include(request, response); } else { if (this.logger.isDebugEnabled()) { this.logger.debug("Forwarding to resource [" + this.getUrl() + "] in InternalResourceView '" + this.getBeanName() + "'"); } rd.forward(request, response); } } }
//What is called is AbstractView class protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception { Iterator var3 = model.entrySet().iterator(); while(var3.hasNext()) { Entry<String, Object> entry = (Entry)var3.next(); String modelName = (String)entry.getKey(); Object modelValue = entry.getValue(); if (modelValue != null) { request.setAttribute(modelName, modelValue);//Put the model attribute values returned by Controller into if (this.logger.isDebugEnabled()) { this.logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() + "] to request in view with name '" + this.getBeanName() + "'"); } } else { request.removeAttribute(modelName); if (this.logger.isDebugEnabled()) { this.logger.debug("Removed model object '" + modelName + "' from request in view with name '" + this.getBeanName() + "'"); } } } }
Then the request forword is redirected to the target URL on the server side through Request Dispatcher
This is the Internal ResourceViewResolver parsing process
Coherence is
The Internal ResourceViewResolver resolves the returned view names into the Internal ResourceView objects, and the Internal ResourceView stores the model attributes returned by the Controller processor methods into the corresponding request attributes, and then redirects the request for word to the target URL on the server side through the Request Dispatcher. For example, in the Internal ResourceViewResolver, prefix=/WEB-INF/, suffix=.jsp are defined, and then the view name returned by the requested Controller processor method is test. At this time, the Internal ResourceViewResolver will parse the test into an Internal ResourceView object and store the returned model attributes into pairs. In the corresponding HttpServletRequest attribute, the request is forword to/WEB-INF/a.jsp on the server side using RequestDispatcher.
Finally, we summarize the overall process of view analysis:
1. Calling the target method, Spring MVC converts the String, View, ModelMap or ModelAndView returned by the target method into a ModelAndView object.
2. Then the View object in ModelAndView object is parsed by ViewResolver, and the logical view view view object is parsed into a physical view view view object.
3. Finally, the render() method of the physical View object is invoked to render the View, and the response result is obtained.