6 渲染 Web 视图
6.1 Understanding view resolution
Spring MVC defines an interface named ViewResolver that looks a little something like this:
public interface ViewResolver {
View resolveViewName(String viewName, Locale locale) throws Exception;
}
View is another interface that looks like this:
public interface View {
String getContentType();
void render(Map<String, ?> model,
HttpServletRequest request,
HttpServletResponse response) throws Exception;
}
Fortunately, Spring provides several out-of-the-box implementations, that fit most circumstances, [共 12 种]. For the most part, each of the view resolvers corresponds to a specific view technology available for Java web applications. InternalResourceViewResolver is typically used for JSP , TilesViewResolver is for Apache Tiles views, and FreeMarkerViewResolver and VelocityViewResolver map to FreeMarker and Velocity template views respectively.
6.2 Creating JSP views
Spring supports JSP views in two ways:
InternalResourceViewResolver: resolve view names into JSP files.- Spring provides two JSP tag libraries, one for
form-to-model bindingand one providinggeneral utilityfeatures.
Whether or not you use JSTL or intend to use Spring’s JSP tag libraries, it’s important to configure a view resolver to resolve JSP views. Although a few of Spring’s other view resolvers could be used to map view names to JSP files, InternalResourceViewResolver is the simplest and most commonly used view resolver for this task.
6.2.1 Configuring a JSP-ready view resolver
Suffix
↓--Prefix----↓ ↓-↓
/WEB-INF/views/home.jsp
↑---↑
Logical View Name
You can configure InternalResourceViewResolver to apply this convention when resolving views by configuring it with this @Bean annotated method:
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver =
new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
Optionally, if you prefer to use Spring’s XML-based configuration, you can configure InternalResourceViewResolver like this:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/views/"
p:suffix=".jsp" />
When a logical view name has a slash in it, that slash is carried over into the resource path name. Therefore, it maps to a JSP file that’s in a subdirectory [反斜杠反射到子目录] of whatever directory is referenced by the prefix property.
解析 JSTL 视图
JSTL ’s formatting tags need a Locale to properly format locale-specific values such as dates and money. And its message tags can use a Spring message source and a Locale to properly choose messages to render in HTML. By resolving JstlView , the JSTL tags will be given the Locale and any message source configured in Spring.
All that’s needed to have InternalResourceViewResolver resolve JstlView instead of InternalResourceView is to set its viewClass property:
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver =
new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setViewClass(org.springframework.web.servlet.view.JstlView.class);
return resolver;
}
Again, you can accomplish the same thing with XML:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/views/"
p:suffix=".jsp"
p:viewClass="org.springframework.web.servlet.view.JstlView" />
6.2.2 Using Spring’s JSP libraries
Spring offers two JSP tag libraries to help define the view of your Spring MVC web views. One tag library renders HTML form tags that are bound to a model attribute. The other has a hodgepodge of utility tags that come in handy from time to time.
把表单和 Model 绑定到一起
To use the form-binding tag library, you’ll need to declare it in the JSP pages that will use it:
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>
Notice that I specified a prefix of sf, but it’s also common to use a prefix of form. I chose sf because it’s succinct, easy to type, and an abbreviation for Spring forms.
<sf:form method="POST" commandName="spitter">
First Name: <sf:input path="firstName" /><br/>
Last Name: <sf:input path="lastName" /><br/>
Email: <sf:input path="email" /><br/>
Username: <sf:input path="username" /><br/>
Password: <sf:password path="password" /><br/>
<input type="submit" value="Register" />
</sf:form>
The <sf:form> tag renders an HTML <form> tag. But it also sets some context around a model object designated in the commandName attribute. Properties on the model object will be referenced in the other form-binding tags you use.
In the preceding code, you set commandName to spitter . Therefore, there must be an object in the model whose key is spitter , or else the form won’t be able to render (and you’ll get JSP errors). That means you need to make a small change to SpitterController to ensure that a Spitter object is in the model under the spitter key:
@RequestMapping(value="/register", method=GET)
public String showRegistrationForm(Model model) {
model.addAttribute(new Spitter());
return "registerForm";
}
This tweak to showRegistrationForm() now has that method adding a new Spitter instance to the model. The model key will be inferred from the object type to be spitter — exactly what you need it to be.