Spring——Spring MVC(二)

本文主要依據《Spring實戰》第六章內容進行總結

1、Spring MVC視圖解析器

上一節主要介紹了Spring MVC中的控制器,介紹了控制器如何獲取用戶的請求數據,進行業務邏輯處理之後,將處理結果也就是模型傳遞給用來渲染的視圖,但是控制器返回的只是一個邏輯視圖名稱,不會直接引用具體的視圖實現。而要確定使用哪一個視圖實現來渲染模型是視圖解析器的任務。將控制器中請求處理的邏輯和視圖中渲染實現解耦是Spring MVC的一個重要特性。

Spring MVC定義了一個ViewResolver接口:

public interface ViewResolver {
    View resolveViewName(String viewName, Locale locale) throws Exception;
}

當給resolveViewName()方法傳入一個視圖名和Locale對象時,它會返回一個View實例,View也是一個接口:

public interface View {
    void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}

View接口的任務就是接受模型以及Servlet的request和response對象,並將輸出結果渲染到response中。

可以看到,要將模型數據展示到瀏覽器中,只需實現ViewResolver和View,將要渲染的內容放到response中,進而展現到用戶的瀏覽器中。實際上,Spring提供了多個內置的實現,能夠適應大多數的場景,在這裏我們就不一一詳細地介紹了,着重介紹一下InternalResourceViewResolver,它主要用來解析JSP視圖。

2、創建JSP視圖

Spring提供了兩種支持JSP視圖的方式:

  • InternalResourceViewResolver會將視圖名解析爲JSP文件。另外,如果在JSP頁面中使用了JSP標準標籤庫(JSTL),InternalResourceViewResolver能夠將視圖名解析爲JstlView形式的JSP文件,從而將JSTL本地化和資源bundle變量暴露給JSTL的格式化和信息標籤。
  • Spring提供了兩個JSP標籤庫,一個用於表單到模型的綁定,另一個提供了通用的工具類特性。

2.1、配置適用於JSP的視圖解析器

有一些視圖解析器,如ResourceBundleViewResolver會直接將邏輯視圖名映射爲特定的View接口實現,而InternalResourceViewResolver所採取方式並不那麼直接,它遵循一種約定,會在視圖名上添加前綴和後綴,進而確定一個Web應用中視圖資源的物理路徑。

例如,在上一節的例子中,我們要訪問的home.jsp,放在/WEB-INF/views目錄下:

這裏寫圖片描述

這樣能夠防止對它的直接訪問,如果我們將所有的JSP文件都放在/WEB-INF/views目錄下,並且home頁的JSP名爲home.jsp,那麼我們可以確定物理視圖的路徑就是邏輯視圖名home再加上“/WEB-INF/views”前綴和“.jsp”後綴。

在上一節中,我們使用Java配置的方式配置InternalResourceViewResolver,使其在解析視圖時,遵循上述的約定:

@Bean
public ViewResolver viewResolver() {
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix("/WEB-INF/views/");//配置前綴
    resolver.setSuffix(".jsp");//配置後綴
    return resolver;
}

我們也可以通過xml的方式來配置InternalResourceViewResolver:

<bean id="viewResolver"
      class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
    <property name="prefix" value="/WEB-INF/views/"/>  
    <property name="suffix" value=".jsp"/>  
</bean> 

InternalResourceViewResolver配置好之後,它就會將邏輯視圖名稱解析爲JSP文件,例如:home會被解析爲/WEB-INF/views/home.jsp,books/detail會被解析爲/WEB-INF/views/books/detail.jsp,在這裏,當邏輯視圖名中包含斜線時,這個斜線也會帶到資源的路徑中。

2.1.1、解析JSTL視圖

到目前爲止,我們對InternalResourceViewResolver的配置都很基礎和簡單,它最終會將邏輯視圖名解析爲InternalResourceView實例,這個實例會引用JSP文件。但是,如果這些JSP使用JSTL標籤來處理格式化和信息的話,那麼我們會希望InternalResourceViewResolver將視圖解析爲JstlView。要使InternalResourceViewResolver將視圖解析爲JstlView,只需要設置它的viewClass屬性即可:

@Bean
public ViewResolver viewResolver() {
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix("/WEB-INF/views/");
    resolver.setSuffix(".jsp");
    resolver.setViewClass(JstlView.class);
    return resolver;
}

我們也可以通過xml來配置viewClass屬性:

<bean id="viewResolver"
      class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
    <property name="prefix" value="/WEB-INF/views/"/>  
    <property name="suffix" value=".jsp"/>
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>  
</bean> 

2.2、使用Spring的JSP標籤庫

Spring提供了兩個JSP標籤庫,一個標籤庫會用來渲染HTML表單標籤,這些標籤可以綁定model中的某個屬性,另外一個標籤包含了一些工具類標籤,我們隨時可以非常便利地使用它們。

2.2.1、將表單綁定到模型上

Spring的表單綁定JSP標籤庫主要用來渲染HTML中的表單標籤,它會綁定模型中的一個對象,能夠根據模型中對象的屬性填充值,標籤庫中還包含了一個爲用戶展現錯誤的標籤,它會將錯誤信息渲染到最終的HTML中。

爲了使用表單綁定標籤,需要在JSP頁面中對其進行聲明:

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf"%>

在這裏,我們將前綴指定爲”sf”,實際上,前綴可以指定爲任意值,在這裏爲了簡潔方便,我們才指定爲”sf”。聲明瞭表單綁定標籤庫之後,我們就可以使用這些標籤了:

JSP標籤 描述
<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:lable> 渲染成一個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:radiobuttons> 渲染成多個HTML<input> 標籤,其中type屬性設置爲radio
<sf:select> 渲染爲一個HTML<select> 標籤
<sf:textarea> 渲染爲一個HTML<textarea> 標籤

在這裏我們就不詳細介紹每一個標籤的用法了,我們根據上節介紹的學生信息錄入功能來介紹幾個常用的表單綁定標籤,首先,我們需要改寫一下學生信息錄入的頁面,之前的頁面由原生的HTML標籤組成:

<form action="addStudent" method="post">
    ID:<input type="text" name="id"/><br/>
    姓名:<input type="text" name="name"/><br/>
    性別:<input type="text" name="sex"/><br/>
    <input type="submit" value="提交"/>
</form>

現在我們使用上面表格中介紹的表單綁定標籤改寫上述內容:

<sf:form action="addStudent" method="post" commandName="student">
        ID:<sf:input path="id"/><br/>
        姓名:<sf:input path="name"/><br/>
        性別:<sf:input path="sex"/><br/>
        <input type="submit" value="提交">
</sf:form>

我們使用了<sf:form> 標籤來渲染一個HTML<form> 標籤,它通過commandName屬性構建針對某個模型對象的上下文信息,在這裏,我們將commandName設置爲student,因此,在模型中必須要有一個key爲student的對象,否則,表單不能正常渲染,所以我們在Controller中添加如下的處理方法:

@RequestMapping(value="/addStudent",method=RequestMethod.GET)
public String toAddStudent(Model model) {
    model.addAttribute(new Student());
    return "addStudent";
}

在這個方法中我們沒有指定key值,但是,Spring可以通過返回類型推斷得到,因爲返回的是一個Student對象,所以key爲student。

另外,我們將HTML的<input> 標籤改寫爲<sf:input> ,它會渲染爲一個HTML的<input> 標籤,並且type屬性爲text。在這裏,我們還設置了<sf:input> 的path屬性,<input> 標籤的value屬性值將會設置爲模型對象中path屬性所對應的值。

爲了能夠看到表單綁定標籤的實際效果,我們在學生信息錄入頁面錄入一些不合法的信息,如下所示:

這裏寫圖片描述

點擊提交,因爲錄入的信息不合法,所以頁面不會跳轉到錄入成功頁面,而是重定向到錄入頁面,並且表單中會預先填充之前輸入的值,我們可以通過生成的HTML元素來確認:

<form id="student" action="addStudent" method="post">
    ID:<input id="id" name="id" type="text" value="0"/><br/>
    姓名:<input id="name" name="name" type="text" value="aa"/><br/>
    性別:<input id="sex" name="sex" type="text" value="1234567890"/><br/>
    <input type="submit" value="提交">
</form>

2.2.2、展現錯誤

在上一節的案例中,我們錄入了一些不合法的要素,Spring對這些要素校驗不通過之後,會直接重定向到錄入頁面,但是有兩點我們沒有介紹:首先,我們沒有介紹Spring是如何校驗表單的;其次,雖然Spring對錶單元素進行了校驗,但是校驗的結果沒有展示在前臺頁面,我們也不知道哪裏錄入的有問題。在本節中,我們將詳細介紹這兩點。

2.2.2.1、校驗表單

校驗表單要素的方法有很多,最簡單的方法就是直接在控制器的處理方法中校驗錄入元素的合法性,然後將校驗結果返回給頁面,但是這樣處理會使處理方法變得異常複雜。

我們可以使用Spring對Java校驗API(Java Validation API,又稱爲JSR-303)的支持來進行校驗,從Spring 3.0開始,在Spring MVC中提供了對Java校驗API的支持,我們不需要額外的配置,只要在類路徑下包含Java校驗API的實現即可,比如Hibernate Validator,在這裏,我們需要引入相應的依賴包:

<dependency>  
    <groupId>javax.validation</groupId>  
        <artifactId>validation-api</artifactId>  
        <version>1.1.0.Final</version>  
    </dependency> 
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.1.0.Final</version>
</dependency>

一開始我們引入的Hibernage Validator版本爲4.3.1.Final,但是啓動服務器之後就出現如下異常:

Caused by: java.lang.AbstractMethodError: org.hibernate.validator.engine.ConfigurationImpl.getDefaultParameterNameProvider()

在網上查了資料之後,初步判斷應該是Hibernage Validator版本兼容性問題,將版本升至5.1.0.Final之後問題解決。

Java校驗API定義了多個註解,這些註解可以放到屬性上,從而限制這些屬性的值,所有的註解都位於javax.validation.constraints包中,下表列出了這些校驗註解:

註解 描述
@AssertFalse 所註解的元素必須是Boolean類型,並且值爲false
@AssertTrue 所註解的元素必須是Boolean類型,並且值爲true
@DecimalMax 所註解的元素必須是數字,並且它的值要小於或等於給定的BigDecimalString值
@DecimalMin 所註解的元素必須是數字,並且它的值要大於或等於給定的BigDecimalString值
@Digits 所註解的元素必須是數字,並且它的值必須有指定的位數
@Future 所註解的元素的值必須是一個將來的日期
@Max 所註解的元素必須是數字,並且它的值要小於或等於給定的值
@Min 所註解的元素必須是數字,並且它的值要大於或等於給定的值
@NotNull 所註解的元素的值必須不能爲null
@Null 所註解的元素的值必須爲null
@Past 所註解的元素的值必須是一個一過去的日期
@Pattern 所註解的元素的值必須匹配給定的正則表達式
@Size 所註解的元素的值必須是String、集合或數組,並且它的長度要符合給定的範圍

有了這些註解,我們可以修改Student類,爲它的屬性添加一些校驗註解:

package model;

import java.util.ArrayList;
import java.util.List;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class Student {

    @NotNull
    @Min(value=1)           //非空,必須是數字,最小值爲1
    private int id;

    @NotNull
    @Size(min=5, max=16)    //非空,5到16個字符
    private String name;

    @NotNull
    @Size(min=1, max=8)     //非空,1到8個字符
    private String sex;

    ……

}

在修改後的Student類中,我們使用@NotNull註解以確保屬性的值都不能爲null,另外使用@Min註解表示id屬性的值最小爲1,使用@Size註解限制name和sex的長度,也就是說在信息錄入頁面,用戶必須錄入指定長度的name和sex信息。

在Student中添加了校驗註解之後,我們需要修改控制器的addStudent()方法來啓用校驗功能:

@RequestMapping(value="/addStudent",method=RequestMethod.POST)
public String addStudent(@Valid Student student, Errors errors, Model model) {
    //校驗表單提交的數據,如果校驗出現錯誤,則返回錄入頁面
    if(errors.hasErrors()) {
        model.addAttribute(student);
        return "addStudent";
    }
    ……
    //添加學生信息
}

在上面的代碼中,我們首先在表單參數類Student前面添加了@Valid註解,這會告知Spring,需要確保這個對象滿足校驗限制。如果校驗出現錯誤的話,這些錯誤可以通過Errors對象進行訪問,所以我們將Errors作爲參數傳入addStudent()方法中,值得注意的是,Errors參數要緊跟在帶有@Valid註解的參數後面,@Valid註解所標註的就是要校驗的參數。完成了表單的校驗之後,接下來我們就看一下如何將校驗的結果顯示在頁面上。

2.2.2.2、展現錯誤

如果存在校驗錯誤的話,請求中會包含錯誤的詳細信息,這些信息是與模型數據放到一起的,我們需要做的就是到模型中將這些數據抽取出來,並展現給用戶。我們可以通過<sf:errors> 標籤來完成。例如,我們修改錄入學生信息頁面:

<sf:form action="addStudent" method="post" commandName="student">
    ID:<sf:input path="id"/><sf:errors path="id" /><br/>
    姓名:<sf:input path="name"/><sf:errors path="name" /><br/>
    性別:<sf:input path="sex"/><sf:errors path="sex" /><br/>
    <input type="submit" value="提交">
</sf:form>

可以看到,我們在每一個輸入域後面都新增了一個<sf:errors> 標籤,它的path屬性設置爲Student模型對象中對應的屬性,也就是說,通過path屬性指定Student模型對象中哪個屬性的錯誤。如果屬性沒有錯誤的話,那麼<sf:errors> 不會渲染任何內容。但如果有校驗錯誤的話,那麼它將會在一個HTML<span> 標籤中顯示錯誤信息。例如,如果我們在上面的學生信息錄入頁面錄入不合法的信息,<sf:errors> 會渲染相應的格式錯誤信息:

這裏寫圖片描述

而生成的HTML中也會加入相應的錯誤信息:

<form id="student" action="addStudent" method="post">
    ID:<input id="id" name="id" type="text" value="0"/><span id="id.errors">最小不能小於1</span><br/>
    姓名:<input id="name" name="name" type="text" value="aa"/><span id="name.errors">個數必須在5和16之間</span><br/>
    性別:<input id="sex" name="sex" type="text" value="1234567890"/><span id="sex.errors">個數必須在1和8之間</span><br/>
    <input type="submit" value="提交">
</form>

在上面這個例子中,錯誤信息的樣式是默認的HTML樣式,並沒有突出顯示,我們可以通過設置<sf:errors> 標籤的cssClass屬性來爲其指定樣式,我們修改一下代碼:

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<style>
    span.error {
        color:red;
    }
</style>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <h1>請錄入學生信息</h1>
    <sf:form action="addStudent" method="post" commandName="student">
        ID:<sf:input path="id"/><sf:errors path="id" cssClass="error"/><br/>
        姓名:<sf:input path="name"/><sf:errors path="name" cssClass="error"/><br/>
        性別:<sf:input path="sex"/><sf:errors path="sex" cssClass="error"/><br/>
        <input type="submit" value="提交">
    </sf:form>
</body>
</html>

這樣如果出現格式錯誤的話,錯誤信息會標紅顯示:

這裏寫圖片描述

上面這種方式是在每個輸入域旁邊顯示錯誤信息,我們還可以將所有的錯誤信息在同一個地方顯示,要做到這一點,我們可以移除每個輸入域上的<sf:errors> 元素,並將其放到表單的頂部:

<sf:form action="addStudent" method="post" commandName="student">
    <sf:errors path="*" cssClass="error" element="div"/>
    ID:<sf:input path="id"/><br/>
    姓名:<sf:input path="name"/><br/>
    性別:<sf:input path="sex"/><br/>
    <input type="submit" value="提交">
</sf:form>

在這裏,我們將path屬性設置爲”*”,這是一個通配符選擇器,會告訴<sf:errors> 展現所有屬性的所有錯誤。另外我們還是用了element屬性將錯誤信息渲染在一個<div> 標籤中,我們再修改一下樣式信息:

div.error {
    color:red;
}

這樣,當我們錄入非法要素時,頁面會在表單頭顯示錯誤信息:

這裏寫圖片描述

如果出現校驗錯誤,我們還想要着重顯示需要修正的輸入域,我們可以通過爲每個輸入域設置cssErrorClass屬性,另外,我們還可以使用<sf:label> 標籤來渲染<label> 元素:

<sf:form action="addStudent" method="post" commandName="student">
    <sf:errors path="*" cssClass="error" element="div"/>
    <sf:label path="id" cssErrorClass="error">ID:</sf:label><sf:input path="id" cssErrorClass="error"/><br/>
    <sf:label path="name" cssErrorClass="error">姓名:</sf:label><sf:input path="name" cssErrorClass="error"/><br/>
    <sf:label path="sex" cssErrorClass="error">性別:</sf:label><sf:input path="sex" cssErrorClass="error"/><br/>
    <input type="submit" value="提交">
</sf:form>

<sf:label> 標籤像其他的表單綁定標籤一樣,使用path來指定它屬於模型對象中哪個屬性,如果沒有出現校驗錯誤,那麼它會渲染爲如下的HTML:

<label for="id">ID:</label>

如果出現校驗錯誤,它也會根據cssErrorClass屬性設置的樣式顯示爲相應的效果,並將渲染的<label> 標籤class屬性設置爲cssErrorClass屬性的值:

<label for="name" class="error">姓名:</label>

我們再爲label和input設置樣式:

label.error {
    color:red;
}
input.error {
    background-color: #ffcccc;
}

接下來我們嘗試在錄入頁面錄入一些不合法的元素,頁面會集中顯示錯誤信息並着重顯示需要修正的輸入域:

這裏寫圖片描述

上面的例子中我們已經能夠對頁面錄入的元素進行校驗,但是如果錯誤信息集中顯式在表單開頭的話,我們很難確認每條錯誤信息對應的是哪一個輸入域,而且錯誤信息的內容並不友好,例如上圖中顯示的錯誤信息,我們很難定位“個數必須在5和16之間”還有“個數必須在1和8之間”分別是指哪一個輸入域的格式錯誤。爲了使錯誤信息更加易讀友好,我們需要修改一下Student類中定義的格式校驗:

public class Student {

    @NotNull
    @Min(value=1, message="ID格式錯誤")
    private int id;

    @NotNull
    @Size(min=5, max=16, message="姓名格式錯誤")
    private String name;

    @NotNull
    @Size(min=1, max=8, message="性別格式錯誤")
    private String sex;

    ……  
}

我們在每個校驗註解中添加了message屬性,併爲其制定了對應的內容,這樣修改之後,如果出現格式錯誤,message屬性中的錯誤信息將會展現給用戶:

這裏寫圖片描述

上面的錯誤信息仍然存在一個問題,現在雖然已經友好地提示了用戶哪些輸入域存在問題,但是並沒有指出具體的輸入域正確格式是什麼,還有就是雖然在Student類中指定了相關輸入域的長度限制,但是如果長度限制修改之後,頁面的錯誤提示也需要能夠同步更新,要做到以上兩點,我們需要重新配置一下message屬性:

public class Student {

    @NotNull
    @Min(value=1, message="{id.min}")
    private int id;

    @NotNull
    @Size(min=5, max=16, message="{name.size}")
    private String name;

    @NotNull
    @Size(min=1, max=8, message="{sex.size}")
    private String sex;

    ……  
}

這一次,我們將message屬性中值使用大括號括了起來,這樣message中的值是屬性文件中的某一個屬性,該屬性包含了實際的信息,接下來我們就需要在根類路徑下創建一個名爲ValidationMessages.properties的文件,文件內容爲:

id.min=ID最小爲{value}
name.size=姓名長度要在{min}到{max}之間
sex.size=性別長度要在{min}到{max}之間

ValidationMessages.properties文件中每條信息的key值對應於註解中message屬性佔位符的值,同時最大和最小長度等信息也沒有硬編碼在ValidationMessages.properties文件中,在這個用戶友好的信息中也有自己的佔位符{value}、{min}、{max},它會引用@Min和@Size註解上所設置的value、min和max屬性。因此,我們測試錄入頁面,可以得到我們想要的校驗結果:

這裏寫圖片描述

將這些錯誤信息抽取到屬性文件中還會帶來一個好處,那就是我們可以通過創建地域相關的屬性文件,爲用戶展現特定語言和地域的信息,例如,如果用戶的瀏覽器設置爲英語,那就應該展示英語的報錯信息,我們就需要創建一個名爲ValidationMessages_en_US.properties的配置文件。我們可以按需創建任意數量的ValidationMessages.properties文件,使其涵蓋我們想支持的所有語言和地域。

2.2.3、Spring通用標籤庫

除了表單綁定標籤庫之外,Spring還提供了更爲通用的JSP標籤庫,而要使用Spring通用的標籤庫,我們必須在頁面上對其進行聲明:

<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>

當然,和聲明表單綁定標籤庫一樣,這裏聲明的前綴可以爲任意值,我們爲了使用方便設置爲“s”。

Spring提供了多個通用標籤,在這裏我們只介紹幾個常用的標籤,其餘的標籤在使用時查閱相關手冊文檔即可。

2.2.3.1、展現國際化信息

目前我們的JSP頁面中,很多文本內容都是硬編碼在JSP中的,如果Web系統需要根據用戶的語言環境顯示相應語言的信息,現有的JSP頁面很難滿足我們的需求,所以我們需要能夠在頁面上展示國際化的信息。例如,在home.jsp頁面中,我們原有的頁面如下:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>主頁</title>
</head>
<body>
    <h1>這是主頁</h1>
</body>
</html>

我們只顯示了中文的信息,現在,我們在英文的語言環境下想顯示英文的主頁提示,我們可以藉助<s:message> 標籤來完成:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title><s:message code="homepage" /></title>
</head>
<body>
    <h1><s:message code="thisIsHomepage" /></h1>
</body>
</html>

我們使用<s:message> 標籤來替換原有的硬編碼文本,這樣<s:message> 就會根據key值爲<s:message> 標籤中code屬性的值去信息源中查找文本信息,然後渲染文本,現在我們需要配置一個信息源。

Spring有多個配置信息源的類,它們都實現了MessageSource接口,在這些類中,最常用的是ResourceBundleMessageSource。它會從一個屬性文件中加載信息,這個屬性文件的名稱是根據基礎名稱衍生而來的:

@Bean
public MessageSource messageSource() {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    messageSource.setBasename("message");

    return messageSource;
}

在這裏我們使用Java配置的方式聲明瞭一個信息源,在這個聲明中,核心在於設置basename屬性,可以將其設置爲任意喜歡的值,在這裏我們設置的是message,ResourceBundleMessageSource會試圖在根路徑的屬性文件中解析信息,這些屬性文件的名稱是根據這個基礎名稱衍生得到的,例如,對於中文的環境,我們有message_zh_CN.properties,英文的環境我們有message_en_US.properties等等。

英文環境的message_en_US.properties:

homepage=homepage
thisIsHomepage=This is Homepage

中文環境的message_zh_CN.properties:

homepage=主頁
thisIsHomepage=這是主頁

接下來,我們可以訪問主頁,如果我們的瀏覽器語言環境爲中文,則顯示中文信息:

這裏寫圖片描述

如果瀏覽器語言環境爲英文,則顯示英文的主頁信息:

這裏寫圖片描述

另一個信息源的類是ReloadableResourceBundleMessageSource,它的工作方式和ResourceBundleMessageSource非常相似,但是它能夠重新加載信息屬性,而不必重新編譯或重啓應用:

@Bean
public MessageSource messageSource() {
    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setBasename("file:f:/config/message");
    messageSource.setCacheSeconds(10);

    return messageSource;
}

在上面的配置中,我們basename設置爲外部路徑file:f:/config/message,而不是ResourceBundleMessageSource在類路徑下查找,實際上ReloadableResourceBundleMessageSource的basename屬性可以設置爲在類路徑下(以“classpath:”作爲前綴)、文件系統中(以“file:”作爲前綴)或Web應用的根路徑下(沒有前綴)查找屬性。ResourceBundleMessageSource只能在類路徑下查找屬性。

2.2.3.2、創建URL

<s:url> 標籤可以創建URL,然後將其賦值給一個變量或者渲染到響應中。<s:url> 會接受一個相對於Servlet上下文的URL,並在渲染的時候,預先添加上Servlet上下文路徑。例如,下面這個例子就是<s:url> 標籤的基本用法:

<a href="<s:url value="/addStudent" />">添加學生</a>

如果Servlet上下文名爲spring_mvc1,那麼在響應中將會渲染如下的HTML:

<a href="/spring_mvc1/addStudent">添加學生</a>

這樣,我們在創建URL的時候,就不用再擔心Servlet上下文路徑是什麼了,<s:url> 將會負責這件事。

另外,我們還可以使用<s:url> 創建URL,並將其賦值給一個變量供頁面在稍後使用:

<s:url value="/addStudent" var="add"/>
<a href="${add }">添加學生</a>

默認情況下,URL是在頁面作用域內創建的,但是通過設置scope屬性,我們可以讓<s:url> 在應用作用域內、會話作用域內或請求作用域內創建URL:

<s:url value="/addStudent" var="add" scope="request"/>

如果希望URL上添加參數的話,我們可以使用<s:param> 標籤,例如我們想爲上面的URL添加兩個參數:ID和姓名,我們可以在<s:url> 標籤上添加兩個內嵌的<s:param> 標籤:

<s:url value="/addStudent" var="add" >
    <s:param name="id" value="1" />
    <s:param name="name" value="Tom" />
</s:url>
<a href="${add }">添加學生</a>

這樣的話,渲染得到的HTML內容即爲:

<a href="/spring_mvc1/addStudent?id=1&name=Tom">添加學生</a>

如果我們創建帶有路徑參數的URL,我們也可以使用<s:param> 標籤:

<s:url value="/addStudent/{id}" var="add" >
    <s:param name="id" value="1" />
    <s:param name="name" value="Tom" />
</s:url>
<a href="${add }">添加學生</a>

當value屬性中的佔位符匹配<s:param> 中所指定的參數時,這個參數會插入到佔位符的位置中,如果<s:param> 參數無法匹配value中的任何佔位符,那麼這個參數將會作爲查詢參數,所以,上面的例子最終渲染得到的HTML爲:

<a href="/spring_mvc1/addStudent/1?name=Tom">添加學生</a>

如果我們希望渲染得到的URL內容展現在Web頁面上,而不是作爲超鏈接,我們需要將<s:url> 進行HTML轉義,即將htmlEscape屬性設置爲true:

<s:url value="/addStudent" var="add"  htmlEscape="true">
    <s:param name="id" value="1" />
    <s:param name="name" value="Tom" />
</s:url>

這時頁面顯示內容爲:/spring_mvc1/addStudent?id=1&name=Tom,而渲染得到的HTML內容爲:/spring_mvc1/addStudent?id=1&amp ;name=Tom,可以看到,它將&符號進行了轉義。

如果希望在JavaScript代碼中使用URL的話,應該將javaScriptEscape屬性設置爲true:

<s:url value="/addStudent" var="add"  javaScriptEscape="true">
    <s:param name="id" value="1" />
    <s:param name="name" value="Tom" />
</s:url>

這樣在下面的這段JavaScript:

<script type="text/javascript">
    var url = "${add }";
</script>

就可以轉換爲如下的內容返回給響應:

<script type="text/javascript">
    var url = "\/spring_mvc1\/addStudent?id=1&name=Tom";
</script>
2.2.3.3、轉義內容

<s:escapeBody> 標籤是一個通用的轉義標籤,它會渲染標籤體中內嵌的內容,並且在必要時進行轉義,例如,我們想在頁面上顯示一段HTML代碼段,如果直接寫“<“、”>“,瀏覽器將不能正確顯示,需要將其轉換爲”&lt ;“、”&gt ;“,這項工作很繁瑣,並且代碼難以閱讀,所以我們可以使用<s:escapeBody> 來完成這項任務:

<s:escapeBody htmlEscape="true">
    <h1>Hello</h1>
</s:escapeBody>

這樣,在渲染得到的HTML中將會得到如下內容:

&lt;h1&gt;Hello&lt;/h1&gt;

通過javaScriptEscape屬性,<s:escapeBody> 標籤還支持JavaScript轉義:

<s:escapeBody javaScriptEscape="true">
    <h1>Hello</h1>
</s:escapeBody>

<s:escapeBody> 標籤和<s:url> 標籤不同的地方在於,它只會渲染內容,並不能將內容設置爲變量。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章