一,JSP標準標籤庫 JSTL
* 用於編寫和開發jsp頁面的一組標準標籤。目的在於簡化JSP頁面的設計。
* 組成:
core核心標籤庫:http://java.sun.com/jsp/jstl/core 首碼c
I18N國際化與格式化標籤庫:http://java.sun.com/jsp/jstl/fmt 首碼fmt
SQL標籤庫:http://java.sun.com/jsp/jstl/sql 首碼sql
XML標籤庫:http://java.sun.com/jsp/jstl/xml 首碼x
Funcions :http://java.sun.com/jsp/jstl/Funcions 首碼fn
* 二種版本
EL版本和請求時運算式版本
二,配置JSTL
* 下載JSEL安裝包,解壓後有2個jar包jstl.jar和standart.jar;
jstl.jar中包含JSTL規範中定義的介面和相關的類;
standart.jar中包含Jakarta小組對JSTL的實現和JSTL中5個標籤庫的TLD檔案;
放入WEB-INF/lib目錄下。
* 在JSP頁面中匯入要使用的標籤庫的URL。和使用自訂標籤一樣。
* 可以在web.xml中使用<tablib-url>元素來修改標籤庫的URL引用。
三,核心標籤庫Core :用於操作JSP頁面建立的範圍變數;
1,組成:
通用標籤:設定,刪除和顯示在JSP頁面內建立的變數值。
條件標籤:
迭代標籤
* 動態值指屬性的值可以是jsp運算式,EL運算式,或通過<jsp:attribute>標籤設定的值。
EL 提供了一種簡化語言,用於在 JSP 應用程式中訪問和操作資料並使該資料可被 JSTL 定製標記用作動態屬性值。
2,通用標籤:
<c:set>:設定範圍變數或bean屬性的值;
* 設定範圍變數使用var,value,scope;
設定bean屬性使用value,target(bean對象), property(屬性名稱)
* var和scope屬性不能接受動態值,其他標籤也一樣。
* tld中<body-content>設定為JSP;
<c:remove>:移除範圍變數;
* 不指定scope按PageContext.removeAttribute(name)來移除。
指定scope按PageContext.removeAttribute(name,scope)來移除。
<c:out>:將運算式結果輸出到當前的JspWriter對象中;
* 類似JSP運算式或EL ${運算式};
* tld中<body-content>設定為JSP;
3,條件標籤:
<c:if>:if的實現
* var 為儲存條件結果的變數為boolean類型.
* tld中<body-content>設定為JSP;
* 如果指定了scope就必須指定var屬性。scope預設page。
* 執行結果被輸出到當前JspWriter對象中.
<c:choose>:if/else的實現,
* 判斷<c:when>標籤的測試條件的值是否為true。如果沒有滿足的條件<c:ohterwise>被執行。
* tld中<body-content>設定為JSP;
* <c:choose>為<c:when>和<c:ohterwise>的父標籤,<c:choose>只能含有這2個標籤.
<c:when>:一個可選條件;
* tld中<body-content>設定為JSP;
* 必須在<c:choose>標籤下使用<c:ohterwise>之前出現.
<c:ohterwise>:最後的選擇;
<c:catch>:允許在 JSP 頁面內進行初級的異常處理,使得能夠在頁面自身內部進行定製錯誤處理。
4,迭代標籤
<c:forEach>:主要用於訪存和顯示資料集,通常是以列表或表中的一系列行的形式顯示
* 對整數範圍上的迭代(類似 Java 語言的 for 語句)
<c:forEach var="name" varStatus="name" begin="expression" end="expression" step="expression">
body content
</c:forEach>
begin 和 end 屬性要麼是靜態整數值,要麼是可以得出整數值的運算式。它們分別指定迭代索引的初始值以及迭代索引的終止值。
出現 step 時,它也必須是整數值。它指定每次迭代後索引的增量。省略了 step 屬性,那麼步長預設為 1。
如果指定了 var 屬性,那麼將會建立一個帶有指定名稱的並限定了範圍的變數,並將每次迭代的當前索引值賦給該變數。只可以在 <c:forEach> 標記體內對其進行訪問。
* 對集合上的迭代
<c:forEach var="name" items="expression" varStatus="name" begin="expression" end="expression" step="expression">
body content
</c:forEach>
items 屬性是唯一必需的屬性。 items 屬性的值應該是一個集合,對該集合的成員進行迭代,通常使用 EL 運算式指定值。
如果items是通過 <c:forEach> 標記的 item 屬性指定的,那麼對於每次迭代該已命名變數都將被綁定到集合後續元素上。
<c:forEach> 標記的 items 屬性所支援的集合
items 的值 所產生的 item 值
java.util.Collection 調用 iterator() 所獲得的元素
java.util.Map java.util.Map.Entry 的執行個體
java.util.Iterator 迭代器元素
java.util.Enumeration 枚舉元素
Object 執行個體數組 數組元素
基本類型值數組 經過封裝的數組元素
用逗號定界的 String 子字串
javax.servlet.jsp.jstl.sql.Result SQL 查詢所獲得的行
* 不論是對整數還是對集合進行迭代, <c:forEach> 剩餘的屬性 varStatus 所起的作用相同。
和 var 屬性一樣, varStatus 用於建立限定了範圍的變數。
不過,由 varStatus 屬性命名的變數並不儲存當前索引值或當前元素,
而是賦予 javax.servlet.jsp.jstl.core.LoopTagStatus 類的執行個體。
該類定義了一組特性,它們描述了迭代的目前狀態,
LoopTagStatus 對象的特性
特性 Getter 描述
current getCurrent() 當前這次迭代的(集合中的)項
index getIndex() 當前這次迭代從 0 開始的迭代索引
count getCount() 當前這次迭代從 1 開始的迭代計數
first isFirst() 用來表明當前這輪迭代是否為第一次迭代的標誌
last isLast() 用來表明當前這輪迭代是否為最後一次迭代的標誌
begin getBegin() begin 屬性值
end getEnd() end 屬性值
step getStep() step 屬性值
* 對String的迭代:按特定的分隔字元為間隔迭代。
<c:forTokens>:迭代字串中有分隔字元分隔的成員。
* 通過java.util.StringTokenizer類執行個體完成字串的分隔。delims和items屬性為其構造參數。
* 通過 delims 屬性提供用於產生標記的一組定界符.其它屬性都相同。
* 對於標記之間為空白或為空白格則不輸出。
5,URL相關的標籤:
<c:import>:匯入一個基於URL的資源。
* 不僅可以匯入同一web應用下的資源,還可以匯入不同web應用或網站中的資源。
* tld中<body-content>設定為JSP;
<c:url> :使用正確的URL重寫規則構造一個URL
* 在前面附加當前 servlet 內容相關的名稱
* 和<c:param>一起使用將請求參數名稱和值的 URL 編碼
* 為會話管理重寫 URL 。
* value 屬性用來指定基本 URL,然後在必要時標記對其進行轉換。
如果這個基本 URL 以一個斜杠開始,那麼會在它前面加上 servlet 的上下文名稱。可以使用 context 屬性提供顯式的上下文名稱。
如果省略該屬性,那麼就使用當前 servlet 內容相關的名稱。
這一點特別有用,因為 servlet 上下文名稱是在部署期間而不是開發期間決定的。
(如果這個基本 URL 不是以斜杠開始的,那麼就認為它是一個相對 URL,這時就不必添加上下文名稱。)
* 如果為 var 屬性提供了一個值(還可以同時為 scope 屬性提供一個相應的值,這是可選的),
那麼將產生的 URL 賦值給這個限定了範圍的指定變數。
否則,將使用當前的 JspWriter 輸出產生的 URL。這種直接輸出其結果的能力允許 <c:url> 標記作為值出現,
*
<c:redirect>:重定位到另外的資源。
* 用於向使用者的瀏覽器發送 HTTP 重新導向響應
* 通過請求指派器進行轉寄是在伺服器端實現的,而重新導向卻是由瀏覽器來執行的。
從開發人員的角度來講,轉寄比重新導向更有效率。
<c:import>:將輸出結果匯入JSP頁面
* core 庫的 <c:import> 操作是更通用、功能更強大的 <jsp:include> 版本
* 和 <jsp:include> 一樣, <c:import> 也是一種請求時操作,它的基本任務就是將其它一些 Web 資源的內容插入 JSP 頁面中。
* 通過 url 屬性指定將要匯入內容的 URL,這個屬性是 <c:import> 的唯一一個必選屬性。
如果 url 屬性的值以斜杠開始,那麼它就被解釋成本地 JSP 容器內的絕對 URL。
* 如果沒有為 context 屬性指定值,那麼就認為這樣的絕對 URL 引用當前 servlet 上下文內的資源。
* 也可以將包含協議和主機名稱的完整 URI 指定為 url 屬性的值。可以使用 java.net.URL 類所支援的任何協議。
* var 屬性會導致從指定 URL 擷取的內容(作為 String 值)被儲存在一個限定了範圍的變數中,而不是包含在當前 JSP 頁面中。
四,國際化和格式化標籤庫
1,HTTP 協議通過 Accept-Language 要求標頭將本地化資訊從瀏覽器傳遞至伺服器。許多 網頁瀏覽器允許使用者定製他們的語言喜好設定,
那些沒有為一種或多種慣用語言環境提供顯式設定的瀏覽器會詢問作業系統以確定在 Accept-Language 頭中發送哪個值(或哪些值)。
servlet 規範通過 javax.servlet.ServletRequest 類的 getLocale() 和 getLocales() 方法自動地利用 HTTP 協議的這一功能。
JSTL fmt 庫中的定製標記又會利用這些方法來自動地確定使用者的語言環境,從而相應地調整它們的輸出。
但不存在將使用者的時區從瀏覽器傳輸到伺服器的標準 HTTP 要求頭。
2,組成:
本地化上下文標記:設定本地化上下文,其它標記將在其中進行操作。
日期標記:標記分別支援對日期和數字進行格式化和解析。
訊息標記:側重於對簡訊進行本地化。
3,本地化上下文標記
<fmt:setLocale> : 覆蓋使用者語言環境,JSP 容器處理完該 JSP 程式碼片段之後,將忽略使用者瀏覽器設定中所指定的語言喜好設定。
* value 屬性。該屬性的值應當是命名該語言環境的一個字串或者是 java.util.Locale 類的一個執行個體。
語言環境名稱是這樣組成的:小寫兩字母 ISO 語言代碼,可選地,後面可以跟底線或連字號以及大寫的兩字母 ISO 國家或地區代碼。
* 可選屬性 scope 用來指定語言環境的範圍。
page 範圍指出這項設定只適用於當前頁.
request 範圍將它應用於請求期間訪問的所有 JSP 頁面。
session ,那麼指定的語言環境被用於使用者會話期間訪問的所有 JSP 頁面。
application 指出該語言環境適用於該 Web 應用程式所有 JSP 頁面的全部請求和該應用程式所有使用者的全部請求。
* variant 屬性(也是可選的)允許您進一步針對特定的 網頁瀏覽器平台或供應商定製語言環境。例如, MAC 和 WIN
<fmt:setTimeZone> :設定其它 fmt 定製標記所使用的預設時區值。
* value 屬性是必需的,但是在本例中它應當是時區名或 java.util.TimeZone 類的執行個體。
* 通過調用 java.util.TimeZone 類的 getAvailableIDs() 靜態方法來檢索有效時區名列表。
* 使用可選的 scope 屬性來指出時區設定的範圍。
* 可以使用 var 屬性,將 TimeZone 執行個體的值儲存在限定了範圍的變數中。
<fmt:timeZone>:使用該標記來指定將由其它 JSTL 標記使用的時區。但是, <fmt:timeZone> 操作的範圍僅限於其標記體內容。
4,日期標記
<fmt:formatDate> :用來格式化和顯示日期和時間(資料 輸出)
* value 屬性才是必需的。其值應當是 java.util.Date 類的執行個體,指定要進行格式化和顯示的日期和/或時間資料。
* 可選的 timeZone 屬性指出將要顯示哪個時區的日期和/或時間。
* type 屬性指出要顯示指定的 Date 執行個體的哪些欄位,應當是 time 、 date 或 both 。該屬性的預設值是 date 。
* dateStyle 和 timeStyle 屬性分別指出應當如何格式化日期和時間資訊。有效樣式有 default 、 short 、 medium 、 long 和 full 。
* pattern 屬性來指定定製樣式,而不必依賴於內建樣式。
* 如果指定了 var 屬性,那就把包含格式化日期的 String 值指派給指定的變數。
<fmt:parseDate>: 用來解析日期和時間值(資料 輸入)
* type 、 dateStyle 、 timeStyle 、 pattern 和 timeZone 屬性對 <fmt:parseDate> 和對 <fmt:formatDate> 起一樣的作用,
不同之處僅在於對於前者,它們控制日期值的解析而非顯示。
* parseLocale 屬性用來指定一種語言環境,將根據這種語言環境來解析該標記的值,它應當是語言環境的名稱或 Locale 類的執行個體。
* 對於生產代碼,文本輸入的驗證和轉換最好由後端代碼(比如 servlet)來處理,而不是通過 JSP 定製標記來處理。
5,數字標記
<fmt:formatNumber> :用來以特定於語言環境的方式顯示數字資料,包括貨幣和百分數。操作由語言環境確定,
* value 屬性才是必需的。它用來指定將被格式化的數值。
* type 屬性的值應當是 number 、 currency 或 percentage ,並指明要對哪種類型的數值進行格式化。
當 type 屬性的值為 currency 時, currencyCode 屬性可以用來顯式地指定所顯示的數值的貨幣單位。
* pattern 屬性優先於 type 屬性,允許對遵循 java.text.DecimalFormat 類模式約定的數值進行更精確的格式化。
* maxIntegerDigits 、 minIntegerDigits 、 maxFractionDigits 和 minFractionDigits 屬性用來控制小數點前後所顯示的有效數位個數。
這些屬性要求是整數值。
* groupingUsed 屬性帶有布爾值並控制是否要對小數點前面的數字分組。
<fmt:parseDate> :
* integerOnly 屬性指出是否應當只解析所給值的整數部分。如果該屬性的值為 true ,那麼就忽略要被解析的字串中跟在小數點後面的任何數字。該屬性的預設值為 false 。
* 解析資料並不是一項非常適合於展示層的任務。如果解析和驗證資料作為應用程式商務邏輯的一部分實現,那麼軟體維護將會得到簡化。
6,訊息標記
<fmt:message> :實現文本的本地化。
* 該操作利用 java.text.MessageFormat 類所提供的功能,所以可以將參數化的值替換進這樣的簡訊,以便動態地定製本地化內容。
* 只有 key 屬性才是必需的。 key 屬性的值用來確定要顯示在資源束中定義的哪些訊息。
* var 屬性,那麼將由該標記所產生的簡訊賦給指定的變數,而不是寫到 JSP 頁面。
* <fmt:param> 標記的 value 屬性來提供簡訊的參數化值。
<fmt:setBundle> : 操作設定了一個預設資源束,供 <fmt:message> 標記在特定範圍內使用,
* basename 屬性是必需的,它標識了設為預設值的資源束。
* basename 屬性的值不應當包含任何本地化尾碼或副檔名。
* 可選的 scope 屬性指明預設資源束設定所應用的 JSP 範圍。如果沒有顯式地指定該屬性,就假定為 page 範圍。
* 如果指定了可選的 var 屬性,那麼將把由 basename 屬性所標識的資源束賦給該屬性值所命名的變數。
在這種情況下, scope 屬性指定變數的範圍;沒有將預設資源束賦給相應的 JSP 範圍。
<fmt:bundle> : 指定了為嵌套在其標記體內容中的全部和任意 <fmt:message> 操作所用的資源束。
* 只有 basename 屬性才是必需的。您可以使用可選的 prefix 屬性來為任何嵌套的 <fmt:message> 操作的 key 值指定預設首碼。
7,使用JDK工具native2asci.exe,它在JDK/BIN 目錄下,進行編碼的轉換:
* 用於儲存特定於語言環境訊息的資源束採用類或特性檔案的形式,這些類或特性檔案符合標準命名規範,在這種命名規範中基名和語言環境名組合在一起。
native2ascii [-reverse] [-encoding encoding] [inputfile [outputfile]]
正轉:To:Unicode
native2ascii -encoding gb2312 source.properties target.properties
反轉:Reverse Unicode To 指定碼
native2ascii -reverse -encoding Big5 source22.properties target2.properties
例如:native2ascii -encoding gb2312 E:/apache/zh_CN.txt E:/zh_CN.txt
五,XML庫
1,在企業級應用越來越依賴XML的今天,XML格式的資料被作為資訊交換的優先選擇。
XML processing標籤庫為程式設計者提供了基本的對XML格式檔案的操作。在該標籤庫中的標籤一共有10個,被分為了三類,分別是:
XML核心標籤:<x:parse>、<x:out>、<x:set>。
XML流量控制標籤:<x:if>、<x:choose>、<x:when>、<x:otherwise>、<x:forEach>。
XML轉換標籤:<x:transform>、<x:param>。
2,<x:parse> : 標籤是該組標籤庫的核心,用於解析XML檔案.
<x:parse>標籤屬性和說明
屬性 描述
doc 源XML的內容,該屬性的內容應該為String類型或者java.io.Reader的執行個體,可以用xml屬性來替代,但是不被推薦
var 將解析後的XML儲存在該屬性所指定的變數中,之後XML processing標籤庫中的其他標籤若要取XML中的內容就可以從該變數中得到(可選)
scope 變數的作用範圍(可選)
varDom 指定儲存的變數為org.w3c.dom.Document介面類型(可選)
scopeDom org.w3c.dom.Document的介面類型變數作用範圍(可選)
systemId 定義一個URI,該URI將被使用到XML檔案中以接入其他資源檔(可選)
filter 該屬性必須為org.xml.sax.XMLFilter類的一個執行個體,可以使用EL運算式傳入,將對XML檔案做過濾得到自身需要的部分(可選)
其中,var、scope和varDom、scopeDom不應該同時出現,而應該被視為兩個版本來使用,二者的變數都可以被XML processing標籤庫的其他標籤來使用。
<x:parse>標籤單獨使用的情況很少,一般會結合XML processing標籤庫中的其他標籤來一起工作。下面看一個樣本。
首先給出一個簡單的XML檔案,將對該XML檔案做解析,該XML檔案名稱為SampleXml.xml。
<?xml version="1.0" encoding="UTF-8"?>
<xml-body>
<name>RW</name>
<passWord>123456</passWord>
<age>28</age>
<books>
<book>book1</book>
<book>book2</book>
<book>book3</book>
</books>
</xml-body>
標籤庫的工作:
<c:import var="xmlFile" url="http://localhost:8080/booksamplejstl/SampleXml.xml"/>
<x:parse var="xmlFileValue" doc="${xmlFile}"/>
該樣本讀取XML檔案得到了<c:import>標籤的協助,<c:import>標籤將源XML檔案的內容儲存在“xmlFile”變數中,<x:parse>標籤根據“xmlFile”變數的值解析“SampleXml.xml”。
3,<x:out>:用於顯示XML內容的
<x:out>標籤從<x:parse>標籤解析後儲存的變數中取得需要的XML檔案內容,並顯示在頁面上。該標籤是通過XPath技術(定位XML元素的一種技術)來實現的。要使用<x:out>標籤必須將xalan-j的jar包儲存在“WEB-INF/lib”下。它的屬性和描述如表9.13所示:
<x:out>標籤屬性和說明
屬性 描述
select XPath運算式
escape 當特殊字元如:“<,>,&,’,””出現在取得的結果字串中時,將以逸出字元來替換
<x:out>標籤需要與<x:parse>標籤協同工作,下面看一個樣本。
<c:import var="xmlFile" url="http://localhost:8080/booksamplejstl/SampleXml.xml"/>
<x:parse var="xmlFileValue" doc="${xmlFile}"/>
name:<x:out select="$xmlFileValue/xml-body/name"/><br>
passWord:<x:out select="$xmlFileValue/xml-body/passWord"/><br>
age:<x:out select="$xmlFileValue/xml-body/age"/><br>
讀取XML檔案並解析後的變數xmlFileValue將加上“$”作為XPath運算式的開頭,select中的運算式將從xml-body根項目下的各個子項目中取得實體內容。
根據“SampleXml.xml”檔案的內容,將顯示。
name:RW
passWord:123456
age:28
4,<x:set>:用於儲存XML內容。
<x:set>標籤允許將某個源XML中元素的實體內容或屬性,儲存到一個變數中去,它的實現也依靠XPath技術。
<x:set>標籤屬性和說明
屬性 描述
select XPath運算式
var 儲存結果的變數名
scope 變數的作用範圍(可選)
<x:set>標籤的var儲存的變數由XPath的結果決定該變數的類型,下面看一個樣本。
<c:import var="xmlFile" url="http://localhost:8080/booksamplejstl/SampleXml.xml"/>
<x:parse var="xmlFileValue" doc="${xmlFile}"/>
<x:set select="$xmlFileValue/xml-body/name" var="thisName"/>
這裡將儲存XML的name元素內容到變數“thisName”中。
5,<x:if>:用於判斷
<x:if>標籤允許由XPath的boolean()函數得到的判斷結果,來判斷是否顯示其標籤所包含的內容。
<x:if>標籤的屬性與<x:set>標籤相同,但是var的結果只能是boolean類型。
6,<x:choose>、<x:when>、<x:otherwise>:用於複雜判斷。
這組標籤將一起使用,來提供“if elseif”語句的功能。
<x:choose>標籤沒有屬性,可以被認為是父標籤,<x:when>、<x:otherwise>將作為其子標籤來使用。
<x:when>標籤等價於“if”語句,它包含一個select屬性,該屬性為XPath判斷運算式。
<x:otherwise>標籤沒有屬性,它等價於“else”語句。
7,<x:forEach>:用於對XML元素迴圈。
<x:forEach>為對XML檔案中同一名稱元素的迴圈控制標籤。
<x:set>標籤屬性和說明
屬性 描述
select XPath運算式,結果是一個集合,將對該集合進行迴圈(可選)
begin 開始條件(可選)
end 結束條件(可選)
step 迴圈的步長,預設為1(可選)
var 做迴圈的物件變數名,表示XPath運算式結果集合中的一個對象(可選)
varStatus 顯示迴圈狀態的變數(可選)
下面看一個樣本。
<x:forEach select="$xmlFileValue/xml-body/books/book" var="book">
${book}
</x:forEach>
該樣本將使用迴圈讀取XML中多個同存於books元素下的book子項目。
8,<x:transform>:格式化XML顯示資料。
<x:transform>標籤允許使用XSLT(轉換XML格式的語言)為頁面的顯示資料做格式化的處理。
<x:transform>標籤屬性和說明
屬性 描述
doc 源XML的內容,該屬性的內容應該為String、java.io.Reader、javax.xml.transform.Source、org.w3c.dom.Document的執行個體,或者從<x:parse>、<x:set>兩個標籤得到。可以用xml屬性來替代,但是不被推薦(可選)
xslt 源XSLT的內容,該屬性的內容應該為String、java.io.Reader、javax.xml.transform.Source的執行個體(可選)
docSystemId 定義一個URI,該URI將被使用到XML檔案中以接入其他資源檔。可以用xml SystemId屬性來替代,但是不被推薦(可選)
xsltSystemId 定義一個URI,該URI將被使用到XSLT檔案中以接入其他資源檔(可選)
var 將格式化後的XML檔案儲存在該屬性所指定的變數中,儲存的變數為org.w3c.dom.Document介面類型(可選)
scope 變數的作用範圍(可選)
result 儲存轉化結果的變數,儲存的變數為javax.xml.transform.Result類型的執行個體(可選)
下面看一個樣本:
<c:import var="xmlFile" url="http://localhost:8080/booksamplejstl/SampleXml.xml" />
<c:set var="xsltdoc">
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="xml-body">
<html>
<head></head>
<body marginheight="0" marginwidth="0" topmargin="0" leftmargin="0">
<h2>
UserName:
<xsl:value-of select="name" />
</h2>
<h2>
PassWord:
<xsl:value-of select="passWord" />
</h2>
<h2>
age:
<xsl:value-of select="age" />
</h2>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
</c:set>
<x:transform xslt="${xsltdoc}" doc="${xmlFile}" />
這個樣本將XML檔案儲存的資料資訊利用<c:import>儲存在“xmlFile”中,然後使用<c:set>標籤儲存一個XSLT的源到“xsltdoc”,最後通過<x:transform>格式化XML檔案的資料顯示在頁面上。
9,用於參數傳遞的<x:param>標籤
<x:param>標籤用於在格式化XML時傳遞所需要的參數。它的屬性和描述與<c:param>標籤相同。