Spring 相關工具類

Spring框架下自帶了豐富的工具類,在我們開發時可以簡化很多工作:

1.Resource訪問文件資源:

   具體有:ResourceUtils.getFile(url);

           FileSystemResource(); ClassPathResource();

           ServletContextResource(application,url);

 

2.文件操作 FileCopyUtils

   具體有:FileCopyUtils.copy(Resource.getFile,new File(Resource.getFile(),getParent()+'目標文件名'));

 

3.屬性文件操作 PropertiesLoaderUtils    

   具體有: PropertiesLoaderUtils.loadAllProperties("屬性文件名");  --基於類路徑

 

4.EncodedResource(Resource對象,"UTF-8") 編碼資源(特殊的);

 

5.WebApplicationContextUtils

 

6.WebUtils

   具體有:getCookie, getSessionAttribute, getRealPath;

 

7.StringEscapeutils 編碼解碼

 

 

 

 

 

 

 

 

=====================

 

 

 

 

Web 相關工具類

您幾乎總是使用 Spring 框架開發 Web 的應用,Spring 爲 Web 應用提供了很多有用的工具類,這些工具類可以給您的程序開發帶來很多便利。在這節裏,我們將逐一介紹這些工具類的使用方法。

操作 Servlet API 的工具類

當您在控制器、JSP 頁面中想直接訪問 Spring 容器時,您必須事先獲取 WebApplicationContext 對象。Spring 容器在啓動時將 WebApplicationContext 保存在 ServletContext的屬性列表中,通過 WebApplicationContextUtils 工具類可以方便地獲取 WebApplicationContext 對象。

WebApplicationContextUtils

當 Web 應用集成 Spring 容器後,代表 Spring 容器的 WebApplicationContext 對象將以 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE 爲鍵存放在 ServletContext 屬性列表中。您當然可以直接通過以下語句獲取 WebApplicationContext:

WebApplicationContext wac = (WebApplicationContext)servletContext.
getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

 

但通過位於 org.springframework.web.context.support 包中的 WebApplicationContextUtils 工具類獲取 WebApplicationContext 更方便:

WebApplicationContext wac =WebApplicationContextUtils.
getWebApplicationContext(servletContext);

 

當 ServletContext 屬性列表中不存在 WebApplicationContext 時,getWebApplicationContext() 方法不會拋出異常,它簡單地返回 null。如果後續代碼直接訪問返回的結果將引發一個 NullPointerException 異常,而 WebApplicationContextUtils 另一個 getRequiredWebApplicationContext(ServletContext sc) 方法要求 ServletContext 屬性列表中一定要包含一個有效的 WebApplicationContext 對象,否則馬上拋出一個 IllegalStateException 異常。我們推薦使用後者,因爲它能提前發現錯誤的時間,強制開發者搭建好必備的基礎設施。

WebUtils

位於 org.springframework.web.util 包中的 WebUtils 是一個非常好用的工具類,它對很多 Servlet API 提供了易用的代理方法,降低了訪問 Servlet API 的複雜度,可以將其看成是常用 Servlet API 方法的門面類。

下面這些方法爲訪問 HttpServletRequest 和 HttpSession 中的對象和屬性帶來了方便:

方法說明
Cookie getCookie(HttpServletRequest request, String name) 獲取 HttpServletRequest 中特定名字的 Cookie 對象。如果您需要創建 Cookie, Spring 也提供了一個方便的 CookieGenerator 工具類;
Object getSessionAttribute(HttpServletRequest request, String name) 獲取 HttpSession 特定屬性名的對象,否則您必須通過request.getHttpSession.getAttribute(name) 完成相同的操作;
Object getRequiredSessionAttribute(HttpServletRequest request, String name) 和上一個方法類似,只不過強制要求 HttpSession 中擁有指定的屬性,否則拋出異常;
String getSessionId(HttpServletRequest request) 獲取 Session ID 的值;
void exposeRequestAttributes(ServletRequest request, Map attributes) 將 Map 元素添加到 ServletRequest 的屬性列表中,當請求被導向(forward)到下一個處理程序時,這些請求屬性就可以被訪問到了;

此外,WebUtils還提供了一些和ServletContext相關的方便方法:

方法說明
String getRealPath(ServletContext servletContext, String path) 獲取相對路徑對應文件系統的真實文件路徑;
File getTempDir(ServletContext servletContext) 獲取 ServletContex 對應的臨時文件地址,它以 File 對象的形式返回。

下面的片斷演示了使用 WebUtils 從 HttpSession 中獲取屬性對象的操作:

protected Object formBackingObject(HttpServletRequest request) throws Exception {
    UserSession userSession = (UserSession) WebUtils.getSessionAttribute(request, 
        "userSession");
    if (userSession != null) {
        return new AccountForm(this.petStore.getAccount(
        userSession.getAccount().getUsername()));
    } else {
        return new AccountForm();
    }
}

 

Spring 所提供的過濾器和監聽器

Spring 爲 Web 應用提供了幾個過濾器和監聽器,在適合的時間使用它們,可以解決一些常見的 Web 應用問題。

延遲加載過濾器

Hibernate 允許對關聯對象、屬性進行延遲加載,但是必須保證延遲加載的操作限於同一個 Hibernate Session 範圍之內進行。如果 Service 層返回一個啓用了延遲加載功能的領域對象給 Web 層,當 Web 層訪問到那些需要延遲加載的數據時,由於加載領域對象的 Hibernate Session 已經關閉,這些導致延遲加載數據的訪問異常。

Spring 爲此專門提供了一個 OpenSessionInViewFilter 過濾器,它的主要功能是使每個請求過程綁定一個 Hibernate Session,即使最初的事務已經完成了,也可以在 Web 層進行延遲加載的操作。

OpenSessionInViewFilter 過濾器將 Hibernate Session 綁定到請求線程中,它將自動被 Spring 的事務管理器探測到。所以 OpenSessionInViewFilter 適用於 Service 層使用HibernateTransactionManager 或 JtaTransactionManager 進行事務管理的環境,也可以用於非事務只讀的數據操作中。

要啓用這個過濾器,必須在 web.xml 中對此進行配置:

…
<filter>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>
    org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>hibernateFilter</filter-name>
    <url-pattern>*.html</url-pattern>
</filter-mapping>
…


上面的配置,我們假設使用 .html 的後綴作爲 Web 框架的 URL 匹配模式,如果您使用 Struts 等 Web 框架,可以將其改爲對應的“*.do”模型。

中文亂碼過濾器

在您通過表單向服務器提交數據時,一個經典的問題就是中文亂碼問題。雖然我們所有的 JSP 文件和頁面編碼格式都採用 UTF-8,但這個問題還是會出現。解決的辦法很簡單,我們只需要在 web.xml 中配置一個 Spring 的編碼轉換過濾器就可以了:

<web-app>
<!---listener的配置-->
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>
        org.springframework.web.filter.CharacterEncodingFilter ① Spring 編輯過濾器
    </filter-class>
    <init-param> ② 編碼方式
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param> ③ 強制進行編碼轉換
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
    </filter>
    <filter-mapping> ② 過濾器的匹配 URL
        <filter-name>encodingFilter</filter-name>
        <url-pattern>*.html</url-pattern>
    </filter-mapping>

<!---servlet的配置-->
</web-app>

 

這樣所有以 .html 爲後綴的 URL 請求的數據都會被轉碼爲 UTF-8 編碼格式,表單中文亂碼的問題就可以解決了。

請求跟蹤日誌過濾器

除了以上兩個常用的過濾器外,還有兩個在程序調試時可能會用到的請求日誌跟蹤過濾器,它們會將請求的一些重要信息記錄到日誌中,方便程序的調試。這兩個日誌過濾器只有在日誌級別爲 DEBUG 時纔會起作用:

方法說明
org.springframework.web.filter.ServletContextRequestLoggingFilter 該過濾器將請求的 URI 記錄到 Common 日誌中(如通過 Log4J 指定的日誌文件);
org.springframework.web.filter.ServletContextRequestLoggingFilter 該過濾器將請求的 URI 記錄到 ServletContext 日誌中。

以下是日誌過濾器記錄的請求跟蹤日誌的片斷:

(JspServlet.java:224) -     JspEngine --> /htmlTest.jsp
(JspServlet.java:225) - 	     ServletPath: /htmlTest.jsp
(JspServlet.java:226) - 	        PathInfo: null
(JspServlet.java:227) - 	        RealPath: D:/masterSpring/chapter23/webapp/htmlTest.jsp
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|

|-------- XML error:  The previous line is longer than the max of 90 characters ---------|

(JspServlet.java:228) - 	      RequestURI: /baobaotao/htmlTest.jsp
…

 

通過這個請求跟蹤日誌,程度調試者可以詳細地查看到有哪些請求被調用,請求的參數是什麼,請求是否正確返回等信息。雖然這兩個請求跟蹤日誌過濾器一 般在程序調試時使用,但是即使程序部署不將其從 web.xml 中移除也不會有大礙,因爲只要將日誌級別設置爲 DEBUG 以上級別,它們就不會輸出請求跟蹤日誌信息了。

轉存 Web 應用根目錄監聽器和 Log4J 監聽器

Spring 在 org.springframework.web.util 包中提供了幾個特殊用途的 Servlet 監聽器,正確地使用它們可以完成一些特定需求的功能。比如某些第三方工具支持通過 ${key} 的方式引用系統參數(即可以通過 System.getProperty() 獲取的屬性),WebAppRootListener 可以將 Web 應用根目錄添加到系統參數中,對應的屬性名可以通過名爲“webAppRootKey”的 Servlet 上下文參數指定,默認爲“webapp.root”。下面是該監聽器的具體的配置:


清單 6. WebAppRootListener 監聽器配置

…
<context-param>
    <param-name>webAppRootKey</param-name>
    <param-value>baobaotao.root</param-value> ① Web 應用根目錄以該屬性名添加到系統參數中
</context-param>
…
② 負責將 Web 應用根目錄以 webAppRootKey 上下文參數指定的屬性名添加到系統參數中
<listener>
    <listener-class> 
    org.springframework.web.util.WebAppRootListener
    </listener-class>
</listener>
…

 

這樣,您就可以在程序中通過 System.getProperty("baobaotao.root") 獲取 Web 應用的根目錄了。不過更常見的使用場景是在第三方工具的配置文件中通過${baobaotao.root} 引用 Web 應用的根目錄。比如以下的 log4j.properties 配置文件就通過 ${baobaotao.root} 設置了日誌文件的地址:

log4j.rootLogger=INFO,R
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=${baobaotao.root}/WEB-INF/logs/log4j.log ① 指定日誌文件的地址
log4j.appender.R.MaxFileSize=100KB
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout.ConversionPattern=%d %5p [%t] (%F:%L) - %m%n

 

另一個專門用於 Log4J 的監聽器是 Log4jConfigListener。一般情況下,您必須將 Log4J 日誌配置文件以 log4j.properties 爲文件名並保存在類路徑下。Log4jConfigListener 允許您通過 log4jConfigLocation Servlet 上下文參數顯式指定 Log4J 配置文件的地址,如下所示:

① 指定 Log4J 配置文件的地址
<context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
…
② 使用該監聽器初始化 Log4J 日誌引擎
<listener>
    <listener-class>
    org.springframework.web.util.Log4jConfigListener
    </listener-class>
</listener>
…

 

提示 

一些Web應用服務器(如 Tomcat)不會爲不同的Web應用使用獨立的系統參數,也就是說,應用服務器上所有的 Web 應用都共享同一個系統參數對象。這時,您必須通過webAppRootKey 上下文參數爲不同Web應用指定不同的屬性名:如第一個 Web 應用使用 webapp1.root 而第二個 Web 應用使用 webapp2.root 等,這樣纔不會發生後者覆蓋前者的問題。此外,WebAppRootListener 和 Log4jConfigListener 都只能應用在 Web 應用部署後 WAR 文件會解包的 Web 應用服務器上。一些 Web 應用服務器不會將Web 應用的 WAR 文件解包,整個 Web 應用以一個 WAR 包的方式存在(如 Weblogic),此時因爲無法指定對應文件系統的 Web 應用根目錄,使用這兩個監聽器將會發生問題。

Log4jConfigListener 監聽器包括了 WebAppRootListener 的功能,也就是說,Log4jConfigListener 會自動完成將 Web 應用根目錄以 webAppRootKey 上下文參數指定的屬性名添加到系統參數中,所以當您使用 Log4jConfigListener 後,就沒有必須再使用 WebAppRootListener了。

Introspector 緩存清除監聽器

Spring 還提供了一個名爲 org.springframework.web.util.IntrospectorCleanupListener 的監聽器。它主要負責處理由 JavaBean Introspector 功能而引起的緩存泄露。IntrospectorCleanupListener 監聽器在 Web 應用關閉的時會負責清除 JavaBean Introspector 的緩存,在 web.xml 中註冊這個監聽器可以保證在 Web 應用關閉的時候釋放與其相關的 ClassLoader 的緩存和類引用。如果您使用了 JavaBean Introspector 分析應用中的類,Introspector 緩存會保留這些類的引用,結果在應用關閉的時候,這些類以及Web 應用相關的 ClassLoader 不能被垃圾回收。不幸的是,清除 Introspector 的唯一方式是刷新整個緩存,這是因爲沒法準確判斷哪些是屬於本 Web 應用的引用對象,哪些是屬於其它 Web 應用的引用對象。所以刪除被緩存的 Introspection 會導致將整個 JVM 所有應用的 Introspection 都刪掉。需要注意的是,Spring 託管的 Bean 不需要使用這個監聽器,因爲 Spring 的 Introspection 所使用的緩存在分析完一個類之後會馬上從 javaBean Introspector 緩存中清除掉,並將緩存保存在應用程序特定的 ClassLoader 中,所以它們一般不會導致內存資源泄露。但是一些類庫和框架往往會產生這個問題。例如 Struts 和 Quartz 的 Introspector 的內存泄漏會導致整個的 Web 應用的 ClassLoader 不能進行垃圾回收。在 Web 應用關閉之後,您還會看到此應用的所有靜態類引用,這個錯誤當然不是由這個類自身引起的。解決這個問題的方法很簡單,您僅需在 web.xml 中配置 IntrospectorCleanupListener 監聽器就可以了:

<listener>
    <listener-class>
    org.springframework.web.util.IntrospectorCleanupListener
    </listener-class>
</listener>

小結

本文介紹了一些常用的 Spring 工具類,其中大部分 Spring 工具類不但可以在基於 Spring 的應用中使用,還可以在其它的應用中使用。使用 JDK 的文件操作類在訪問類路徑相關、Web 上下文相關的文件資源時,往往顯得拖泥帶水、拐彎抹角,Spring 的 Resource 實現類使這些工作變得輕鬆了許多。

在 Web 應用中,有時你希望直接訪問 Spring 容器,獲取容器中的 Bean,這時使用 WebApplicationContextUtils 工具類從 ServletContext 中獲取 WebApplicationContext 是非常方便的。WebUtils 爲訪問 Servlet API 提供了一套便捷的代理方法,您可以通過 WebUtils 更好的訪問 HttpSession 或 ServletContext 的信息。

Spring 提供了幾個 Servlet 過濾器和監聽器,其中 ServletContextRequestLoggingFilter 和 ServletContextRequestLoggingFilter 可以記錄請求訪問的跟蹤日誌,你可以在程序調試時使用它們獲取請求調用的詳細信息。WebAppRootListener 可以將 Web 應用的根目錄以特定屬性名添加到系統參數中,以便第三方工具類通過 ${key} 的方式進行訪問。Log4jConfigListener 允許你指定 Log4J 日誌配置文件的地址,且可以在配置文件中通過 ${key} 的方式引用 Web 應用根目錄,如果你需要在 Web 應用相關的目錄創建日誌文件,使用 Log4jConfigListener 可以很容易地達到這一目標。

Web 應用的內存泄漏是最讓開發者頭疼的問題,雖然不正確的程序編寫可能是這一問題的根源,也有可能是一些第三方框架的 JavaBean Introspector 緩存得不到清除而導致的,Spring 專門爲解決這一問題配備了 IntrospectorCleanupListener 監聽器,它只要簡單在 web.xml 中聲明該監聽器就可以了。

發佈了177 篇原創文章 · 獲贊 14 · 訪問量 59萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章