文章目錄
電子書以及項目完整源代碼
視圖解析
ViewResolver 和 View
- 視圖解析器ViewResolver負責處理視圖名與實際視圖之間的映射關係。 當給resolveViewName()方法傳入一個視圖名和Locale對象時,它會返回一個View實例.
public interface ViewResolver {
View resolveViewName(String var1, Locale var2) throws Exception;
}
- 視圖接口View負責準備請求,並將請求的渲染交給某種具體的視圖技術實現。接受模型以及Servlet的request和response對象,並將輸出結果渲染到response中。
public interface View {
String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
String PATH_VARIABLES = View.class.getName() + ".pathVariables";
String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";
String getContentType();
void render(Map<String, ?> var1, HttpServletRequest var2, HttpServletResponse var3) throws Exception;
}
視圖解析器
- BeanNameViewResolver
將視圖解析爲Spring應用上下文中的bean,其中
bean的ID與視圖的名字相同 - ContentNegotiatingViewResolver
通過考慮客戶端需要的內容類型來解析視圖,
委託給另外一個能夠產生對應內容類型的視圖
解析器 - FreeMarkerViewResolver 將視圖解析爲FreeMarker模板
- InternalResourceViewResolver
將視圖解析爲Web應用的內部資源(一般爲
JSP) - JasperReportsViewResolver 將視圖解析爲JasperReports定義
- ResourceBundleViewResolver 將視圖解析爲資源bundle(一般爲屬性文件)
- TilesViewResolver
將視圖解析爲Apache Tile定義,其中tile ID與視
圖名稱相同。注意有兩個不同的TilesViewResolver實現,分別對應於Tiles 2.0和
Tiles 3.0 - UrlBasedViewResolver
直接根據視圖的名稱解析視圖,視圖的名稱會
匹配一個物理視圖的定義 - VelocityLayoutViewResolver
將視圖解析爲Velocity佈局,從不同的Velocity模
板中組合頁面 - VelocityViewResolver 將視圖解析爲Velocity模板
- XmlViewResolver
將視圖解析爲特定XML文件中的bean定義。類
似於BeanName-ViewResolver - XsltViewResolver 將視圖解析爲XSLT轉換後的結果
Jsp 視圖
兩種方式
- 使用JSP標準標籤庫
(JavaServer Pages Standard Tag Library,JSTL),InternalResourceViewResolver能夠將視圖名解析爲
JstlView形式的JSP文件,從而將JSTL本地化和資源bundle變量暴
露給JSTL的格式化(formatting)和信息(message)標籤。 - 使用spring 提供的兩個JSP標籤庫,一個用於表單到模型的綁定,另一
個提供了通用的工具類特性。
jsp 視圖解析器的配置
InternalResourceViewResolver 主要是採用拼接的方式,將視圖名稱拼接到配置的字符串,即添加前綴和後綴,從而確認Web應用中視圖資源的物理路徑。
- java 配置方式啓用mvc 和 定製配置
@Configuration
@EnableWebMvc //啓用Spring MVC
@ComponentScan("com.zexing.spittr.web") //啓用組件掃描
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public ViewResolver viewResolver() { //配置視圖解析器
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
//```
}
- xml 配置方式啓用mvc 和 定製配置
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 開啓註解驅動的spring mvc-->
<mvc:annotation-driven />
<context:component-scan base-package="com.zexing.spittr" />
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
</beans:beans>
以上配置解析的是InternalResourceView視圖
- 配置 Jstl 視圖
JSTL的格式化標籤需要一個Locale對象,以便於恰當地格式化地域
相關的值,如日期和貨幣。信息標籤可以藉助Spring的信息資源和
Locale,從而選擇適當的信息渲染到HTML之中。通過解析
JstlView,JSTL能夠獲得Locale對象以及Spring中配置的信息資
源。
設置它的viewClass屬性,即加上以下代碼
resolver.setViewClass(JstlView.class);
而 xml 加上
<beans:property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
spring 的JSP庫
- 綁定模型數據的表單標籤
在JSP頁面聲明標籤庫
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>
- <sf:checkbox>
渲染成一個HTML <input>標籤,其中type屬性設置
爲checkbox - <sf:checkboxes>
渲染成多個HTML <input>標籤,其中type屬性設置
爲checkbox - <sf:errors> 在一個HTML <span>中渲染輸入域的錯誤
- <sf:form> 渲染成一個HTML <form>標籤,併爲其內部標籤暴露綁定路
徑,用於數據綁定 - <sf:hidden> 渲染成一個HTML <input>標籤,其中type屬性設置爲hidden
- <sf:input> 渲染成一個HTML <input>標籤,其中type屬性設置爲text
- <sf:label> 渲染成一個HTML <label>標籤
- <sf:option> 渲染成一個HTML <option> 標籤,其selected屬性根據所綁定的值進行設置
- <sf:options> 按照綁定的集合、數組或Map,渲染成一個HTML <option>標
籤的列表 - <sf:password>
渲染成一個HTML <input>標籤,其中type屬性設置
爲password - <sf:radiobutton> 渲染成一個HTML <input>標籤,其中type屬性設置爲radio
- <sf:select> 渲染爲一個HTML <select>標籤
- <sf:textarea> 渲染爲一個HTML <textarea>標籤
就Spitter樣例,用到註冊表單
<sf:form method="POST" comandName="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/>
<sf:input type="submit" value="Register" />
</sf:form>
其中sf:form會渲染一個HTMl 標籤,同時通過commandName屬性構建針對某個模型對象的上下文信息。
因此在模型中必須要有一個key爲Spitter對象,否則的話,表單不能正常渲染(會出現JSP錯誤).這意味着我們需要修改SpitterController,以確保模型中存在以Spitter爲key的Spitter對象。
@RequestMapping(value = "/register",method = RequestMethod.GET)
public String showRegistrationForm(Model model){
model.addAttribute(new Spitter());//對應registerForm.jsp中 <sf:form> 的commandName屬性值
return "registerForm";
}
我們在這裏設置了path屬性,< input>標籤的value屬性值將會設置爲spitter對象中path屬性所對應的值。
例如在模型中Spitter對象中firstName屬性值爲guo,那麼<sf:input path=“firstname”/>所渲染的< input>標籤中,會存在value=“guo”。
當用戶註冊失敗後,返回表單將預設先前用戶的填寫內容
從Spring 3.1開始,<sf:input>標籤能夠允許我們指
定type屬性,即還能指定HTML 5
特定類型的文本域,如date、range和email。例如,我們可以按
照如下的方式指定email域:
Email: <sf:input path="email" type="email"/> <br/>
- 向用戶展現後臺校驗的錯誤信息
如果存在校驗錯誤的話,請求中會包含錯誤的詳細信息,這些信息是
與模型數據放到一起的。我們所需要做的就是到模型中將這些數據抽
取出來,並展現給用戶
<sf:errors path="firstName"/>
path屬性指定了將要顯示模型對象的哪個屬性的錯誤信息,當校驗錯誤,將會在一個HTML 標籤中顯示錯誤信息,否則不渲染任何內容。
如以上校驗失敗時渲染的內容是:
<span id="firstName.errors">size must be between 2 and 30</span>
- 用property文件定義錯誤信息
在校驗註解上設置message屬性,使其引
用對用戶更爲友好的信息。(PS:沒有使用{}將直接顯示)
Spitter.java
@NotNull
@Size(min=5, max=16, message="{username.size}")
private String username;
ValidationMessages.properties
firstName.size=First name must be between {min} and {max} characters long.
{min}和{max}會引用@Size註解上所設
置的min和max屬性。
Spring 的通用標籤庫
聲明標籤庫
<%@ taglib uri="http://www.springframework.org.tags" prefix='s'%>
幾種標籤說明
- <s:escapeBody> 將標籤體中的內容進行HTML和/或JavaScript轉義
- <s:htmlEscape> 爲當前頁面設置默認的HTML轉義值
- <s:message>
根據給定的編碼獲取信息,然後要麼進行渲染(默認行
爲),要麼將其設置爲頁面作用域、請求作用域、會話作用
域或應用作用域的變量(通過使用var和scope屬性實現) - <s:url>
創建相對於上下文的URL,支持URI模板變量以及
HTML/XML/JavaScript轉義。可以渲染URL(默認行爲),也
可以將其設置爲頁面作用域、請求作用域、會話作用域或應
用作用域的變量(通過使用var和scope屬性實現)
- 使用 <s:message> 對展示信息進行國際化處理
- 修改代碼
<h1><s:message code="spittr.welcome" /></h1>
- 配置信息源
@Bean
public MessageSource messageSource () { //配置信息源
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setCacheSeconds(10);
return messageSource;
}
basename屬性可以設置爲在類路徑下(以“classpath:”作
爲前綴)、文件系統中(以“file:”作爲前綴)或Web應用的根路徑
下(沒有前綴)查找屬性
- 創建property文件
messages.properties
spittr.welcome=Welcome to Spitter!
2.使用<s:url> 創建URL
- 簡單使用
<a href=" <s:url value="/spitter/register" />">register</a>
<s:url> 會接受一個相對於Servlet上下文的URL,並在渲染的時候,在URL 後面拼接上Servlet上下文路徑,即當應用的Servlet上下文名爲spittr,渲染後的
標籤內容是
<a href="/spittr/spitter/register">register</a>
- 將 URL 賦值變量
<s:url value="/spitter/register" var="registerUrl" />
<a href=" ${registerUrl}">register</a>
- 添加作用域屬性
<s:url value="/spitter/register" var="registerUrl" scope="page"/>
- URL上添加參數
<s:url value="/spittles" var="spittlesUrl">
<s:param name="max" value="60"/>
<s:param name="count" value="20" />
</s:url>
<a href="${spittlesUrl}">Spittles</a>
跳轉的URl將會拼接參數:
http://localhost:8080/spittles?max=60&count=20
- 渲染URL內容(需要去除 var 屬性)
設置屬性 htmlEscape 爲true
<s:url value="/spittles" htmlEscape="true">
<s:param name="max" value="60"/>
<s:param name="count" value="20" />
</s:url>
將在頁面直接顯示URL的內容
/spittles?max=60&count=20
在javascript裏面使用
設置屬性 javaScriptEscape 爲true
<s:url value="/spittles" var="jsUrl" javaScriptEscape="true">
<s:param name="max" value="60"/>
<s:param name="count" value="20" />
</s:url>
<script>
var spittlesUrl = ${jsUrl};
</script>
【這部分尚未完成】使用Apache Tiles視圖定義佈局
爲所有頁面定義通用頁面佈局模板
導入相關jar包
需導入Tiles相關的jar包(缺少包可能導致的Exception):
- tiles-api-3.0.8.jar
- tiles-core-3.0.8.jar
- tiles-jsp-3.0.8.jar
- tiles-servlet-3.0.8.jar
- tiles-template-3.0.8.jar
- slf4j-api-1.7.25 (java.lang.ClassNotFoundException: org.slf4j.LoggerFactory)
- commons-digester-2.1 (java.lang.ClassNotFoundException: org.apache.commons.digester.Rule)
- commons-beanutils-1.9.3 (ClassNotFoundException: org.apache.commons.beanutils.MethodUtils)
- tiles-request-api-1.0.7.(java.lang.NoClassDefFoundError: org/apache/tiles/request/render/Renderer)
- tiles-request-servlet-1.0.7.(ClassNotFoundException: org.apache.tiles.request.servlet.ServletApplicationContext)
- tiles-request-jsp-1.0.7 (ClassNotFoundException: org.apache.tiles.request.jsp.autotag.JspAutotagRuntime)
- tiles-autotag-core-runtime-1.2 (ClassNotFoundException: org.apache.tiles.autotag.core.runtime.AutotagRuntime)
配置Tiles視圖解析器
- TilesConfigurer bean
負責定位和加載Tile定義並協調生成Tiles
// Tiles
@Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tiles = new TilesConfigurer();
tiles.setDefinitions(new String[] {
"/WEB-INF/layout/tiles.xml", //指定Tiles定義的位置
"/WEB-INF/views/**/tiles.xml" //遍歷“WEB-INF/”的所有子目錄來查找Tile定義。
});
tiles.setCheckRefresh(true); //啓用刷新功能
return tiles;
}
- TilesViewResolver bean
將邏輯視圖名稱解析爲Tile定義。
@Bean
public ViewResolver viewResolver() {
return new TilesViewResolver();
}
- WebConfig.java
@Configuration
@EnableWebMvc //啓用Spring MVC
@ComponentScan("com.zexing.spittr.web") //啓用組件掃描
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public ViewResolver viewResolver() { //配置視圖解析器
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) { //配置靜態資源的處理
// TODO Auto-generated method stub
super.addResourceHandlers(registry);
}
}
- 通過xml配置
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="difinitions">
<list>
<value>WEB-INF/layout/tiles.xml</value>
<value>/WEB-INF/view/**.tiles.xml</value>
</property>
</bean>
<bean id="ViewResolver"
class="org.springframework.web.servlet.view.tiles3.TilesViewResolver" />
【TODO】定義Tiles
未完待續
Thymeleaf
1.Thymeleaf 在有網絡和無網絡的環境下皆可運行,即它可以讓美工在瀏覽器查看頁面的靜態效果,也可以讓程序員在服務器查看帶數據的動態頁面效果。這是由於它支持 html 原型,然後在 html 標籤裏增加額外的屬性來達到模板+數據的展示方式。瀏覽器解釋 html 時會忽略未定義的標籤屬性,所以 thymeleaf 的模板可以靜態地運行;當有數據返回到頁面時,Thymeleaf 標籤會動態地替換掉靜態內容,使頁面動態顯示。
2.Thymeleaf 開箱即用的特性。它提供標準和spring標準兩種方言,可以直接套用模板實現JSTL、 OGNL表達式效果,避免每天套模板、該jstl、改標籤的困擾。同時開發人員也可以擴展和創建自定義的方言。
3.Thymeleaf 提供spring標準方言和一個與 SpringMVC 完美集成的可選模塊,可以快速的實現表單綁定、屬性編輯器、國際化等功能。
配置Thymeleaf視圖解析器
配置啓用的三個bean
- ThymeleafViewResolver:將邏輯視圖名稱解析爲Thymeleaf模板視圖;
- SpringTemplateEngine:處理模板並渲染結果;
- TemplateResolver:加載Thymeleaf模板。
@Bean
public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine);
return viewResolver;
}
@Bean
public SpringTemplateEngine templateEngine(TemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
return templateEngine;
}
@Bean
public TemplateResolver templateResolver() {
TemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
return templateResolver;
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
使用 xml
<bean id="viewResolver" class="org.thymeleaf.spring4.view.ThymeleafViewResolver"
p:templateEngine-ref="templateEngine" />
<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine"
P:templateResolver-ref="templateResolver" />
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver"
p:prefix="WEB-INF/templates/"
p:suffix=".html"
p:templateMode="HTML5" />
ThymeleafViewResolver是Spirng MVC中ViewResolver的一個實現類。像其他視圖解析器一樣,會接受一個邏輯視圖名稱,並將其解析爲視圖。不過在該場景下 ,視圖會是一個Thymeleaf模板。
需要注意的是:ThymeleafViewResolver bean中注入了一個對SpringTemplateEnginebean 的引用。SpringTemplateEngine會在Spring中啓用Thymeleaf引擎,用來解析模板並基於這些模板渲染結果。
TemplateResolver會最終定位和查找模板。與之前配置的InternalResourceVIewResolver類似,他使用了prefix 和 suffix屬性。它的templateMode屬性被設置爲HTML5,這表明我們預期要解析的模板會渲染成HTML5輸出。
定義Thymeleaf模板
- 簡單模板
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"> <!--聲明Thymeleaf命名空間-->
<head>
<title>Spitter</title>
<link rel="stylesheet"
type="text/css"
th:href="@{/resources/style.css}"></link> <!--到樣式表的th:href鏈接-->
</head>
<body>
<h1>Welcome to Spitter</h1>
<a th:href="@{/spittles}">Spittles</a> | <!--到頁面的th:herf鏈接-->
<a th:href="@{/spitter/register}">Register</a>
</body>
</html>
這裏使用th:href屬性的三個地方都是用到了“@{}”表達式,用來計算相對於URL的路徑,相比於在JSP中 使用JSTL的 <c:url>標籤或Spring<s:url>標籤,Thymeleaf 模板能夠按照原始的方式進行編輯甚至渲染,而不必經過任何類型的處理器,當然我們需要Thymeleaf來處理模板,並渲染得到最終期望的輸出。
- 實現表單綁定
<label th:class="${#fields.hasErrors('firstName')}? 'error'">First Name</label>:
<input type="text" th:field="*{firstName}"
th:class="${#fields.hasErrors('firstName')}? 'error'" /><br/>
這裏th:class屬性會渲染爲一個class屬性,它的值是根據給定的表達式計算得到的。在上面的這兩個th:class屬性中,它會直接檢查firstName域有沒有校驗錯誤。如果有的話,class屬性在渲染時的值爲error。如果這個域沒有錯誤的話,將不會渲染class屬性。
標籤使用了th:field屬性,用來引用後端對象的firstName域。
<form method="POST" th:object="${spitter}">
<div class="errors" th:if="${#fields.hasErrors('*')}"> <!-- 展現錯誤信息 -->
<ul>
<li th:each="err : ${#fields.errors('*')}"
th:text="${err}">Input is incorrect</li>
</ul>
</div>
<label th:class="${#fields.hasErrors('firstName')}? 'error'">First Name</label>:
<input type="text" th:field="*{firstName}"
th:class="${#fields.hasErrors('firstName')}? 'error'" /><br/>
<label th:class="${#fields.hasErrors('lastName')}? 'error'">Last Name</label>:
<input type="text" th:field="*{lastName}"
th:class="${#fields.hasErrors('lastName')}? 'error'" /><br/>
<label th:class="${#fields.hasErrors('email')}? 'error'">Email</label>:
<input type="text" th:field="*{email}"
th:class="${#fields.hasErrors('email')}? 'error'" /><br/>
<label th:class="${#fields.hasErrors('username')}? 'error'">Username</label>:
<input type="text" th:field="*{username}"
th:class="${#fields.hasErrors('username')}? 'error'" /><br/>
<label th:class="${#fields.hasErrors('password')}? 'error'">Password</label>:
<input type="password" th:field="*{password}"
th:class="${#fields.hasErrors('password')}? 'error'" /><br/>
<input type="submit" value="Register" />
</form>
在頂部,<div>元素使用th:if屬性來檢查是否有校驗錯誤。如果有的話,會渲染<div>,否則的話,它將不會渲染。在<div>中,會使用一個無順序的列表來展現每項錯誤。<li>標籤上的th:each屬性將會通知Thymeleaf爲每項錯誤都渲染一個<li>,在每次迭代中會將當前錯誤設置到一個名爲err的變量中。
"{Spitter}這裏 例子中,它會解析爲ket爲spitter的model屬性。
而對於*{}表達式,他們是選擇表達式。變量表達式是基於整個SpEl上下文計算的,而選擇表達式是基於某一個選中對象計算的。在本例的表單中,選中對象就是標籤中的th:object屬性所設置的對象:模型中的Spitter對象。因此,“*{firsrName}”表達式就會計算爲Spitter對象的firstName屬性。