1. 程式人生 > >Spring——Spring MVC(二)

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" />
    &l