渲染web视图
理解web解析
Spring为我们提供了13种视图解析器,Spring4和Spring3.2支持以上13种视图解析器。
每一种视图解析器应用在不同的场景,例如,InternalResourceViewResolver一般用在JSP中,TilesViewResolver用户Apache Tiles视图。
创建JSP视图
这里我们使用InternalResourceViewResolver来解析JSP。
Spring提供了两种支持JSP的方式
- jstl(JSP标准标签库)
- Spring提供了两种标签库,一种是表单绑定,另一种是通用的标签库
配置适用于JSP的视图解析器
- 基于Java显式配置的方式
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
- 基于xml显式配置的方式
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/views" p:suffix=".jsp">
</bean>
解析jstl
InternalResourceViewResolver会将逻辑视图名解析成InternalResourceView实例,这个实例会引用JSP视图。而如果需要jstl来处理格式化和信息,需要解析成JstlView。想让InternalResourceViewResolver解析逻辑视图名为JstlView的话,只需设置InternalResourceViewResolver实例的viewClass属性即可。
- Java配置的方式
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
viewResolver.setViewClass(org.springframework.web.servlet.view.JstlView.class);
return viewResolver;
}
- 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" />
使用Spring的JSP库
在之前的注册方法中,如果注册失败,那么,会返回注册页面,页面里面的信息全是空的,但是,我们想如果数据能放回相应的位置,并且有错误提示的话,这个系统就更加友好了。
将表单绑定到模型上
Spring的表单绑定JSP标签库有14个标签,如下图。
注意:使用这些标签前,需要在JSP页面进行如下声明
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>
这时,注册页面重写如下
<sf:form method="post" commandName="spitter">
firstName:<sf:input path="firstName" />
secondName:<sf:input path="secondName" />
username:<sf:input path="username" />
Email:<sf:input path="email" />
password:<sf:password path="password" />
<input type="submit" value="Register" />
</sf:form>
- commandName:是model中的key。
- path:上面的key对应的对象的属性名。对象对应的属性值就会注入相应的位置。
跳转到注册页面的控制器方法重写如下
@RequestMapping(value="/regiester", method=RequestMethod.GET)
public String getRegisterationForm(Model model) {
model.addAttribute(new Spitter());
return "registerForm";
}
@RequestMapping(value="/register", method=RequestMethod.POST)
public String processRegistration(
@Valid Spitter spitter,
Errors errors,
Model model
) {
if(errors.hasErrors()) {
model.addAttribute(spitter);
return "registerForm";
}
spitterRepository.save(spitter);
return "redirect:/spitter/" + spitter.getUsername();
}
校验失败后,最终的html如下
<form id="spitter" action="/spitter/spitter/register" method="POST">
First Name:
<input id="firstName"
name="firstName" type="text" value="J"/><br/>
Last Name:
<input id="lastName"
name="lastName" type="text" value="B"/><br/>
Email:
<input id="email"
name="email" type="text" value="jack"/><br/>
Username:
<input id="username"
name="username" type="text" value="jack"/><br/>
Password:
<input id="password"
name="password" type="password" value=""/><br/>
<input type="submit" value="Register" />
</form>
注意:从Spring3.1开始,允许我们在sf:input中设置type属性,例如email,file等。
<sf:input type="email" path="email" />
渲染出来的页面如下
<input id="email" name="email" type="email" value="jack"/><br/>
展示错误
上面我们解决了将输入的信息回显到输入框中,接下来是显示错误信息,使用sf:errors标签。
<sf:form method="POST" commandName="spitter">
First Name: <sf:input path="firstName" />
<sf:errors path="firstName" /><br/>
...
</sf:form>
如果校验错误,那么会将错误信息在<span>标签中显示。如果没有错误,则不会渲染任何信息。出现错误时,如下显示:
First Name: <input id="firstName"
name="firstName" type="text" value="J"/>
<span id="firstName.errors">size must be between 2 and 30</span>
我们也可以为错误信息添加样式,使用cssClass属性,这个属性里面的值是我们自定义一个class名。
<sf:form method="POST" commandName="spitter" >
First Name: <sf:input path="firstName" />
<sf:errors path="firstName" cssClass="error" /><br/>
...
</sf:form>
span.error {
color: red;
}
但是如果把错误信息都放到输入框的后面,可能会影响页面布局,这时,我们可以把所有的错误信息都放到表单的最上面。
<sf:form method="POST" commandName="spitter" >
<sf:errors path="*" element="div" cssClass="errors" />
...
</sf:form>
**path="*"
**的意思是把所有的错误都放这里,element="div"会生成一个div元素。
div.errors {
background-color: #ffcccc;
border: 2px solid red;
}
我们也可以在校验错误时,改变输入域的样式
<sf:form method="POST" commandName="spitter" >
<sf:label path="firstName"
cssErrorClass="error">First Name</sf:label>:
<sf:input path="firstName" cssErrorClass="error" /><br/>
...
</sf:form>
label.error {
color: red;
}
input.error {
background-color: #ffcccc;
}
我们可以自定义错误提示信息,在**@Size注解中有message属性**
@NotNull
@Size(min=5, max=16, message="{username.size}")
private String username;
@NotNull
@Size(min=5, max=25, message="{password.size}")
private String password;
@NotNull
@Size(min=2, max=30, message="{firstName.size}")
private String firstName;
@NotNull
@Size(min=2, max=30, message="{lastName.size}")
private String lastName;
@NotNull
@Email(message="{email.valid}")
private String email;
如果message的值没有大括号,那么里面的字符串就是错误提示信息,如果有大括号,里面的字符串是属性文件的某个属性,我们就叫这个属性文件是ValidationMessages.properties。
firstName.size=
First name must be between {min} and {max} characters long.
lastName.size=
Last name must be between {min} and {max} characters long.
username.size=
Username must be between {min} and {max} characters long.
password.size=
Password must be between {min} and {max} characters long.
email.valid=The email address must be valid.
里面的{min}和{max}是@Size标签的min和max属性值。
Spring的通用标签库
要使用Spring通用标签库,必须在页面上做出如下的声明:
<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
- <s:message>
<s:message code="keyName" />
使用这个标签,可以使用将属性文件中key为keyName的值和<s:message>替换掉,解除硬编码。
- <s:url>
<s:url href="url">
<s:url>的作用是创建url,然后赋值给变量或渲染到页面中。href属性的url只需写上想对与servlet的url即可,在渲染的时候会自动加上servlet路径的。
- <s:escapeBody>
这个标签会将标签体的内容进行转义。因为前端html和js都有特殊字符。
有2个属性
* htmlEscape:值的true/false,true就是进行html转义。
* JavaScriptEscape:值的true/false,true就是进行JavaScript转义。
使用Apache Tiles定义视图布局
定义视图解析器
首先我们需要配置2个bean,TilesConfigurer和TilesViewResolver。TilesViewResolver负责将逻辑视图名解析成Tiles定义。TilesConfigurer负责定位和加载Tiles定义并协助生成Tiles。
这两个组件有两种形式,Tiles2和Tiles3,区别在于包名。
- java配置方式
@Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tiles = new TilesConfigurer();
tiles.setDefinitions(new String[] {
"/WEB-INF/layout/tiles.xml" //指定Tiles定义的位置
});
tiles.setCheckRefresh(true); //启用刷新功能
return tiles;
}
@Bean
public ViewResolver viewResolver() {
return new TilesViewResolver();
}
- xml方式
<bean id="tilesConfigurer" class=
"org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/layout/tiles.xml.xml</value>
<value>/WEB-INF/views/**/tiles.xml</value>
</list>
</property>
</bean>
<bean id="viewResolver" class=
"org.springframework.web.servlet.view.tiles3.TilesViewResolver" />
定义Tiles
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
"http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
<definition name="base"
template="/WEB-INF/layout/page.jsp"> //定义base tiles
<put-attribute name="header"
value="/WEB-INF/layout/header.jsp" /> //设置属性
<put-attribute name="footer"
value="/WEB-INF/layout/footer.jsp" />
</definition>
<definition name="home" extends="base"> //扩展base tiles
<put-attribute name="body"
value="/WEB-INF/views/home.jsp" />
</definition>
<definition name="registerForm" extends="base">
<put-attribute name="body"
value="/WEB-INF/views/registerForm.jsp" />
</definition>
<definition name="profile" extends="base">
<put-attribute name="body"
value="/WEB-INF/views/profile.jsp" />
</definition>
<definition name="spittles" extends="base">
<put-attribute name="body"
value="/WEB-INF/views/spittles.jsp" />
</definition>
<definition name="spittle" extends="base">
<put-attribute name="body"
value="/WEB-INF/views/spittle.jsp" />
</definition>
</tiles-definitions>
page.jsp如下
<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="t" %>
<%@ page session="false" %>
<html>
<head>
<title>Spittr</title>
<link rel="stylesheet"
type="text/css"
href="<s:url value="/resources/style.css" />" >
</head>
<body>
<div id="header">
<t:insertAttribute name="header" />
</div>
<div id="content">
<t:insertAttribute name="body" />
</div>
<div id="footer">
<t:insertAttribute name="footer" />
</div>
</body>
</html>
使用Thymeleaf
配置Thymeleaf视图解析器
首先需要配置3个bean
- ThymeleafViewResolver:将逻辑视图名称解析为Thymeleaf模板视图;
- SpringTemplateEngine:处理模板并渲染结果;
- TemplateResolver:加载Thymeleaf模板。
- java方式
@Bean
public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine);
return viewResolver;
}
@Bean
public TemplateEngine templateEngine(TemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
return templateEngine;
}
@Bean
public TemplateResolver templateResolver() {
TemplateResolver templateResolver =
new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
return templateResolver;
}
- xml方式
<bean id="viewResolver"
class="org.thymeleaf.spring3.view.ThymeleafViewResolver"
p:templateEngine-ref="templateEngine" />
<bean id="templateEngine"
class="org.thymeleaf.spring3.SpringTemplateEngine"
p:templateResolver-ref="templateResolver" />
<bean id="templateResolver" class=
"org.thymeleaf.templateresolver.ServletContextTemplateResolver"
p:prefix="/WEB-INF/templates/"
p:suffix=".html"
p:templateMode="HTML5" />
定义Thymeleaf模板
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"> <!--声明Thymeleaf命名空间-->
<head>
<title>Spittr</title>
<link rel="stylesheet"
type="text/css"
th:href="@{/resources/style.css}"> <!--连接到样式表-->
</head>
<body>
<h1>Welcome to Spittr</h1>
<a th:href="@{/spittles}">Spittles</a> | <!--到页面的链接-->
<a th:href="@{/spitter/register}">Register</a>
</body>
</html>