6将模型数据渲染成HTML
6.1 理解视图解析
在MVC模型中,控制器将数据填充到模型中,然后将模型传递给一个用来渲染的视图。控制器中返回的String类型的值是视图的名称。
逻辑处理和视图渲染是解耦的,控制器方法和视图在模型内容上达成一致,除此之外再无关联。
Spring MVC中定了一个名为ViewResolver的接口作为视图解析器,它将返回一个View接口,而View接口将会接收模型和Servlet的request和response,然后将结果写会response。
public interface ViewResolver{
View resolveViewName(String viewName, Locale locale) throw Exception;
}
public interface View{
String getContentType();
void render(Map<String,?> model, HttpServletRequest request, HttpServeltResponse response) throws Exception;
}
Spring 自带了13个视图解析器,所以大部分情况下我们不需要自己实现ViewResolver。大多数情况下我们只使用极少的几个就可以了。
InternalResourceViewResolver用于解析JSP
FreeMarkerViewResolver用于解析FreeMarker模板视图
VelocityViewResolver模板视图。
6.2 创建JSP视图
Spring 支持两种JSP视图模式
- InternalResourceViewResolver会将视图名解析为JSP库,稍加设置可以使用JSTL
- Spring提供了2种标签库,一种用于表单和模型的绑定,另一种提供了通用的工具类特性。
6.2.1 配置适用于JSP的视图解析器
根据前缀和后缀来解析
使用Bean注解配置
@Bean
public ViewResolver viewResolver(){
InternalResorceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setViewClass(org.springframework.web.servlet.view.JstlView.class);//这句话用于JSTL标签库。
return resolver;
}
使用xml配置
<bean id="viewResovler"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/views/"
p:suffix=".jsp"
<!--下面这行用于JSTL标签库-->
p:viewClass="org.springframework.web.servlet.view.JstlView"
/>
6.2.2 使用Spring的JSP标签库
Spring 提供了两个标签库,
一个标签库用来渲染html表单标签,绑定表单和模型;另一个包含了一些工具标签。
对于表单标签库,其一个典型的作用就是讲填写表单的元素绑定到表单上,这样的好处之一就是可以验证填写表单的元素,然后重填的时候可以使用模型来自动填充之前填写的数据,并且使用特殊的样式来标记错误的表单项。
这里举一个例子:
比如你有一个需要注册的用户信息如下:
package com.zhaoch93.EmailManager.po;
import org.hibernate.validator.constraints.Email;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class User {
@NotNull
@Size(min=5,max = 35,message = "{username.size}")
private String username;
@NotNull
@Size(min=5,max = 35,message = "{password.size}")
private String password;
@NotNull
@Email(message = "{email.valid}")
private String bingemail;
public User() {
}
public User(String username, String password, String bingemail) {
this.username = username;
this.password = password;
this.bingemail = bingemail;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getBingemail() {
return bingemail;
}
public void setBingemail(String bingemail) {
this.bingemail = bingemail;
}
}
这是要一个简单的POJO,但是在属性上有一些标注,比如@NotNull,@Size@Email等等。
这些注解是JSR-303的数据验证规范,属于JAVA EE的规范一部分,hibernate-validator是这个规范的实现,在实现的过程中还拓展了一些,比如@Email就是JSR规范中没有的,是实现自己做了拓展。
所以上面这个POJO想要具体发回功能还需要把hibernate-validator加入到路径中,此外还有一个常识性的问题,就是要加<mvc:annotation-driven/>
。只有完成这些才有效。
然后是JSP的部分
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>
<%@ page session="false" %>
<html>
<head>
<title>Spitter</title>
<link rel="stylesheet" type="text/css"
href="/css/style.css" >
</head>
<body>
<h1>Register</h1>
<sf:form method="POST" commandName="user" >
<sf:errors path="*" element="div" cssClass="errors" />
<sf:label path="bingemail" cssErrorClass="error">Email</sf:label>:
<sf:input path="bingemail" cssErrorClass="error" /><br/>
<sf:label path="username" cssErrorClass="error">Username</sf:label>:
<sf:input path="username" cssErrorClass="error" /><br/>
<sf:label path="password" cssErrorClass="error">Password</sf:label>:
<sf:password path="password" cssErrorClass="error" /><br/>
<input type="submit" value="Register"/>
</sf:form>
</body>
</html>
taglib里面的是固定的,但是sf可以自由选择其他的字段代替。
form中commandName后需要填的是绑定的模型的名字,借助自动推断功能,我们可以用User的小写模式。当然在进入这个registerform.jsp之前模型里面需要有user键值对才行。这里可以通过Controller层进行添加。
Controller的java代码如下:
package com.zhaoch93.EmailManager.controller;
import com.zhaoch93.EmailManager.po.User;
import com.zhaoch93.EmailManager.service.IUserService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.List;
@Controller
public class AuthController {
@RequestMapping(value = "/register",method = RequestMethod.GET)
public String showRegisterationForm(Model model){
model.addAttribute(new User());
return "registerform";
}
@RequestMapping(value="/register", method=RequestMethod.POST)
public String processRegistration(
@Valid User user,
Errors errors) {
if (errors.hasErrors()) {
return "registerform";
}
return "access";
}
}
这里代码很简单,在get阶段添加一个model进去,名字就是自动推断的user,当然你也可以自己改一个key,相应的jsp中的commandName也要变了。在Post阶段进行验证,如果验证通过就进入access,如果验证失败就重新进入registerform,这时之前的model还带,并且会根据设定的css来显示不同样式。
JSP通用工具的标签库不介绍了
6.3 使用Apache Tiles视图定义布局
略
6.4 使用Thymeleaf
略