spring(6) 渲染web视图
生活随笔
收集整理的這篇文章主要介紹了
spring(6) 渲染web视图
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【0】README 1)本文部分文字描述轉自:“Spring In Action(中/英文版)”,旨在review ?“spring(6) 渲染web視圖”?的相關知識;
?
【1】 理解視圖解析
【1.1】視圖解析的基礎知識以及spring 提供的其他視圖解析器
1)spring mvc 定義了一個名為 ViewResolver的接口,如下
public interface ViewResolver {View resolveViewName(String viewName, Locale locale)throws Exception;
}
2)當給 resolveViewName()方法傳入一個視圖名和Locale對象時,它會返回一個View實例。View是另外一個接口:
public interface View {
String getContentType();void render(Map<String, ?> model,HttpServletRequest request,HttpServletResponse response) throws Exception;
}
代碼分析:View接口的任務就是接受模型以及 servlet的request 和 response對象,并將輸出結果渲染到 response;
3)spring自帶了13個視圖解析器
對上表的分析(Analysis): A1)InternalResourceViewResolver:?用于 JSP, TilesViewResolver用于Apache Tiles 視圖, FreeMarkerViewResolver and VelocityViewResolver 分別用于 FreeMaker 和 Velocity模板視圖; A2)Thymeleaf:?是一種用來替代JSP 的新興技術,spring提供了與 Thymeleaf 的原生模板協作的視圖解析器;這種模板之所以得到這樣的稱呼是因為它更像最終產生的HTML,而不是驅動它們的java 代碼;
? 【2】創建JSP視圖 1)spring提供了兩種支持 JSP 的視圖(type) type1)InternalResourceViewResolver?會將視圖名解析為 jsp 文件;如果在jsp頁面中使用了 JSP 標準標簽庫(java server page standard tag library)的話,InternalResourceViewResolver?能夠將視圖名解析為 JstlView 形式的jsp 文件,從而將JSTL 本地化和資源 bundle變量暴露給 JSTL 的格式化和信息標簽; type2)spring提供了兩個JSP 標簽庫:?一個用于表單到模型的綁定,另一個提供了通用的工具類特性; 【2.1】配置適用于JSP的視圖解析器 1)看個荔枝:
@Configuration @EnableWebMvc @ComponentScan(basePackages={"com.spring.chapter5.spittr.web","com.spring.chapter5.spittr.data"}) public class WebConfig extends WebMvcConfigurerAdapter {@Beanpublic ViewResolver viewResolver() { // highlight line.InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/WEB-INF/views/");resolver.setSuffix(".jsp");resolver.setExposeContextBeansAsAttributes(true);return resolver;}@Overridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();} } 【2.1.1】解析JSTL 視圖(jsp standard tag lib-java標準庫標簽) 1)intro:?InternalResourceViewResolver 最終會將邏輯視圖名解析為 InternalResourceView 實例,這個實例會引用jsp文件; 2)如果想讓InternalResourceViewResolver? 將視圖解析為 JstlView,而不是?InternalResourceView?實例的話,只需要設置它的 viewClass屬性即可: @Beanpublic 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;} 3)同樣,在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" /> <span style="font-family: verdana, Arial, Helvetica, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">?</span>
【2.2】使用 spring 的 jsp庫 1)標簽庫的作用:?能夠避免在腳本塊中直接編寫 java 代碼;(干貨——標簽庫的作用) 2)spring提供了兩個JSP 標簽庫:一個用于表單到模型的綁定,另一個提供了通用的工具類特性; ? 【2.2.1】將表單綁定到模型上 1)intro:spring 的表單綁定jsp 標簽庫包含了14個標簽,他們中的大多數都用用來渲染HTML 中的表單標簽; 2)為了使用表單標簽庫,需要在jsp 頁面上對其聲明; <%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>
? 4)我們可以指定email 域: Email: <sf:input path="email" type="email" /><br/> 4.1)得到的 HTML 如下所示: Email: <input id="email" name="email" type="email" value="jack"/><br/>
5)為了矯正用戶輸入錯誤,需要使用 標簽 <sf:errors> ? 【2.2.2】展現錯誤 1)將 <sf:errors> 用到 registerForm.jsp 中的代碼片段中; <sf:form method="POST" commandName="spitter">First Name: <sf:input path="firstName" /><sf:errors path="firstName" /><br/>... </sf:form> 代碼分析(Analysis):?這里path 屬性設置為 firstName,即指定了要顯示 Spitter 模型對象中哪個屬性的的錯誤; ? 看個荔枝)如果用戶提交字母”J“的話,那么如下的HTML 片段就是針對 firstName 輸入域所顯示的內容: First Name: <input id="firstName"name="firstName" type="text" value="J"/> <span id="firstName.errors">size must be between 2 and 30</span> 2)進一步修改錯誤的樣式,使其更加突出顯示;設置 cssClass屬性: <sf:form method="POST" commandName="spitter">First Name: <sf:input path="firstName" /><sf:errors path="firstName" cssClass="error" /><br /> ... </sf:form> 2.1)再定義一個css樣式: span.error {color: red; }?
3)problem+solution: 3.1)problem:在輸入域的旁邊展現錯誤信息是一種很好的方式,但是會帶來布局問題; 3.2)solution:將所有的錯誤信息都 在同一個地方進行顯示;我們可以移除每個輸入域上的 <sf:errors> 元素,并將其放到表單的頂部,如下所示: <sf:form method="POST" commandName="spitter" ><sf:errors path="*" element="div" cssClass="errors" />... </sf:form>? 對以上代碼分析(Analysis):這里的paht被設置為了 “*”,這是一個通配符選擇器;會告訴 <sf: errors> 展現所有屬性的所有錯誤;
4)通過為每個輸入域設置 cssErrorClass 屬性,顯示需要修正的輸入域; <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>? 對以上代碼的分析(Analysis): A1)<sf:label> 標簽:使用path 來指定它屬于模型對象中的 哪個屬性;在本例中,將其設置為 firstName,它會綁定 spitter對象的 firstName屬性; A2)如果校驗錯誤的話,渲染得到 的<label>元素中,class屬性將會被設置為 error: <label for="firstName" class="error">First Name</label>? A3)還可以設置一些css 屬性? label.error {color: red; } input.error {}?
5)如何讓錯誤信息更加易讀。可以在校驗注解上設置 message屬性,使其引用對用戶更為友好的信息,這些信息定義在屬性文件中;并將該屬性文件放在根目錄下; // ValidationMessages.properties 文件內容如下(放置在根類路徑下,即 project/src/ 目錄下): 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.?
【2.2.3】spring 通用的標簽庫 1)要使用spring通用的標簽庫,在頁面上對其進行聲明; <%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>? 2)spring的jsp 標簽庫提供了多個便利的標簽; ?
【2.2.4】展現國際化消息 1)考慮首頁info: <h1>Welcome to Spittr!</h1> ? 1.1)考慮將其國際化,<s:message>標簽就是一個很好地方案; <h1><s:message code="spittr.welcome" /></h1>? 對以上代碼的分析(Analysis):該標簽將會工具 ?key=spittr.welcome 的信息源來渲染文本; 1.2)spring有多個信息源類,都實現了 MessageSource接口,最為常見的是ResourceBundleMessageSource. 1.3)intro to ResourceBundleMessageSource:它會從屬性文件中加載信息,該屬性文件的名稱根據基礎名稱(base name)衍生而來的。如下的 @Bean 方法配置了?ResourceBundleMessageSource: @Beanpublic MessageSource messageSource() {ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();messageSource.setBasename("messages"); // 核心在于設置basename屬性值.return messageSource;}? 對以上代碼的分析(Analysis):將basename屬性值設置為 messages后,SourceBundleMessageSource就會視圖在根路徑的屬性文件中解析信息,這些屬性文件的名稱是根據這個基礎名稱衍生得到的;
1.4)還可以使用ReloadableResourceBundleMessageSource,它能夠重新加載信息屬性,而不必重新編譯或重啟應用,其配置如下: @Beanpublic MessageSource messageSource() {ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();messageSource.setBasename("file:///etc/spittr/messages");messageSource.setCacheSeconds(10);return messageSource;}? 對以上代碼的分析(Analysis): A1)關鍵區別在于 basename 屬性設置為在應用的外部查找(而不是像?ResourceBundleMessageSource 在類路徑下查找); A2)basename的屬性可以設置在類路徑下,文件系統中或web 應用的根路徑下查找屬性;
2)創建屬性文件 2.1)創建默認的屬性文件,名為 messages.properties:它要么位于根路徑下(使用ResourceBundleMessageSource),要么位于pathname屬性指定的路徑下 (使用ReloadableResourceBundleMessageSource); 2.2)對于 spittr.welcome 信息來講,需要如下條目: spittr.welcome=Welcome to Spittr! 2.3)problem+solution: 2.3.1)problem:如果你不再創建其他信息文件的話,我們所做的事情就是將jsp中硬編碼的信息抽取到了屬性文件中,仍然是硬編碼; 2.3.2)solution:如果想要設置西班牙語的話,需要創建另外一個 名為 message_es.properties 的屬性文件 spittr.welcome=Bienvenidos a Spittr! ?
【2.2.5】創建URL 1)intro:<s:url>的主要任務就是創建 URL,然后將其賦值給一個變量或渲染到相應中, 它是 JSTL 中 <c:url> 標簽的替代者;(干貨——<s:url>?是 JSTL 中 <c:url> 標簽的替代者) 2)看幾個荔枝: 2.1)<a href="<s:url href="/spitter/register" />">Register</a>,如果應用的servlet上下文名為 spittr,則 <s:url> 將會渲染為: <a href="/spittr/spitter/register">Register</a>? 2.2)將<s:url> 進行賦值,并使用:? <s:url href="/spitter/register" var="registerUrl" /> <a href="${registerUrl}">Register</a>?
2.3)default case, URL是在頁面作用域內創建的。但通過設置scope 屬性,可以讓 <s:url> 在應用作用域內,會話作用域內或請求作用域內創建URL:(干貨——default case,URL是在頁面作用域內創建的) <s:url href="/spitter/register" var="registerUrl" scope="request" />? 2.4)如果希望添加參數的話,使用 <s:param>標簽; <s:url href="/spittles" var="spittlesUrl"><s:param name="max" value="60" /><s:param name="count" value="20" /> </s:url>? 3)各種需求組團襲來 3.1)假設我們要為特定用戶的基本信息頁面創建一個URL,<s:param> 標簽可以承擔此任;?(干貨——這里用到了占位符{username}) <s:url href="/spitter/{username}" var="spitterUrl"><s:param name="username" value="jbauer" /> </s:url>? 3.2)解決URL 的轉義需求:希望將渲染得到的URL 內容展現在 web 頁面上(而不是作為超鏈接),這就要求 <s:url> 進行HTML 轉義,將 htmlEscape屬性設置為 true; <s:url value="/spittles" htmlEscape="true"><s:param name="max" value="60" /><s:param name="count" value="20" /> </s:url> 所渲染得到的結果為: /spitter/spittles?max=60&count=20? 3.3)解決在?javascript中使用URL的話,應該將 javascriptEscape 屬性設置為 true; <s:url value="/spittles" var="spittlesJSUrl" javaScriptEscape="true"><s:param name="max" value="60" /><s:param name="count" value="20" /> </s:url> <script>var spittlesUrl = "${spittlesJSUrl}" </script>渲染得到的結果為: <script>var spittlesUrl = "\/spitter\/spittles?max=60&count=20" </script>? 【2.2.6】轉義內容(<s:escapeBody> 標簽) 1)intro:<s:escapeBody> 標簽是一個轉義標簽; 2)任務來啦: 2.1)任務一:需要將 ?"<" and ">" 字符替換為 <, >;<s:escapeBody> 可以做到這一點; <s:escapeBody htmlEscape="true"><h1>Hello</h1> </s:escapeBody> 所渲染得到的結果為: <h1>Hello</h1>?
2.2)通過設置 javaScriptEscape屬性,<s:escapeBody> 標簽還支持 JavaScript 轉義: <s:escapeBody javaScriptEscape="true"><h1>Hello</h1> </s:escapeBody>? 【3】使用 Apache Tiles視圖定義布局 1)intro:為了更好的定義視圖布局,引入了布局引擎,如Apache Tiles;(干貨——引入了布局引擎); 【3.1】配置 Tiles 視圖解析器 1)intro:為了在spring 中使用 Tiles,需要配置幾個 bean 1.1)需要一個 TilesConfigurer bean:負責定位和加載 Tile 定義并協調生成 Tiles; 1.2)還需要TilesViewResolver bean:?將邏輯視圖名稱解析為 Tile定義; 2)設置的具體操作: 2.1)需要一個 TilesConfigurer bean:負責定位和加載 Tile 定義并協調生成 Tiles; @Beanpublic TilesConfigurer tilesConfigurer() {TilesConfigurer tiles = new TilesConfigurer();tiles.setDefinitions(new String[] {"/WEB-INF/layout/tiles.xml"});tiles.setCheckRefresh(true);return tiles;} 對以上代碼的分析(Analysis): A1)所要設置的最重要的屬性是 definitions:這個屬性接收一個 string 類型的 數組,其中每個條目都指定一個 Tile定義的 xml 文件; A2)我們可以在數組中指定多個文件,并使用通配符; tiles.setDefinitions(new String[] {"/WEB-INF/**/tiles.xml" });? 對以上代碼的分析(Analysis):? A1)我們要求?TilesConfigurer? 加載 /WEB-INF/ 目錄下的所有名字為 tiles.xml 的文件; A2)上述代碼使用了 Ant 風格的通配符(**);?
2.2)還需要TilesViewResolver bean: 將邏輯視圖名稱解析為 Tile定義; @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" />? Conclusion) C1)TilesConfigurer 會加載 Tile定義并與 Apache Tiles協作; C2)而 TilesViewResolver 會將邏輯視圖名稱解析為引用 Tile 定義的視圖。它是通過查找與 邏輯視圖名稱相匹配的Tile 定義實現該功能的; ? 【3.1.1】 定義Tiles 1)intro:Apache Tiles 提供了一個文檔類型定義(document type definition, DTD),用來在 XML文件中指定Tile的定義。每個定義中需要包含一個 <definition> 元素,這個元素會有一個或多個 <put-attribute>元素; 2)看個荔枝:如下的xml 文檔為 Spittr 應用定義了幾個 Tile: <?xml version="1.0" encoding="ISO-8859-1" ?> <!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"><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"> // hightlight line: 這里用到了繼承,碉堡了.<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>? 對以上代碼的分析(Analysis): A1)每個 <definition> 元素都定義了一個 Tile,它最終引用的是一個 JSP 模板; A2)某個 Tile 可能還引用其他的JSP模板,對于base Tile 來講,引用的是一個頭部 jsp 模板 和 一個底部 jsp 模板; ? 3)base Tile 所引用的page.jap 模板如下面程序清單所示: <%@ taglib uri="http://www.springframework.org/tags" prefix="s" %> <%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="t" %><%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %> <%@ 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>? 對以上代碼的分析(Analysis):重點在于 使用 Tile標簽庫中的 <t:insertAttribute> jsp 標簽來插入其他的模板;插入了 header, body, ?footer 的模板; ?
【4】 使用Thymeleaf 模板 1)problem+solution: 1.1)problem:jsp最明顯的問題:在于它看起來像 HTML 或 XML,但它其實并不是。大多數的jsp 模板都采用了HTML 的形式,但 又摻雜了各種jsp 標簽庫的標簽,使其變得很是混亂; 1.2)solution:Thymelead模板:能在接收原始HTML 的地方進行編輯和渲染。因為它沒有和 servlet規范耦合,因此 Thymeleaf 模板能夠進入jsp 所無法涉足的領域; ? 【4.1】配置 Thymeleaf 視圖解析器 1)intro:為了要在spring中 使用 Thymeleaf,我們要配置三個啟用 Thymeleaf 與 spring集成的bean; 1.1)ThymeleafViewResolver:將邏輯視圖名解析為 Thymeleaf 模板視圖; 1.2)SpringTemplateEngine:處理模板并渲染結果; 1.3)TemplateResolver:?加載 Thymeleaf模板;
2)如下是聲明這些bean 的 java配置; @Beanpublic ViewResolver viewResolver(SpringTemplateEngine templateEngine) {ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();viewResolver.setTemplateEngine(templateEngine);return viewResolver;}@Beanpublic TemplateEngine templateEngine(TemplateResolver templateResolver) {SpringTemplateEngine templateEngine = new SpringTemplateEngine();templateEngine.setTemplateResolver(templateResolver);return templateEngine;}@Beanpublic TemplateResolver templateResolver() {TemplateResolver templateResolver = new ServletContextTemplateResolver();templateResolver.setPrefix("/WEB-INF/templates/");templateResolver.setSuffix(".html");templateResolver.setTemplateMode("HTML5");return templateResolver;}? 2.1)通過XML 聲明這些bean 的java配置 <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" /> Conclusion)不管采用何種配置,Thymeleaf都可以將響應中的模板渲染到 spring mvc 控制器所處理的請求中; ? 3)ThymeleafViewResolver 3.1)intro:ThymeleafViewResolver 是 spring mvc 中?ViewResolver的一個實現類; 3.2)需要注意的是:ThymeleafViewResolver bean 中注入了一個對 ?SpringTemplateEngine?bean 的引用; 3.2)SpringTemplateEngine?會在spring中啟用 Thymeleaf引擎,用來解析模板,并基于這些模板渲染結果; 3.4)TemplateResolver會最終定位和查找模板,它也使用了prefix 和 suffix 屬性。前綴和后綴將會與 邏輯視圖名組合使用,進而定位 Thymeleaf 引擎,它的templateMode屬性被設置為 HTML5,這表明我們預期要解析的模板會渲染成 HTML5 輸出; ? 【4.2】定義 Thymeleaf 模板 1)intro:?Thymeleaf之所以能夠發揮作用,是因為它通過自定義的命名空間,為標準的HTML 標簽集合添加 Thymeleaf屬性; 2)使用 Thymeleaf模板的 home.html源碼 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head><title>Spittr</title><link rel="stylesheet" type="text/css" th:href="@{/resources/style.css}"></link> </head> <body><h1>Welcome to Spittr</h1><a th:href="@{/spittles}">Spittles</a> |<a th:href="@{/spitter/register}">Register</a> </body> </html>? ?
【4.2.1】借助Thymeleaf實現表單綁定 1)review 表單綁定 1.1) 下面展現了在 registration.jsp 中的firname 輸入域: <sf:label path="firstName"cssErrorClass="error">First Name</sf:label>: <sf:input path="firstName" cssErrorClass="error" /><br/>
對上表的分析(Analysis): A1)InternalResourceViewResolver:?用于 JSP, TilesViewResolver用于Apache Tiles 視圖, FreeMarkerViewResolver and VelocityViewResolver 分別用于 FreeMaker 和 Velocity模板視圖; A2)Thymeleaf:?是一種用來替代JSP 的新興技術,spring提供了與 Thymeleaf 的原生模板協作的視圖解析器;這種模板之所以得到這樣的稱呼是因為它更像最終產生的HTML,而不是驅動它們的java 代碼;
? 【2】創建JSP視圖 1)spring提供了兩種支持 JSP 的視圖(type) type1)InternalResourceViewResolver?會將視圖名解析為 jsp 文件;如果在jsp頁面中使用了 JSP 標準標簽庫(java server page standard tag library)的話,InternalResourceViewResolver?能夠將視圖名解析為 JstlView 形式的jsp 文件,從而將JSTL 本地化和資源 bundle變量暴露給 JSTL 的格式化和信息標簽; type2)spring提供了兩個JSP 標簽庫:?一個用于表單到模型的綁定,另一個提供了通用的工具類特性; 【2.1】配置適用于JSP的視圖解析器 1)看個荔枝:
@Configuration @EnableWebMvc @ComponentScan(basePackages={"com.spring.chapter5.spittr.web","com.spring.chapter5.spittr.data"}) public class WebConfig extends WebMvcConfigurerAdapter {@Beanpublic ViewResolver viewResolver() { // highlight line.InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/WEB-INF/views/");resolver.setSuffix(".jsp");resolver.setExposeContextBeansAsAttributes(true);return resolver;}@Overridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();} } 【2.1.1】解析JSTL 視圖(jsp standard tag lib-java標準庫標簽) 1)intro:?InternalResourceViewResolver 最終會將邏輯視圖名解析為 InternalResourceView 實例,這個實例會引用jsp文件; 2)如果想讓InternalResourceViewResolver? 將視圖解析為 JstlView,而不是?InternalResourceView?實例的話,只需要設置它的 viewClass屬性即可: @Beanpublic 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;} 3)同樣,在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" /> <span style="font-family: verdana, Arial, Helvetica, sans-serif; font-size: 14px; background-color: rgb(255, 255, 255);">?</span>
【2.2】使用 spring 的 jsp庫 1)標簽庫的作用:?能夠避免在腳本塊中直接編寫 java 代碼;(干貨——標簽庫的作用) 2)spring提供了兩個JSP 標簽庫:一個用于表單到模型的綁定,另一個提供了通用的工具類特性; ? 【2.2.1】將表單綁定到模型上 1)intro:spring 的表單綁定jsp 標簽庫包含了14個標簽,他們中的大多數都用用來渲染HTML 中的表單標簽; 2)為了使用表單標簽庫,需要在jsp 頁面上對其聲明; <%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>
?3)在注冊JSP 中使用這些標簽后,會得到如下程序:<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> 代碼分析(Analysis):?<sf:form>標簽?會渲染為一個 HTML<form> 標簽,通過?commandName 屬性構建針對某個模型對象的上下文信息;這就需要我們必須要有一個key==spitter的對象;
? 4)我們可以指定email 域: Email: <sf:input path="email" type="email" /><br/> 4.1)得到的 HTML 如下所示: Email: <input id="email" name="email" type="email" value="jack"/><br/>
5)為了矯正用戶輸入錯誤,需要使用 標簽 <sf:errors> ? 【2.2.2】展現錯誤 1)將 <sf:errors> 用到 registerForm.jsp 中的代碼片段中; <sf:form method="POST" commandName="spitter">First Name: <sf:input path="firstName" /><sf:errors path="firstName" /><br/>... </sf:form> 代碼分析(Analysis):?這里path 屬性設置為 firstName,即指定了要顯示 Spitter 模型對象中哪個屬性的的錯誤; ? 看個荔枝)如果用戶提交字母”J“的話,那么如下的HTML 片段就是針對 firstName 輸入域所顯示的內容: First Name: <input id="firstName"name="firstName" type="text" value="J"/> <span id="firstName.errors">size must be between 2 and 30</span> 2)進一步修改錯誤的樣式,使其更加突出顯示;設置 cssClass屬性: <sf:form method="POST" commandName="spitter">First Name: <sf:input path="firstName" /><sf:errors path="firstName" cssClass="error" /><br /> ... </sf:form> 2.1)再定義一個css樣式: span.error {color: red; }?
3)problem+solution: 3.1)problem:在輸入域的旁邊展現錯誤信息是一種很好的方式,但是會帶來布局問題; 3.2)solution:將所有的錯誤信息都 在同一個地方進行顯示;我們可以移除每個輸入域上的 <sf:errors> 元素,并將其放到表單的頂部,如下所示: <sf:form method="POST" commandName="spitter" ><sf:errors path="*" element="div" cssClass="errors" />... </sf:form>? 對以上代碼分析(Analysis):這里的paht被設置為了 “*”,這是一個通配符選擇器;會告訴 <sf: errors> 展現所有屬性的所有錯誤;
4)通過為每個輸入域設置 cssErrorClass 屬性,顯示需要修正的輸入域; <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>? 對以上代碼的分析(Analysis): A1)<sf:label> 標簽:使用path 來指定它屬于模型對象中的 哪個屬性;在本例中,將其設置為 firstName,它會綁定 spitter對象的 firstName屬性; A2)如果校驗錯誤的話,渲染得到 的<label>元素中,class屬性將會被設置為 error: <label for="firstName" class="error">First Name</label>? A3)還可以設置一些css 屬性? label.error {color: red; } input.error {}?
5)如何讓錯誤信息更加易讀。可以在校驗注解上設置 message屬性,使其引用對用戶更為友好的信息,這些信息定義在屬性文件中;并將該屬性文件放在根目錄下; // ValidationMessages.properties 文件內容如下(放置在根類路徑下,即 project/src/ 目錄下): 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.?
【2.2.3】spring 通用的標簽庫 1)要使用spring通用的標簽庫,在頁面上對其進行聲明; <%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>? 2)spring的jsp 標簽庫提供了多個便利的標簽; ?
【2.2.4】展現國際化消息 1)考慮首頁info: <h1>Welcome to Spittr!</h1> ? 1.1)考慮將其國際化,<s:message>標簽就是一個很好地方案; <h1><s:message code="spittr.welcome" /></h1>? 對以上代碼的分析(Analysis):該標簽將會工具 ?key=spittr.welcome 的信息源來渲染文本; 1.2)spring有多個信息源類,都實現了 MessageSource接口,最為常見的是ResourceBundleMessageSource. 1.3)intro to ResourceBundleMessageSource:它會從屬性文件中加載信息,該屬性文件的名稱根據基礎名稱(base name)衍生而來的。如下的 @Bean 方法配置了?ResourceBundleMessageSource: @Beanpublic MessageSource messageSource() {ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();messageSource.setBasename("messages"); // 核心在于設置basename屬性值.return messageSource;}? 對以上代碼的分析(Analysis):將basename屬性值設置為 messages后,SourceBundleMessageSource就會視圖在根路徑的屬性文件中解析信息,這些屬性文件的名稱是根據這個基礎名稱衍生得到的;
1.4)還可以使用ReloadableResourceBundleMessageSource,它能夠重新加載信息屬性,而不必重新編譯或重啟應用,其配置如下: @Beanpublic MessageSource messageSource() {ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();messageSource.setBasename("file:///etc/spittr/messages");messageSource.setCacheSeconds(10);return messageSource;}? 對以上代碼的分析(Analysis): A1)關鍵區別在于 basename 屬性設置為在應用的外部查找(而不是像?ResourceBundleMessageSource 在類路徑下查找); A2)basename的屬性可以設置在類路徑下,文件系統中或web 應用的根路徑下查找屬性;
2)創建屬性文件 2.1)創建默認的屬性文件,名為 messages.properties:它要么位于根路徑下(使用ResourceBundleMessageSource),要么位于pathname屬性指定的路徑下 (使用ReloadableResourceBundleMessageSource); 2.2)對于 spittr.welcome 信息來講,需要如下條目: spittr.welcome=Welcome to Spittr! 2.3)problem+solution: 2.3.1)problem:如果你不再創建其他信息文件的話,我們所做的事情就是將jsp中硬編碼的信息抽取到了屬性文件中,仍然是硬編碼; 2.3.2)solution:如果想要設置西班牙語的話,需要創建另外一個 名為 message_es.properties 的屬性文件 spittr.welcome=Bienvenidos a Spittr! ?
【2.2.5】創建URL 1)intro:<s:url>的主要任務就是創建 URL,然后將其賦值給一個變量或渲染到相應中, 它是 JSTL 中 <c:url> 標簽的替代者;(干貨——<s:url>?是 JSTL 中 <c:url> 標簽的替代者) 2)看幾個荔枝: 2.1)<a href="<s:url href="/spitter/register" />">Register</a>,如果應用的servlet上下文名為 spittr,則 <s:url> 將會渲染為: <a href="/spittr/spitter/register">Register</a>? 2.2)將<s:url> 進行賦值,并使用:? <s:url href="/spitter/register" var="registerUrl" /> <a href="${registerUrl}">Register</a>?
2.3)default case, URL是在頁面作用域內創建的。但通過設置scope 屬性,可以讓 <s:url> 在應用作用域內,會話作用域內或請求作用域內創建URL:(干貨——default case,URL是在頁面作用域內創建的) <s:url href="/spitter/register" var="registerUrl" scope="request" />? 2.4)如果希望添加參數的話,使用 <s:param>標簽; <s:url href="/spittles" var="spittlesUrl"><s:param name="max" value="60" /><s:param name="count" value="20" /> </s:url>? 3)各種需求組團襲來 3.1)假設我們要為特定用戶的基本信息頁面創建一個URL,<s:param> 標簽可以承擔此任;?(干貨——這里用到了占位符{username}) <s:url href="/spitter/{username}" var="spitterUrl"><s:param name="username" value="jbauer" /> </s:url>? 3.2)解決URL 的轉義需求:希望將渲染得到的URL 內容展現在 web 頁面上(而不是作為超鏈接),這就要求 <s:url> 進行HTML 轉義,將 htmlEscape屬性設置為 true; <s:url value="/spittles" htmlEscape="true"><s:param name="max" value="60" /><s:param name="count" value="20" /> </s:url> 所渲染得到的結果為: /spitter/spittles?max=60&count=20? 3.3)解決在?javascript中使用URL的話,應該將 javascriptEscape 屬性設置為 true; <s:url value="/spittles" var="spittlesJSUrl" javaScriptEscape="true"><s:param name="max" value="60" /><s:param name="count" value="20" /> </s:url> <script>var spittlesUrl = "${spittlesJSUrl}" </script>渲染得到的結果為: <script>var spittlesUrl = "\/spitter\/spittles?max=60&count=20" </script>? 【2.2.6】轉義內容(<s:escapeBody> 標簽) 1)intro:<s:escapeBody> 標簽是一個轉義標簽; 2)任務來啦: 2.1)任務一:需要將 ?"<" and ">" 字符替換為 <, >;<s:escapeBody> 可以做到這一點; <s:escapeBody htmlEscape="true"><h1>Hello</h1> </s:escapeBody> 所渲染得到的結果為: <h1>Hello</h1>?
2.2)通過設置 javaScriptEscape屬性,<s:escapeBody> 標簽還支持 JavaScript 轉義: <s:escapeBody javaScriptEscape="true"><h1>Hello</h1> </s:escapeBody>? 【3】使用 Apache Tiles視圖定義布局 1)intro:為了更好的定義視圖布局,引入了布局引擎,如Apache Tiles;(干貨——引入了布局引擎); 【3.1】配置 Tiles 視圖解析器 1)intro:為了在spring 中使用 Tiles,需要配置幾個 bean 1.1)需要一個 TilesConfigurer bean:負責定位和加載 Tile 定義并協調生成 Tiles; 1.2)還需要TilesViewResolver bean:?將邏輯視圖名稱解析為 Tile定義; 2)設置的具體操作: 2.1)需要一個 TilesConfigurer bean:負責定位和加載 Tile 定義并協調生成 Tiles; @Beanpublic TilesConfigurer tilesConfigurer() {TilesConfigurer tiles = new TilesConfigurer();tiles.setDefinitions(new String[] {"/WEB-INF/layout/tiles.xml"});tiles.setCheckRefresh(true);return tiles;} 對以上代碼的分析(Analysis): A1)所要設置的最重要的屬性是 definitions:這個屬性接收一個 string 類型的 數組,其中每個條目都指定一個 Tile定義的 xml 文件; A2)我們可以在數組中指定多個文件,并使用通配符; tiles.setDefinitions(new String[] {"/WEB-INF/**/tiles.xml" });? 對以上代碼的分析(Analysis):? A1)我們要求?TilesConfigurer? 加載 /WEB-INF/ 目錄下的所有名字為 tiles.xml 的文件; A2)上述代碼使用了 Ant 風格的通配符(**);?
2.2)還需要TilesViewResolver bean: 將邏輯視圖名稱解析為 Tile定義; @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" />? Conclusion) C1)TilesConfigurer 會加載 Tile定義并與 Apache Tiles協作; C2)而 TilesViewResolver 會將邏輯視圖名稱解析為引用 Tile 定義的視圖。它是通過查找與 邏輯視圖名稱相匹配的Tile 定義實現該功能的; ? 【3.1.1】 定義Tiles 1)intro:Apache Tiles 提供了一個文檔類型定義(document type definition, DTD),用來在 XML文件中指定Tile的定義。每個定義中需要包含一個 <definition> 元素,這個元素會有一個或多個 <put-attribute>元素; 2)看個荔枝:如下的xml 文檔為 Spittr 應用定義了幾個 Tile: <?xml version="1.0" encoding="ISO-8859-1" ?> <!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"><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"> // hightlight line: 這里用到了繼承,碉堡了.<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>? 對以上代碼的分析(Analysis): A1)每個 <definition> 元素都定義了一個 Tile,它最終引用的是一個 JSP 模板; A2)某個 Tile 可能還引用其他的JSP模板,對于base Tile 來講,引用的是一個頭部 jsp 模板 和 一個底部 jsp 模板; ? 3)base Tile 所引用的page.jap 模板如下面程序清單所示: <%@ taglib uri="http://www.springframework.org/tags" prefix="s" %> <%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="t" %><%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %> <%@ 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>? 對以上代碼的分析(Analysis):重點在于 使用 Tile標簽庫中的 <t:insertAttribute> jsp 標簽來插入其他的模板;插入了 header, body, ?footer 的模板; ?
【4】 使用Thymeleaf 模板 1)problem+solution: 1.1)problem:jsp最明顯的問題:在于它看起來像 HTML 或 XML,但它其實并不是。大多數的jsp 模板都采用了HTML 的形式,但 又摻雜了各種jsp 標簽庫的標簽,使其變得很是混亂; 1.2)solution:Thymelead模板:能在接收原始HTML 的地方進行編輯和渲染。因為它沒有和 servlet規范耦合,因此 Thymeleaf 模板能夠進入jsp 所無法涉足的領域; ? 【4.1】配置 Thymeleaf 視圖解析器 1)intro:為了要在spring中 使用 Thymeleaf,我們要配置三個啟用 Thymeleaf 與 spring集成的bean; 1.1)ThymeleafViewResolver:將邏輯視圖名解析為 Thymeleaf 模板視圖; 1.2)SpringTemplateEngine:處理模板并渲染結果; 1.3)TemplateResolver:?加載 Thymeleaf模板;
2)如下是聲明這些bean 的 java配置; @Beanpublic ViewResolver viewResolver(SpringTemplateEngine templateEngine) {ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();viewResolver.setTemplateEngine(templateEngine);return viewResolver;}@Beanpublic TemplateEngine templateEngine(TemplateResolver templateResolver) {SpringTemplateEngine templateEngine = new SpringTemplateEngine();templateEngine.setTemplateResolver(templateResolver);return templateEngine;}@Beanpublic TemplateResolver templateResolver() {TemplateResolver templateResolver = new ServletContextTemplateResolver();templateResolver.setPrefix("/WEB-INF/templates/");templateResolver.setSuffix(".html");templateResolver.setTemplateMode("HTML5");return templateResolver;}? 2.1)通過XML 聲明這些bean 的java配置 <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" /> Conclusion)不管采用何種配置,Thymeleaf都可以將響應中的模板渲染到 spring mvc 控制器所處理的請求中; ? 3)ThymeleafViewResolver 3.1)intro:ThymeleafViewResolver 是 spring mvc 中?ViewResolver的一個實現類; 3.2)需要注意的是:ThymeleafViewResolver bean 中注入了一個對 ?SpringTemplateEngine?bean 的引用; 3.2)SpringTemplateEngine?會在spring中啟用 Thymeleaf引擎,用來解析模板,并基于這些模板渲染結果; 3.4)TemplateResolver會最終定位和查找模板,它也使用了prefix 和 suffix 屬性。前綴和后綴將會與 邏輯視圖名組合使用,進而定位 Thymeleaf 引擎,它的templateMode屬性被設置為 HTML5,這表明我們預期要解析的模板會渲染成 HTML5 輸出; ? 【4.2】定義 Thymeleaf 模板 1)intro:?Thymeleaf之所以能夠發揮作用,是因為它通過自定義的命名空間,為標準的HTML 標簽集合添加 Thymeleaf屬性; 2)使用 Thymeleaf模板的 home.html源碼 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head><title>Spittr</title><link rel="stylesheet" type="text/css" th:href="@{/resources/style.css}"></link> </head> <body><h1>Welcome to Spittr</h1><a th:href="@{/spittles}">Spittles</a> |<a th:href="@{/spitter/register}">Register</a> </body> </html>? ?
【4.2.1】借助Thymeleaf實現表單綁定 1)review 表單綁定 1.1) 下面展現了在 registration.jsp 中的firname 輸入域: <sf:label path="firstName"cssErrorClass="error">First Name</sf:label>: <sf:input path="firstName" cssErrorClass="error" /><br/>
2)考慮如下的 Thymeleaf模板片段,它會渲染first name輸入域:
<label th:class="${#fields.hasErrors('firstName')}? 'error'">First Name</label>: <input type="text" th:field="*{firstName}"th:class="${#fields.hasErrors('firstName')}? 'error'" /><br/>
對以上代碼分析(Analysis):
A1)不再使用jsp 標簽中的 cssClassName 屬性,而是在標準的HTML 標簽中上使用 th:class 屬性;th:class 屬性會渲染成為一個 class屬性; A2)<input> 標簽使用了 th:field 屬性,用來引用后端對象的 firstname域; 3)以下代碼暫時了完整的注冊表單模板 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <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> Listing 6.7 Registration page, using Thymeleaf to bind a form to a command object Display errors 192 CHAPTER 6 Rendering web views </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> </body> </html>??
總結
以上是生活随笔為你收集整理的spring(6) 渲染web视图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么把图片html代码(怎么把图片htm
- 下一篇: intro to JNDI