<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    心的方向

    新的征途......
    posts - 75,comments - 19,trackbacks - 0

    轉自:http://dev.csdn.net/article/68/68297.shtm
    hibernate 三種查詢方式     選擇自 wangyihust 的 Blog 
     

    (一)HQL

    HQLHibernate Qusery Language,如果你已經熟悉它,就會發現它跟SQL非常相像。不過你不要被表面的假象迷惑,HQL是面向對象的(OO,用生命的眼光看待每一個對象,他們是如此鮮活)。如果你對JAVASQL語句有一定了解的話,那么HQL對你簡直易如反掌,你完全可以利用在公車上的時間掌握它。

    以下從幾個方面進行慢慢深入:

    1
    。大小些敏感
    大家知道SQL-92 Query是對大小寫不敏感的,但是在HQL(前面提到它是OO的)中對對象類的名稱和屬性確實大小寫敏感的(符合java編程語法)。

    HQL 子句本身大小寫無關,但是其中出現的類名和屬性名必須注意大小寫區分
    如:sElect cat.name from Cat as catselect cat.name from Cat as cat是一樣的
    但是:
    sElect
    cat.name from CAT as catselect cat.name from Cat as cat確實不一樣的。

    2
    from語句
    最簡單的:
    from eg.Cat
    它只是簡單的返回所有eg.Cat的實例,通常我們此時會為eg.Cat其個別名,因為在query的其余部分可能會用到(參看上邊關于大小寫敏感時的例子情形),如:
    from eg.Cat as cat 這里as可以省略。


    上邊只是單表查詢,多表的情況如下寫法:
    from eg.Cat, eg.Dog
    from eg.Cat as cat, eg.Dog as dog

    3
    join相關
    (inner) join
    left (outer) join
    right (outer) join
    full join
    HQL
    同樣對SQL中的這些特性支持
    下面插播一個小話題,關于上邊的那些特性,我一直都沒怎么用,今天既然說到這里,就想把上邊的幾個特性的用法說一下,也算對自己的一個補充:


    假設有兩個表:部門、員工,下面列舉一些數據:
    員工(Employee)
     ID     Name    DepNo
     001   Jplateau   01
     002    Jony        01
     003   Camel      02

    部門(Department)
     ID  Name
     01  
    研發部
     02   
    營銷部

    Hibernate中我們操縱的都是對象,所以我們操縱的是部門類和員工


    1).(inner) join
    select employee.ID as id1,employee.Name as name1,

    department.ID as id2,department.Name as name2  from Employee as employee

     join  Department as department on employee.DepNo=department.ID (注意到條件語句我用on 沒有用where)
    那么執行結果是什么呢?
    id1 name1 id2 name2
    ++++++++++++++++++++++++++++++++++++++
    001 Jplateau 01
    研發部
    002 Jony 01
    研發部

    2).left (outer) join
    select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name
    as name2 from Employee as employee left join Department as department on employee.DepNo=
    department.ID
    那么執行結果又該是什么呢?
    id1 name1 id2 name2
    ++++++++++++++++++++++++++++++++++++++
    001 Jplateau 01
    研發部
    002 Jony 01
    研發部
    003 Camel null null
    {
    就是說此時我要已第一個表的記錄多少為準,第二個表中沒有相應紀錄的時候填充null}
    3). right (outer) join
    select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name
    as name2 from Employee as employee right join Department as department on employee.DepNo=
    department.ID
    那么執行結果又該是什么呢?
    id1 name1 id2 name2
    ++++++++++++++++++++++++++++++++++++++
    001 Jplateau 01
    研發部
    002 Jony 01
    研發部
    null null 02
    營銷部
    {
    就是說此時我要已第二個表的記錄多少為準,第一個表中沒有相應紀錄的時候填充null}

    4
    select語句
    就是要確定你要從查詢中返回哪些對象或者哪些對象的屬性。寫幾個例子吧:
    select employee form Employee as employee
    select employee form Employee as employee where employee.Name like 'J%'
    select employee.Name form Employee as employee where employee.Name like 'J%'
    select employee.ID as id1,employee.Name as name1,department.ID as id2,department.Name
    as name2 from Employee as employee right join Department as department on employee.DepNo=
    department.ID

    select
    elements(employee.Name) from Employee as employee
    (不明白elements到底是做什么用的?望給于說明)
    等等


    5。數學函數
    JDO
    目前好像還不支持此類特性。
    avg(...), sum(...), min(...), max(...)

    count(*)

    count(...), count(distinct ...), count(all...)

    其用法和SQL基本相同

    select distinct employee.name from Employee as employee
    select count(distinct employee.name),count(employee) from Employee as employee

    6
    polymorphism (暫時不知道如何解釋?)
    from com.test.Animal as animal
    不光得到所有Animal得實例,而且可以得到所有Animal的子類(如果我們定義了一個子類Cat
    一個比較極端的例子
    from java.lang.Object as o
    可以得到所有持久類的實例

    7
    where語句
    定義查詢語句的條件,舉幾個例子吧:
    from Employee as employee where employee.Name='Jplateau'
    from Employee as employee where employee.Name like 'J%'
    from Employee as employee where employee.Name like '%u'
    where語句中“=”不光可以比較對象的屬性,也可以比較對象,如:
    select animal from com.test.Animal as animal where animal.name=dog

    8
    。表達式

    SQL語句中大部分的表達式在HQL中都可以使用:
    mathematical operators +, -, *, /

    binary comparison operators =, >=, <=, <>, !=, like

    logical operations and, or, not

    string concatenation ||

    SQL scalar functions like upper() and lower()

    Parentheses ( ) indicate grouping

    in, between, is null

    JDBC IN parameters ?

    named parameters :name, :start_date, :x1
    (這種應該是另一種"?"的變通解決方法)

    SQL literals 'foo', 69, '1970-01-01 10:00:01.0'

    Java public static final constants eg.Color.TABBY

    其他不必解釋了,在這里我只想對查詢中的參數問題說明一下:
    大家知道在SQL中進行傳遞參數進行查詢的時候,我們通常用PreparedStatement,在語句中寫一大堆的“?”,
    hql中也可以用這種方法,如:
    List mates = sess.find(
    "select employee.name from Employee as employee " +
    "where employee.Name=? ",
    name,
    Hibernate.STRING
    );
    (
    說明:上面利用Session里的find方法,在hibernateapi Session中重載了很多find方法,它可以滿足你多種形式的查詢)
    上邊是一個參數的情形,這種情況下緊接著引入參數和定義參數的類型,當為多個參數,調用另一個find方法,它的后兩個
    參數都是數組的形式。

    還有另外一種方法來解決上邊的問題,JDO也有這樣的方法,不過和hibernate的表現形式上有差別,但他們兩個骨子里卻是
    一樣的,如:
    Query q = sess.createQuery("select employee.name from Employee as employee where employee.Name=:name");
    q.setString("name", "Jplateau");
    //
    當有多個參數的時候在此逐一定義
    Iterator employees = q.iterate();

    9
    order 語句
    sql語句沒什么差別,如:
    select employee.name from Employee as employee where employee.Name like 'J%' order by employee.ID desc (
    或者asc)

    10
    group by 語句
    同樣和sql語句沒什么差別,如:

    select employee.name,employee.DepNo from Employee as employee group by employee.DepNo

    select foo.id, avg( elements(foo.names) ), max( indices(foo.names) ) from eg.Foo foo group by foo.id
    {Note: You may use the elements and indices constructs inside a select clause, even on databases with no subselects.}
    誰幫我解釋一下上邊兩句,謝過!

    11
    。子查詢
    hibernate
    同樣支持子查詢,寫幾個例子:

    from eg.Cat as fatcat where fatcat.weight > ( select avg(cat.weight) from eg.DomesticCat cat )

    (二)條件查詢Criteria  Query

    。數學函數
    JDO
    目前好像還不支持此類特性。
    avg(...), sum(...), min(...), max(...)

    count(*)

    count(...), count(distinct ...), count(all...)

    其用法和SQL基本相同

    select distinct employee.name from Employee as employee
    select count(distinct employee.name),count(employee) from Employee as employee

    6
    polymorphism (暫時不知道如何解釋?)
    from com.test.Animal as animal
    不光得到所有Animal得實例,而且可以得到所有Animal的子類(如果我們定義了一個子類Cat
    一個比較極端的例子
    from java.lang.Object as o
    可以得到所有持久類的實例

    7
    where語句
    定義查詢語句的條件,舉幾個例子吧:
    from Employee as employee where employee.Name='Jplateau'
    from Employee as employee where employee.Name like 'J%'
    from Employee as employee where employee.Name like '%u'
    where語句中“=”不光可以比較對象的屬性,也可以比較對象,如:
    select animal from com.test.Animal as animal where animal.name=dog

    8
    。表達式

    SQL語句中大部分的表達式在HQL中都可以使用:
    mathematical operators +, -, *, /

    binary comparison operators =, >=, <=, <>, !=, like

    logical operations and, or, not

    string concatenation ||

    SQL scalar functions like upper() and lower()

    Parentheses ( ) indicate grouping

    in, between, is null

    JDBC IN parameters ?

    named parameters :name, :start_date, :x1
    (這種應該是另一種"?"的變通解決方法)

    SQL literals 'foo', 69, '1970-01-01 10:00:01.0'

    Java public static final constants eg.Color.TABBY

    其他不必解釋了,在這里我只想對查詢中的參數問題說明一下:
    大家知道在SQL中進行傳遞參數進行查詢的時候,我們通常用PreparedStatement,在語句中寫一大堆的“?”,
    hql中也可以用這種方法,如:
    List mates = sess.find(
    "select employee.name from Employee as employee " +
    "where employee.Name=? ",
    name,
    Hibernate.STRING
    );
    (
    說明:上面利用Session里的find方法,在hibernateapi Session中重載了很多find方法,它可以滿足你多種形式的查詢)
    上邊是一個參數的情形,這種情況下緊接著引入參數和定義參數的類型,當為多個參數,調用另一個find方法,它的后兩個
    參數都是數組的形式。

    還有另外一種方法來解決上邊的問題,JDO也有這樣的方法,不過和hibernate的表現形式上有差別,但他們兩個骨子里卻是
    一樣的,如:
    Query q = sess.createQuery("select employee.name from Employee as employee where employee.Name=:name");
    q.setString("name", "Jplateau");
    //
    當有多個參數的時候在此逐一定義
    Iterator employees = q.iterate();

    9
    order 語句
    sql語句沒什么差別,如:
    select employee.name from Employee as employee where employee.Name like 'J%' order by employee.ID desc (
    或者asc)

    10
    group by 語句
    同樣和sql語句沒什么差別,如:

    select employee.name,employee.DepNo from Employee as employee group by employee.DepNo

    select foo.id, avg( elements(foo.names) ), max( indices(foo.names) ) from eg.Foo foo group by foo.id
    {Note: You may use the elements and indices constructs inside a select clause, even on databases with no subselects.}
    誰幫我解釋一下上邊兩句,謝過!

    11
    。子查詢
    hibernate
    同樣支持子查詢,寫幾個例子:

    from eg.Cat as fatcat where fatcat.weight > ( select avg(cat.weight) from eg.DomesticCat cat )

    (二)條件查詢Criteria  Query

     Criteria criteria = osession.createCriteria(Owner.class);
       criteria.add(Expression.eq("age", new Integer(100)));
       criteria.setFirstResult(2);                   //從返回結果的第二條記錄開始的5條記錄
       criteria.setMaxResults(5);
       List lc=criteria.list();
       System.out.println("條件查詢");
       System.out.println(lc.size());

    (三)原生SQL語句查詢

    posted @ 2008-04-10 17:41 阿偉 閱讀(283) | 評論 (0)編輯 收藏

    Spring與Struts如何整合

    轉自:http://lihaiyan.javaeye.com/blog/127812
    為了在Struts中加載Spring context,需要在struts-config.xml文件中加入如下部分:
    <struts-config>
      <plug-in
             className="org.springframework.web.struts.ContextLoaderPlugIn">
         <set-property property="contextConfigLocation"
             value="/WEB-INF/applicationContext.xml" />
      </plug-in>
    </struts-config>
    第一種方法:
        通過Struts的plug-in在Struts和Spring之間提供了良好的結合點。通過plug-in我們實現了Spring context的加載,不過僅僅加載Spring context并沒有什么實際的意義,還應該經過配置將Struts的Action交給Spring容器進行管理。
    <action-mappings>
      <action path="/login"
                 type="org.springframework.web.struts.DelegatingActionProxy"
                 name="loginForm">
          <forward name="success" path="/main.jsp" />
          <forward name="failure" path="/login.jsp" />
    </action>
        在form bean這個節點上與傳統的Struts配置沒有什么區別,而在Action上面則發生了變化。在傳統的action節點上type屬性寫入action類的完整類名,而和Spring結合后在這點上是使用了Spring提供的DelegatingActionProxy
    作為action的type屬性,DelegatingActionProxy同樣是org.apache.struts.action.Action的一個子類,它將把調用請求轉交給真正的Action實現。通過這樣的方式,Spring獲得了Action實例的管理權,它將對Action進行調度,并為Struts提供所需的Action實例。這樣,就可以將Action看作是Spring的一個bean,它就可以享受Spring的所有服務,如依賴注入、實例管理、事務管理等。
        在applicationContext.xml中相應的配置如下的節點:
    <beans>
    .......
        <bean name="/login" class="net.xiaxin.action.LoginAction"
                               singleton="false">
            <property name="userDAO">
               <ref bean="userDAOProxy" />
            </property>
        </bean>
    </beans>
        最后這個bean的配置是關鍵,這個名為“/login”的bean與Struts中的
    <action path="/login" ……>
    ……
    </action>
    節點相對應,這樣,Spring Bean Name與Struts Action Path相關聯,當Struts加載對應的Action時,DelegatingActionProxy就根據傳入的path屬性,在Spring Context尋找對應bean,并將其實例返回給Struts。與此同時,還可以看到,"/login" bean 中包含了一個userDAO 引用,Spring 在運行期將根據配置為其提供userDAO 實例,以及圍繞userDAO 的事務管理服務。這樣一來,對于Struts 開發而言,我們既可以延續Struts 的開發流程,也可以享受Spring 提供的事務管
    理服務。而bean 的另外一個屬性singleton="false",指明了Action 的實例獲取方式為每次重新創建。這也解決了Struts中令人詬病的線程安全問題。
    第二種方法:

    為了在 struts-config.xml 文件中配置 DelegatingRequestProcessor,你需要重載 <controller> 元素的 “processorClass” 屬性。 下面的幾行應該放在 <action-mapping> 元素的后面。

    <controller>
    <set-property property="processorClass"
    value="http://www.zhmy.com/org.springframework.web.struts.DelegatingRequestProcessor"/>
    </controller>

    增加這些設置之后,不管你查詢任何類型的 Action,Sping都自動在它的context配置文件中尋找。 實際上,你甚至不需要指定類型。下面兩個代碼片斷都可以工作:

    <action path="/user" type="com.whatever.struts.UserAction"/>
    <action path="/user"/>

    如果你使用 Struts 的 modules 特性,你的 bean 命名必須含有 module 的前綴。 舉個例子,如果一個 Action 的定義為 <action path="/user"/>,而且它的 module 前綴為“admin”, 那么它應該對應名為 <bean name="/admin/user"/> 的 bean

       
    如果你在 Struts 應用中使用了 Tiles,你需要配置 <controller> 為 DelegatingTilesRequestProcessor

    如果第二種方法不行,再用第一種方法。   
     至此,SS組合已經將Struts MVC以及Spring中的Bean管理、事務管理融為一體。如
    果算上userDAO 中的Hibernate 部分,我們就獲得了一個全面、成熟、高效、自頂而下的
    Web 開發框架。

    來源:http://deathmask1980.spaces.live.com/blog/cns!8633c46371110374!118.entry


    posted @ 2008-04-10 16:46 阿偉 閱讀(779) | 評論 (0)編輯 收藏

    Struts+Spring+Hibernate實現上傳下載(四)

    轉自:http://lihaiyan.javaeye.com/blog/127797

    Web層實現

      1、Web層的構件和交互流程

      Web層包括主要3個功能:

      ·上傳文件。

      ·列出所有已經上傳的文件列表,以供點擊下載。

      ·下載文件。

      Web層實現構件包括與2個JSP頁面,1個ActionForm及一個Action:

      ·file-upload.jsp:上傳文件的頁面。

      ·file-list.jsp:已經上傳文件的列表頁面。

      ·FileActionForm:file-upload.jsp頁面表單對應的ActionForm。

      ·FileAction:繼承org.apache.struts.actions.DispatchAction的Action,這樣這個Action就可以通過一個URL參數區分中響應不同的請求。

      Web層的這些構件的交互流程如圖 6所示:

    420){this.resized=true;this.style.width=420;}" border=0 resized="true">
    圖 6 Web層Struts流程圖


      其中,在執行文件上傳的請求時,FileAction在執行文件上傳后,forward到loadAllFile出口中,loadAllFile加載數據庫中所有已經上傳的記錄,然后forward到名為fileListPage的出口中,調用file-list.jsp頁面顯示已經上傳的記錄。

      2、FileAction功能

      Struts 1.0的Action有一個弱項:一個Action只能處理一種請求,Struts 1.1中引入了一個DispatchAction,允許通過URL參數指定調用Action中的某個方法,如http://yourwebsite/fileAction.do?method=upload即調用FileAction中的upload方法。通過這種方式,我們就可以將一些相關的請求集中到一個Action當中編寫,而沒有必要為某個請求操作編寫一個Action類。但是參數名是要在struts-config.xml中配置的:

    1. <struts-config>
    2. <form-beans>
    3. <form-bean name="fileActionForm" type="sshfile.web.FileActionForm" />
    4. </form-beans>
    5. <action-mappings>
    6. <action name="fileActionForm" parameter="method" path="/fileAction"
    7. type="sshfile.web.FileAction">
    8. <forward name="fileListPage" path="/file-list.jsp" />
    9. <forward name="loadAllFile" path="/fileAction.do?method=listAllFile" />
    10. </action>
    11. </action-mappings>
    12. </struts-config>


      第6行的parameter="method"指定了承載方法名的參數,第9行中,我們還配置了一個調用FileAction不同方法的Action出口。

      FileAction共有3個請求響應的方法,它們分別是:

      ·upload(…):處理上傳文件的請求。

      ·listAllFile(…):處理加載數據庫表中所有記錄的請求。

      ·download(…):處理下載文件的請求。

      下面我們分別對這3個請求處理方法進行講解。

      2.1 上傳文件

      上傳文件的請求處理方法非常簡單,簡之言之,就是從Spring容器中獲取業務層處理類FileService,調用其save(FileActionForm form)方法上傳文件,如下所示:

    1. public class FileAction
    2. extends DispatchAction
    3. {
    4. //將上傳文件保存到數據庫中
    5. public ActionForward upload(ActionMapping mapping, ActionForm form,
    6. HttpServletRequest request,
    7. HttpServletResponse response)
    8. {
    9. FileActionForm fileForm = (FileActionForm) form;
    10. FileService fileService = getFileService();
    11. fileService.save(fileForm);
    12. return mapping.findForward("loadAllFile");
    13. }
    14. //從Spring容器中獲取FileService對象
    15. private FileService getFileService()
    16. {
    17. ApplicationContext appContext = WebApplicationContextUtils.
    18. getWebApplicationContext(this.getServlet().getServletContext());
    19. return (FileService) appContext.getBean("fileService");
    20. }
    21. …
    22. }


      由于FileAction其它兩個請求處理方法也需要從Spring容器中獲取FileService實例,所以我們特別提供了一個getFileService()方法(第15~21行)。重構的一條原則就是:"發現代碼中有重復的表達式,將其提取為一個變量;發現類中有重復的代碼段,將其提取為一個方法;發現不同類中有相同的方法,將其提取為一個類"。在真實的系統中,往往擁有多個Action和多個Service類,這時一個比較好的設置思路是,提供一個獲取所有Service實現對象的工具類,這樣就可以將Spring 的Service配置信息屏蔽在一個類中,否則Service的配置名字散落在程序各處,維護性是很差的。

      2.2 列出所有已經上傳的文件

      listAllFile方法調用Servie層方法加載T_FILE表中所有記錄,并將其保存在Request域中,然后forward到列表頁面中:

    1. public class FileAction
    2. extends DispatchAction
    3. {
    4. …
    5. public ActionForward listAllFile(ActionMapping mapping, ActionForm form,
    6. HttpServletRequest request,
    7. HttpServletResponse response)
    8. throws ModuleException
    9. {
    10. FileService fileService = getFileService();
    11. List fileList = fileService.getAllFile();
    12. request.setAttribute("fileList",fileList);
    13. return mapping.findForward("fileListPage");
    14. }
    15. }


      file-list.jsp頁面使用Struts標簽展示出保存在Request域中的記錄:

    1. <%@page contentType="text/html; charset=GBK"%>
    2. <%@taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%>
    3. <%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
    4. <html>
    5. <head>
    6. <title>file-download</title>
    7. </head>
    8. <body bgcolor="#ffffff">
    9. <ol>
    10. <logic:iterate id="item" name="fileList" scope="request">
    11. <li>
    12. <a href='fileAction.do?method=download&fileId=
    13. <bean:write name="item"property="fileId"/>'>
    14. <bean:write name="item" property="fileName"/>
    15. </a>
    16. </li>
    17. </logic:iterate>
    18. </ol>
    19. </body>
    20. </html>


      展現頁面的每條記錄掛接著一個鏈接地址,形如:fileAction.do?method=download&fileId=xxx,method參數指定了這個請求由FileAction的download方法來響應,fileId指定了記錄的主鍵。

      由于在FileActionForm中,我們定義了fileId的屬性,所以在download響應方法中,我們將可以從FileActionForm中取得fileId的值。這里涉及到一個處理多個請求Action所對應的ActionForm的設計問題,由于原來的Action只能對應一個請求,那么原來的ActionForm非常簡單,它僅需要將這個請求的參數項作為其屬性就可以了,但現在一個Action對應多個請求,每個請求所對應的參數項是不一樣的,此時的ActionForm的屬性就必須是多請求參數項的并集了。所以,除了文件上傳請求所對應的fileContent和remark屬性外還包括文件下載的fileId屬性:

    420){this.resized=true;this.style.width=420;}" border=0>
    圖 7 FileActionForm


      當然這樣會造成屬性的冗余,比如在文件上傳的請求中,只會用到fileContent和remark屬性,而在文件下載的請求時,只會使用到fileId屬性。但這種冗余是會帶來好處的--它使得一個Action可以處理多個請求。

      2.3 下載文件

      在列表頁面中點擊一個文件下載,其請求由FileAction的download方法來響應,download方法調用業務層的FileService方法,獲取文件數據并寫出到response的響應流中。通過合理設置HTTP響應頭參數,將響應流在客戶端表現為一個下載文件對話框,其代碼如下所示:

      代碼 10 業務接口實現類之download

    1. public class FileAction
    2. extends DispatchAction
    3. {
    4. …
    5. public ActionForward download(ActionMapping mapping, ActionForm form,
    6. HttpServletRequest request,
    7. HttpServletResponse response)
    8. throws ModuleException
    9. {
    10. FileActionForm fileForm = (FileActionForm) form;
    11. FileService fileService = getFileService();
    12. String fileName = fileService.getFileName(fileForm.getFileId());
    13. try
    14. {
    15. response.setContentType("application/x-msdownload");
    16. response.setHeader("Content-Disposition",
    17. "attachment;" + " filename="+
    18. new String(fileName.getBytes(), "ISO-8859-1"));
    19. fileService.write(response.getOutputStream(), fileForm.getFileId());
    20. }
    21. catch (Exception e)
    22. {
    23. throw new ModuleException(e.getMessage());
    24. }
    25. return null;
    26. }
    27. }


      第15~18行,設置HTTP響應頭,將響應類型設置為application/x-msdownload MIME類型,則響應流在IE中將彈出一個文件下載的對話框,如圖 4所示。IE所支持的MIME類型多達26種,您可以通過這個網址查看其他的MIME類型:

    http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp

      如果下載文件的文件名含有中文字符,如果不對其進行硬編碼,如第18行所示,客戶文件下載對話框中出現的文件名將會發生亂碼。
    第19行代碼獲得response的輸出流,作為FileServie write(OutputStream os,String fileId)的入參,這樣文件的內容將寫到response的輸出流中。

      3、web.xml文件的配置

      Spring容器在何時啟動呢?我可以在Web容器初始化來執行啟動Spring容器的操作,Spring提供了兩種方式啟動的方法:

      ·通過org.springframework.web.context .ContextLoaderListener容器監聽器,在Web容器初始化時觸發初始化Spring容器,在web.xml中通過<listener></listener>對其進行配置。

      ·通過Servlet org.springframework.web.context.ContextLoaderServlet,將其配置為自動啟動的Servlet,在Web容器初始化時,通過這個Servlet啟動Spring容器。

      在初始化Spring容器之前,必須先初始化log4J的引擎,Spring也提供了容器監聽器和自動啟動Servlet兩種方式對log4J引擎進行初始化:

      ·org.springframework.web.util .Log4jConfigListener

      ·org.springframework.web.util.Log4jConfigServlet

      下面我們來說明如何配置web.xml啟動Spring容器:

      代碼 11 web.xml中對應Spring的配置內容

    1. <web-app>
    2. <context-param>
    3. <param-name>contextConfigLocation</param-name>
    4. <param-value>/WEB-INF/applicationContext.xml</param-value>
    5. </context-param>
    6. <context-param>
    7. <param-name>log4jConfigLocation</param-name>
    8. <param-value>/WEB-INF/log4j.properties</param-value>
    9. </context-param>
    10. <servlet>
    11. <servlet-name>log4jInitServlet</servlet-name>
    12. <servlet-class>org.springframework.web.util.Log4jConfigServlet</servlet-class>
    13. <load-on-startup>1</load-on-startup>
    14. </servlet>
    15. <servlet>
    16. <servlet-name>springInitServlet</servlet-name>
    17. <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
    18. <load-on-startup>2</load-on-startup>
    19. </servlet>
    20. …
    21. </web-app>


      啟動Spring容器時,需要得到兩個信息:Spring配置文件的地址和Log4J屬性文件,這兩上信息分別通過contextConfigLocationWeb和log4jConfigLocation容器參數指定,如果有多個Spring配置文件,則用逗號隔開,如:

    /WEB-INF/applicationContext_1.xml, /WEB-INF/applicationContext_1.xm2

      由于在啟動ContextLoaderServlet之前,必須事先初始化Log4J的引擎,所以Log4jConfigServlet必須在ContextLoaderServlet之前啟動,這通過<load-on-startup>來指定它們啟動的先后順序。

      亂碼是開發Web應用程序一個比較老套又常見問題,由于不同Web應用服務器的默認編碼是不一樣的,為了方便Web應用在不同的Web應用服務器上移植,最好的做法是Web程序自身來處理編碼轉換的工作。經典的作法是在web.xml中配置一個編碼轉換過濾器,Spring就提供了一個編碼過濾器類CharacterEncodingFilter,下面,我們為應用配置上這個過濾器:

    1. <web-app>
    2. …
    3. <filter>
    4. <filter-name>encodingFilter</filter-name>
    5. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    6. <init-param>
    7. <param-name>encoding</param-name>
    8. <param-value>GBK</param-value>
    9. </init-param>
    10. </filter>
    11. <filter-mapping>
    12. <filter-name>encodingFilter</filter-name>
    13. <url-pattern>/*</url-pattern>
    14. </filter-mapping>
    15. …
    16. </web-app>


      Spring的過濾器類是org.springframework.web.filter.CharacterEncodingFilter,通過encoding參數指定編碼轉換類型為GBK,<filter-mapping>的配置使該過濾器截獲所有的請示。

      Struts的框架也需要在web.xml中配置,想必讀者朋友對Struts的配置都很熟悉,故在此不再提及,請參見本文所提供的源碼。

      總結

      本文通過一個文件上傳下載的Web應用,講解了如何構建基于SSH的Web應用,通過Struts和FormFile,Spring的LobHandler以及Spring為HibernateBlob處理所提供的用戶類BlobByteArrayType ,實現上傳和下載文件的功能僅需要廖廖數行的代碼即告完成。讀者只需對程序作稍許的調整,即可處理Clob字段:

      ·領域對象對應Clob字段的屬性聲明為String類型;

      ·映射文件對應Clob字段的屬性聲明為org.springframework.orm.hibernate3.support.ClobStringType類型。

      本文通過SSH對文件上傳下載簡捷完美的實現得以管中窺豹了解SSH強強聯合構建Web應用的強大優勢。在行文中,還穿插了一些分層的設計經驗,配置技巧和Spring所提供的方便類,相信這些知識對您的開發都有所裨益。

    作者:陳雄華出處:天極開發


    posted @ 2008-04-10 15:03 阿偉 閱讀(364) | 評論 (0)編輯 收藏

    Struts+Spring+Hibernate實現上傳下載(三)

    轉自:http://lihaiyan.javaeye.com/blog/127796

    業務層

      1、業務層接口

      "面向接口而非面向類編程"是Spring不遺余力所推薦的編程原則,這條原則也已經為大部開發者所接受;此外,JDK的動態代理只對接口有效,否則必須使用CGLIB生成目標類的子類。我們依從于Spring的倡導為業務類定義一個接口:

      代碼 7 業務層操作接口

    1. public interface FileService
    2. {
    3. void save(FileActionForm fileForm);//將提交的上傳文件保存到數據表中
    4. List getAllFile();//得到T_FILE所示記錄
    5. void write(OutputStream os,String fileId);//將某個文件的文件數據寫出到輸出流中
    6. String getFileName(String fileId);//獲取文件名
    7. }

      其中save(FileActionForm fileForm)方法,將封裝在fileForm中的上傳文件保存到數據庫中,這里我們使用FileActionForm作為方法入參,FileActionForm是Web層的表單數據對象,它封裝了提交表單的數據。將FileActionForm直接作為業務層的接口入參,相當于將Web層傳播到業務層中去,即將業務層綁定在特定的Web層實現技術中,按照分層模型學院派的觀點,這是一種反模塊化的設計,但在"一般"的業務系統并無需提供多種UI界面,系統Web層將來切換到另一種實現技術的可能性也微乎其微,所以筆者覺得沒有必要為了這個業務層完全獨立于調用層的過高目標而去搞一個額外的隔離層,浪費了原材料不說,還將系統搞得過于復雜,相比于其它原則,"簡單"始終是最大的一條原則。

      getAllFile()負責獲取T_FILE表所有記錄,以便在網頁上顯示出來。

      而getFileName(String fileId)和write(OutputStream os,String fileId)則用于下載某個特定的文件。具體的調用是將Web層將response.getOutputStream()傳給write(OutputStream os,String fileId)接口,業務層直接將文件數據輸出到這個響應流中。具體實現請參見錯誤!未找到引用源。節下載文件部分。

      2、業務層接口實現類

      FileService的實現類為FileServiceImpl,其中save(FileActionForm fileForm)的實現如下所示:

      代碼 8 業務接口實現類之save()

    1. …
    2. public class FileServiceImpl
    3. implements FileService
    4. {
    5. private TfileDAO tfileDAO;
    6. public void save(FileActionForm fileForm)
    7. {
    8. Tfile tfile = new Tfile();
    9. try
    10. {
    11. tfile.setFileContent(fileForm.getFileContent().getFileData());
    12. }
    13. catch (FileNotFoundException ex)
    14. {
    15. throw new RuntimeException(ex);
    16. }
    17. catch (IOException ex)
    18. {
    19. throw new RuntimeException(ex);
    20. }
    21. tfile.setFileName(fileForm.getFileContent().getFileName());
    22. tfile.setRemark(fileForm.getRemark());
    23. tfileDAO.save(tfile);
    24. }
    25. …
    26. }

      在save(FileActionForm fileForm)方法里,完成兩個步驟:

      其一,象在水桶間倒水一樣,將FileActionForm對象中的數據倒入到Tfile對象中;

      其二,調用TfileDAO保存數據。

      需要特別注意的是代碼的第11行,FileActionForm的fileContent屬性為org.apache.struts.upload.FormFile類型,FormFile提供了一個方便的方法getFileData(),即可獲取文件的二進制數據。通過解讀FormFile接口實現類DiskFile的原碼,我們可能知道FormFile本身并不緩存文件的數據,只有實際調用getFileData()時,才從磁盤文件輸入流中獲取數據。由于FormFile使用流讀取方式獲取數據,本身沒有緩存文件的所有數據,所以對于上傳超大體積的文件,也是沒有問題的;但是,由于數據持久層的Tfile使用byte[]來緩存文件的數據,所以并不適合處理超大體積的文件(如100M),對于超大體積的文件,依然需要使用java.sql.Blob類型以常規流操作的方式來處理。

      此外,通過FileForm的getFileName()方法就可以獲得上傳文件的文件名,如第21行代碼所示。

      write(OutputStream os,String fileId)方法的實現,如代碼 9所示:

      代碼 9 業務接口實現類之write()

    1. …
    2. public class FileServiceImpl
    3. implements FileService
    4. {
    5.
    6. public void write(OutputStream os, String fileId)
    7. {
    8. Tfile tfile = tfileDAO.findByFildId(fileId);
    9. try
    10. {
    11. os.write(tfile.getFileContent());
    12. os.flush();
    13. }
    14. catch (IOException ex)
    15. {
    16. throw new RuntimeException(ex);
    17. }
    18. }
    19. …
    20. }

      write(OutputStream os,String fileId)也簡單地分為兩個操作步驟,首先,根據fileId加載表記錄,然后將fileContent寫入到輸出流中。

      3、Spring事務配置

      下面,我們來看如何在Spring配置文件中為FileService配置聲明性的事務

    1. <beans>
    2. …
    3. <bean id="transactionManager"
    4. class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    5. <property name="sessionFactory" ref="sessionFactory"/>
    6. </bean>
    7. <!-- 事務處理的AOP配置 //-->
    8. <bean id="txProxyTemplate" abstract="true"
    9. class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    10. <property name="transactionManager" ref="transactionManager"/>
    11. <property name="transactionAttributes">
    12. <props>
    13. <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
    14. <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
    15. <prop key="save">PROPAGATION_REQUIRED</prop>
    16. <prop key="write">PROPAGATION_REQUIRED,readOnly</prop>
    17. </props>
    18. </property>
    19. </bean>
    20. <bean id="fileService" parent="txProxyTemplate">
    21. <property name="target">
    22. <bean class="sshfile.service.FileServiceImpl">
    23. <property name="tfileDAO" ref="tfileDAO"/>
    24. </bean>
    25. </property>
    26. </bean>
    27. </beans>

      Spring的事務配置包括兩個部分:

      其一,定義事務管理器transactionManager,使用HibernateTransactionManager實現事務管理;

      其二,對各個業務接口進行定義,其實txProxyTemplate和fileService是父子節點的關系,本來可以將txProxyTemplate定義的內容合并到fileService中一起定義,由于我們的系統僅有一個業務接口需要定義,所以將其定義的一部分抽象到父節點txProxyTemplate中意義確實不大,但是對于真實的系統,往往擁有為數眾多的業務接口需要定義,將這些業務接口定義內容的共同部分抽取到一個父節點中,然后在子節點中通過parent進行關聯,就可以大大簡化業務接口的配置了。

      父節點txProxyTemplate注入了事務管理器,此外還定義了業務接口事務管理的方法(允許通過通配符的方式進行匹配聲明,如前兩個接口方法),有些接口方法僅對數據進行讀操作,而另一些接口方法需要涉及到數據的更改。對于前者,可以通過readOnly標識出來,這樣有利于操作性能的提高,需要注意的是由于父類節點定義的Bean僅是子節點配置信息的抽象,并不能具體實現化一個Bean對象,所以需要特別標注為abstract="true",如第8行所示。

      fileService作為一個目標類被注入到事務代理器中,而fileService實現類所需要的tfileDAO實例,通過引用3.2節中定義的tfileDAO Bean注入。


    posted @ 2008-04-10 15:01 阿偉 閱讀(235) | 評論 (0)編輯 收藏

    Struts+Spring+Hibernate實現上傳下載(二)

    轉自:http://lihaiyan.javaeye.com/blog/127795

    數據持久層

      1、領域對象及映射文件

      您可以使用Hibernate Middlegen、HIbernate Tools、Hibernate Syhchronizer等工具或手工的方式,編寫Hibernate的領域對象和映射文件。其中對應T_FILE表的領域對象Tfile.java為:

      代碼 1 領域對象Tfile

    1. package sshfile.model;
    2. public class Tfile
    3.{
    4. private String fileId;
    5. private String fileName;
    6. private byte[] fileContent;
    7. private String remark;
    8. …//getter and setter
    9. }

      特別需要注意的是:數據庫表為Blob類型的字段在Tfile中的fileContent類型為byte[]。Tfile的Hibernate映射文件Tfile.hbm.xml放在Tfile .java類文件的相同目錄下:

      代碼 2 領域對象映射文件

    1. <?xml version="1.0"?>
    2. <!DOCTYPE hibernate-mapping PUBLIC
    3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
    5. <hibernate-mapping>
    6. <class name="sshfile.model.Tfile" table="T_FILE">
    7. <id name="fileId" type="java.lang.String" column="FILE_ID">
    8. <generator class="uuid.hex"/>
    9. </id>
    10. <property name="fileContent"
    11. type="org.springframework.orm.hibernate3.support.BlobByteArrayType"
    12. column="FILE_CONTENT" lazy="true"/>
    13. …//其它一般字段的映射
    14. </class>
    15. </hibernate-mapping>

      fileContent字段映射為Spring所提供的BlobByteArrayType類型,BlobByteArrayType是用戶自定義的數據類型,它實現了Hibernate 的org.hibernate.usertype.UserType接口。BlobByteArrayType使用從sessionFactory獲取的Lob操作句柄lobHandler將byte[]的數據保存到Blob數據庫字段中。這樣,我們就再沒有必要通過硬編碼的方式,先insert然后再update來完成Blob類型數據的持久化,這個原來難伺候的老爺終于被平民化了。關于lobHandler的配置請見本文后面的內容。

      此外lazy="true"說明地返回整個Tfile對象時,并不返回fileContent這個字段的數據,只有在顯式調用tfile.getFileContent()方法時才真正從數據庫中獲取fileContent的數據。這是Hibernate3引入的新特性,對于包含重量級大數據的表字段,這種抽取方式提高了對大字段操作的靈活性,否則加載Tfile對象的結果集時如果總是返回fileContent,這種批量的數據抽取將可以引起數據庫的"洪泛效應"。

      2、DAO編寫和配置

      Spring強調面向接口編程,所以我們將所有對Tfile的數據操作的方法定義在TfileDAO接口中,這些接口方法分別是:

      ·findByFildId(String fileId)

      ·save(Tfile tfile)

      ·List findAll()

      TfileDAOHibernate提供了對TfileDAO接口基于Hibernate的實現,如代碼 3所示:

      代碼 3 基于Hibernate 的fileDAO實現類

    1. package sshfile.dao;
    2.
    3. import sshfile.model.*;
    4. import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
    5. import java.util.List;
    6.
    7. public class TfileDAOHibernate
    8. extends HibernateDaoSupport implements TfileDAO
    9. {
    10. public Tfile findByFildId(String fileId)
    11. {
    12. return (Tfile) getHibernateTemplate().get(Tfile.class, fileId);
    13. }
    14. public void save(Tfile tfile)
    15. {
    16. getHibernateTemplate().save(tfile);
    17. getHibernateTemplate().flush();
    18. }
    19. public List findAll()
    20. {
    21. return getHibernateTemplate().loadAll(Tfile.class);
    22. }
    23. }

      TfileDAOHibernate通過擴展Spring提供的Hibernate支持類HibernateDaoSupport而建立,HibernateDaoSupport封裝了HibernateTemplate,而HibernateTemplate封裝了Hibernate所提供幾乎所有的的數據操作方法,如execute(HibernateCallback action),load(Class entityClass, Serializable id),save(final Object entity)等等。

      所以我們的DAO只需要簡單地調用父類的HibernateTemplate就可以完成幾乎所有的數據庫操作了。

      由于Spring通過代理Hibernate完成數據層的操作,所以原Hibernate的配置文件hibernate.cfg.xml的信息也轉移到Spring的配置文件中:

      代碼 4 Spring中有關Hibernate的配置信息

    1. <beans>
    2. <!-- 數據源的配置 //-->
    3. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    4. destroy-method="close">
    5. <property name="driverClassName" value="http://www.zhmy.com/oracle.jdbc.driver.OracleDriver"/>
    6. <property name="url" value="jdbc:oracle:thin:@localhost:1521:ora9i"/>
    7. <property name="username" value="test"/>
    8. <property name="password" value="test"/>
    9. </bean>
    10. <!-- Hibernate會話工廠配置 //-->
    11. <bean id="sessionFactory"
    12. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    13. <property name="dataSource" ref="dataSource"/>
    14. <property name="mappingDirectoryLocations">
    15. <list>
    16. <value>classpath:/sshfile/model</value>
    17. </list>
    18. </property>
    19. <property name="hibernateProperties">
    20. <props>
    21. <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
    22. <prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
    23. </props>
    24. </property>
    25. </bean>
    26. <!-- Hibernate 模板//-->
    27. <bean id="hibernateTemplate"
    28. class="org.springframework.orm.hibernate3.HibernateTemplate">
    29. <property name="sessionFactory" ref="sessionFactory"/>
    30. </bean>
    31. <!--DAO配置 //-->
    32. <bean id="tfileDAO" class="sshfile.dao.TfileDAOHibernate">
    33. <property name="hibernateTemplate" ref="hibernateTemplate" />
    34. </bean>
    35. …
    36. </beans>

      第3~9行定義了一個數據源,其實現類是apache的BasicDataSource,第11~25行定義了Hibernate的會話工廠,會話工廠類用Spring提供的LocalSessionFactoryBean維護,它注入了數據源和資源映射文件,此外還通過一些鍵值對設置了Hibernate所需的屬性。

      其中第16行通過類路徑的映射方式,將sshfile.model類包目錄下的所有領域對象的映射文件裝載進來,在本文的例子里,它將裝載進Tfile.hbm.xml映射文件。如果有多個映射文件需要聲明,使用類路徑映射方式顯然比直接單獨指定映射文件名的方式要簡便。

      第27~30行定義了Spring代理Hibernate數據操作的HibernateTemplate模板,而第32~34行將該模板注入到tfileDAO中。

      需要指定的是Spring 1.2.5提供了兩套Hibernate的支持包,其中Hibernate 2相關的封裝類位于org.springframework.orm.hibernate2.*包中,而Hibernate 3.0的封裝類位于org.springframework.orm.hibernate3.*包中,需要根據您所選用Hibernate版本進行正確選擇。

      3、Lob字段處理的配置

      我們前面已經指出Oracle的Lob字段和一般類型的字段在操作上有一個明顯的區別--那就是你必須首先通過Oracle的empty_blob()/empty_clob()初始化Lob字段,然后獲取該字段的引用,通過這個引用更改其值。所以要完成對Lob字段的操作,Hibernate必須執行兩步數據庫訪問操作,先Insert再Update。

      使用BlobByteArrayType字段類型后,為什么我們就可以象一般的字段類型一樣操作Blob字段呢?可以確定的一點是:BlobByteArrayType不可能逾越Blob天生的操作方式,原來是BlobByteArrayType數據類型本身具體數據訪問的功能,它通過LobHandler將兩次數據訪問的動作隱藏起來,使Blob字段的操作在表現上和其他一般字段業類型無異,所以LobHandler即是那個"苦了我一個,幸福十億人"的那位幕后英雄。

      LobHandler必須注入到Hibernate會話工廠sessionFactory中,因為sessionFactory負責產生與數據庫交互的Session。LobHandler的配置如代碼 5所示:

      代碼 5 Lob字段的處理句柄配置

    1. <beans>
    2. …
    3. <bean id="nativeJdbcExtractor"
    4. class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"
    5. lazy-init="true"/>
    6. <bean id="lobHandler"
    7. class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true">
    8. <property name="nativeJdbcExtractor">
    9. <ref local="nativeJdbcExtractor"/>
    10. </property>
    11. </bean>
    12. …
    13. </beans>

      首先,必須定義一個能夠從連接池中抽取出本地數據庫JDBC對象(如OracleConnection,OracleResultSet等)的抽取器:nativeJdbcExtractor,這樣才可以執行一些特定數據庫的操作。對于那些僅封裝了Connection而未包括Statement的簡單數據連接池,SimpleNativeJdbcExtractor是效率最高的抽取器實現類,但具體到apache的BasicDataSource連接池,它封裝了所有JDBC的對象,這時就需要使用CommonsDbcpNativeJdbcExtractor了。Spring針對幾個著名的Web服務器的數據源提供了相應的JDBC抽取器:

      ·WebLogic:WebLogicNativeJdbcExtractor

      ·WebSphere:WebSphereNativeJdbcExtractor

      ·JBoss:JBossNativeJdbcExtractor

      在定義了JDBC抽取器后,再定義lobHandler。Spring 1.2.5提供了兩個lobHandler:

      ·DefaultLobHandler:適用于大部分的數據庫,如SqlServer,MySQL,對Oracle 10g也適用,但不適用于Oracle 9i(看來Oracle 9i確實是個怪胎,誰叫Oracle 公司自己都說Oracle 9i是一個過渡性的產品呢)。

      ·OracleLobHandler:適用于Oracle 9i和Oracle 10g。

      由于我們的數據庫是Oracle9i,所以使用OracleLobHandler。

      在配置完LobHandler后, 還需要將其注入到sessionFactory的Bean中,下面是調用后的sessionFactory Bean的配置:

      代碼 6 將lobHandler注入到sessionFactory中的配置

    1. <beans>
    2. …
    3. <bean id="sessionFactory"
    4. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    5. <property name="dataSource" ref="dataSource"/>
    6. <!-- 為處理Blob類型字段的句柄聲明 //-->
    7. <property name="lobHandler" ref="lobHandler"/>
    8. …
    9. </bean>
    10. …
    11. </beans>

      如第7所示,通過sessionFactory的lobHandler屬性進行注入。


    posted @ 2008-04-10 14:55 阿偉 閱讀(289) | 評論 (0)編輯 收藏
    轉自:http://lihaiyan.javaeye.com/blog/127794
    引言

      文件的上傳和下載在
    J2EE編程已經是一個非常古老的話題了,也許您馬上就能掰著指頭數出好幾個著名的大件:如SmartUpload、Apache的FileUpload。但如果您的項目是構建在Struts+Spring+Hibernate(以下稱SSH)框架上的,這些大件就顯得笨重而滄桑了,SSH提供了一個簡捷方便的文件上傳下載的方案,我們只需要通過一些配置并輔以少量的代碼就可以完好解決這個問題了。

      本文將圍繞SSH文件上傳下載的主題,向您詳細講述如何開發基于SSH的Web程序。SSH各框架的均為當前最新版本:

      ·Struts 1.2

      ·Spring 1.2.5

      ·Hibernate 3.0

      本文選用的數據庫為
    Oracle 9i,當然你可以在不改動代碼的情況下,通過配置文件的調整將其移植到任何具有Blob字段類型的數據庫上,如MySQL,SQLServer等。

      總體實現

      上傳文件保存到T_FILE表中,T_FILE表結構如下:

    420){this.resized=true;this.style.width=420;}" border=0>
    圖 1 T_FILE表結構

      其中:

      ·FILE_ID:文件ID,32個字符,用Hibernate的uuid.hex算法生成。

      ·FILE_NAME:文件名。

      ·FILE_CONTENT:文件內容,對應Oracle的Blob類型。

      ·REMARK:文件備注。

      文件數據存儲在Blob類型的FILE_CONTENT表字段上,在Spring中采用OracleLobHandler來處理Lob字段(包括Clob和Blob),由于在程序中不需要引用到oracle數據驅動程序的具體類且屏蔽了不同數據庫處理Lob字段方法上的差別,從而撤除程序在多數據庫移植上的樊籬。

      1.首先數據表中的Blob字段在Java領域對象中聲明為byte[]類型,而非java.sql.Blob類型。

      2.數據表Blob字段在Hibernate持久化映射文件中的type為org.springframework.orm.hibernate3.support.BlobByteArrayType,即Spring所提供的用戶自定義的類型,而非java.sql.Blob。

      3.在Spring中使用org.springframework.jdbc.support.lob.OracleLobHandler處理Oracle數據庫的Blob類型字段。

      通過這樣的設置和配置,我們就可以象持久化表的一般字段類型一樣處理Blob字段了。

      以上是Spring+Hibernate將文件二進制數據持久化到數據庫的解決方案,而Struts通過將表單中file類型的組件映射為ActionForm中類型為org.apache.struts.upload. FormFile的屬性來獲取表單提交的文件數據。

      綜上所述,我們可以通過圖 2,描繪出SSH處理文件上傳的方案:

    420){this.resized=true;this.style.width=420;}" border=0>
    圖 2 SSH處理文件上傳技術方案

      文件上傳的頁面如圖 3所示:

    420){this.resized=true;this.style.width=420;}" border=0 resized="true">
    圖 3 文件上傳頁面

      文件下載的頁面如圖 4所示:

    420){this.resized=true;this.style.width=420;}" border=0 resized="true">
    圖 4 文件下載頁面

      該工程的資源結構如圖 5所示:

    420){this.resized=true;this.style.width=420;}" border=0>
    圖 5 工程資源結構

      工程的類按SSH的層次結構劃分為數據持久層、業務層和Web層;WEB-INF下的applicationContext.xml為Spring的配置文件,struts-config.xml為Struts的配置文件,file-upload.jsp為文件上傳頁面,file-list.jsp為文件列表頁面。

      本文后面的章節將從數據持久層->業務層->Web層的開發順序,逐層講解文件上傳下載的開發過程。
    posted @ 2008-04-10 14:48 阿偉 閱讀(343) | 評論 (1)編輯 收藏

    轉自:http://ttitfly.javaeye.com/blog/133000

    Spring配置初始化ApplicationContext

    1. 在struts-config.xml里,以插件的形式

    xml 代碼
    < plug-in className="org.springframework.web.struts.ContextLoaderPlugIn" / >  
        < set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml" / >  
    < / plug-in >   

    這種方式如果沒有配置contextConfigLocation的值,則會自動加載xx-servlet.xml.

    xx的值是和web.xml里的配置org.apache.struts.action.ActionServlet的servlet-name的值一樣

    如下:xx的值也就是 action,所以會自動加載action-servlet.xml

    xml 代碼
    < servlet >  
        < servlet-name >action< / servlet-name >  
        < servlet-class >org.apache.struts.action.ActionServlet< / servlet-class >  
        < load-on-startup >1< / load-on-startup >  
      < / servlet >  
      < servlet-mapping >  
        < servlet-name >action< / servlet-name >  
        < url-pattern >*.do< / url-pattern >  
      < / servlet-mapping >  

     如果sturts-config.xml里配置了contextConfigLocation的值,那么就不會自動加載xx-servlet.xml了,而只會加載contextConfigLocation所指定的xml.

     2. 第2種方式

    在web.xml里配置Listener

    xml 代碼
    <listener>  
            <  listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>  
        <  /  listener>  

     

    如果在web.xml里給該Listener指定要加載的xml,如:

    xml 代碼
    <context-param>  
            <param-name>contextConfigLocationparam-name>  
            <param-value>classpath*:spring/*.xmlparam-value>  
        context-param>  

    則會去加載相應的xml,而不會去加載/WEB-INF/下的applicationContext.xml。。但是,如果沒有指定的話,默認會去/WEB-INF/下加載applicationContext.xml。

     

    3. 第三種方式:ContextLoaderServlet

    xml 代碼
    < servlet>    
            < servlet-name>context< / servlet-name>    
            < servlet-class>org.springframework.web.context.ContextLoaderServlet< / servlet-class>    
            < load-on-startup>1< / load-on-startup>    
        < / servlet>  

     

     這種方式和第二種Listener方式一樣,唯一的區別就是用Listener方式初始化ApplicationContext,可以和用第一種方式(struts-config.xml里 plugin方式)同時存在,而ContextLoaderServlet則不可以和第一種方式同時存在

    總結:

    ContextLoaderServlet已經不推薦用了,它只是為了兼容低版本的servlet.jar才用的。

    總的來說:Listerner要比Servlet更好一些,而且Listerner監聽應用的啟動和結束,而Servlet啟動要稍微延遲一些。

     

    posted @ 2008-04-10 10:20 阿偉 閱讀(860) | 評論 (0)編輯 收藏
      轉自:http://blog.tostudy.com.cn/blog/show_3574.html

    優化Web應用的性能絕不象有些人想象的那樣簡單易行,它涉及到諸多技術,從最簡單的HTML代碼修改,到復雜的EJB改造,無不涉及性能問題。但有一點是非常清楚的:要想找出和解決Web應用的性能瓶頸,就必須深入全面地了解信息在Web應用中的流程。

      改善Web應用的性能不一定要局限于Web應用的Java代碼,例如有些時候,簡單地改動一下HTML頁面的質量、減少其傳輸頻度和數據量就可以有效地提高應用的性能表現;有時提高性能的關鍵卻在于修改Web應用的數據庫訪問部分——這只是Java代碼之外影響性能的兩個因素,其他還有許多因素會影響到Web應用的整體性能表現。另一方面,就Java程序本身而言,其性能優化又可以分成三個領域:基本的Java代碼優化,JSP/Servlet優化,EJB優化。

      一、表現層優化

      Web應用的最大性能瓶頸常常不在其他地方,而在于最基本的網絡帶寬限制。如果你的Web應用也面臨這類問題,提高性能最簡單的辦法是減少HTTP傳輸,例如用JavaScript實現客戶端編輯功能以減少數據傳輸次數,避免將數據發送到服務器端再執行合法性驗證之類的編輯操作。

      應當采用一切可能措施減少通過網絡傳輸的數據。例如,你可以要求瀏覽器緩沖模塊化的JavaScript文件,在SCRIPT標記的SRC中指定:
    SCRIPT LANGUAGE="JavaScript" SRC="FormChek.js"。

      其他減少網絡傳輸應當注意的地方還包括:避免過度使用隱藏域,減少超長Cookie值,在RADIO、CHECKBOX和SELECT域中用代碼來替代長長的字符串,等等。不過在HTML優化方面本文不準備作全面的討論,因為WebSphere應用的開發者一般不會擔負設計表現層的責任,只要了解下面這個原理就足夠了:

      性能技巧之一:盡可能減少HTTP數據傳輸的總量和頻度

      二、數據庫訪問

      朋友小A對Java的了解極為有限,但他卻成功地改進了許多WebSphere應用的性能。他是怎么做到的呢?原來,小A是一個數據庫專家,他通過優化數據庫訪問有效地改進了整個應用的性能,但對于Java,他只是略微了解一些有關JDBC的知識。在優化數據庫訪問時,小A做的第一件事情總是檢查數據庫的設計,有時他會建議重新構造數據庫的結構(必須指出的是,為了提高性能而重新構造數據庫結構有時可能使數據庫反規格化(De-Normalization),從而帶來維護方面的問題)。 
    性能技巧之二:規格化(Normalization)數據庫結構

      小A做的第二件事情是執行數據庫分析,根據分析結果提出增加某個索引、減少某個索引的建議。完成這一步驟后,小A通常可以讓應用有令人滿意的性能表現,根本不必去查看應用的Java代碼。

      性能技巧之三:針對常用的SQL操作建立索引,刪除多余的索引

      有時,為了進一步優化應用的性能,小A會檢查Java(也許應該說是SQL)代碼,經常找到Java程序沒有合理運用PreparedStatement和連接緩沖池的情形。只要把Statement類的動態SQL替換成PreparedStatement類的靜態SQL,從連接池提取SQL連接(而不是直接創建連接),應用的性能將得到顯著的改善。注意DB2 UDB(包括其他一些數據庫)的PreparedStatement是可調整和配置的。

      性能技巧之四:合理運用PreparedStatement和連接池

      進一步分析應用的工作流程之后,小A有時會建議批量執行某些SQL命令,這樣就只需一個對數據庫服務器的請求就可以運行大量的SQL命令。

      性能技巧之五:考慮批量執行SQL命令

      既然如此,小A有時還會指出,如果應用中有些SQL命令可以組合成單個事務邏輯,那么應該可以用一個存儲過程來替代。DB2 UDB的存儲過程語言(SPL,Stored Procedure Language)非常強大,如果把數據庫操作邏輯從Web應用轉移到數據庫,一般總是對性能有益。不過需要注意的是,雖然批量執行SQL命令或使用存儲過程會提高性能,但就象重新構造數據庫結構一樣,有時會帶來維護方面的困難。

      性能技巧之六:考慮使用數據庫存儲過程

      檢查JDBC代碼的時候,小A總是留意對象有沒有及時正確釋放。這一點其實很重要。

      性能技巧之七:及時關閉不用的Statement、ResultSet、Connection等對象(但不是在finalize方法內)

    三、Java代碼

      前面我們以小A的經驗為例,探討了Web應用中數據庫訪問性能的重要性。調整好數據庫之后,接下來要做的自然是深入分析應用的Java代碼。從哪里入手呢?你最好使用Java分析工具來找出性能問題的焦點所在。優化Java代碼的性能是一個艱苦的過程,因此一個重要的原則是把精力集中到那些可能引起性能問題的代碼上。換句話說,就是要尊重80/20規則:利用Java分析工具的結果,調整帶來80%性能開銷的那20%代碼。

      性能技巧之八:用Java分析工具清楚地界定性能問題所在

      目前市場上已經有許多優秀的Java分析工具,例如ej-technologie的JProfile(http://www.ej-technologies.com),Klgroup的Jprobe(http://www.klg.com),以及Intuitive Systems的OptimizeIt(http://www.optimizeit.com)。不過不要忘記WebSphere Studio Application Developer(WSAD)本身也集成了一個優秀的分析器,有條件的話,最好多用幾種分析工具分析Java代碼。

      考慮到資金問題,你不一定樂意購買昂貴的分析軟件,但你可以用Java本身的命令行工具生成分析信息。例如,在JDK 1.3中,你可以用下面的命令將TestOrderProcessing類的CPU使用情況保存到java.hprof文件:java -Xrunhprof:cpu=times,format=a,file=java.hprof TestOrderProcessing。

      這種辦法的缺點是它提供的信息條理不夠清楚,比較繁雜;也許可以找到一些源代碼開放的工具輔助分析,但一般不如使用WSAD本身的分析工具或商業化的分析工具方便。另外,如果你已經了解哪些代碼塊可能引起性能問題,可以通過保存系統時間的方式獲得分析信息,例如:
    long startTime = System.currentTimeMillis();
    // 執行某些操作
    long endTime = System.currentTimeMillis();

      3.1 基本篇

      有人建議“穩定性第一,速度第二”,一般而言遵從這個建議是不會錯的,但這并不妨礙我們在編寫代碼的同時運用某些已經證實的性能技巧。例如,我們都知道String類是不可變的,連接兩個String是一項開銷很大操作。

      性能技巧之九:用StringBuffer來連接兩個字符串

      也許你已經注意到,SUN的許多標準Java類是線程安全的,這些類內部的同步機制實際上很容易造成性能問題。例如,Vector類就是一個線程安全的類,除非確實要用到同步機制,否則使用Vector是不值得的,如有可能,應當盡量改用非線程安全的類如ArrayList。

      性能技巧之十:只有在必要時才運用線程安全的類

      許多人習慣使用System.out.println來輸出跟蹤信息,但println要占用不少資源,所以輸出跟蹤信息最好使用專用日志記錄框架,如IBM的JRas或Apache的Log4j。

      性能技巧之十一:用日志記錄框架類輸出跟蹤信息,而不是使用System.out.println

      最后一個提高代碼性能的簡單技巧是清除類里面的調試信息,減小類的體積。IBM有一個WSAD插件,它提供了一個叫做setDebugInfo的任務,可以從Ant腳本調用。

      性能技巧之十二:從正式發行的軟件中刪除調試信息

    posted @ 2008-04-08 13:03 阿偉 閱讀(202) | 評論 (0)編輯 收藏
    web.xml配置的詳細說明3
    7 指定歡迎頁

    假如用戶提供了一個像http: //host/webAppPrefix/directoryName/ 這樣的包含一個目錄名但沒有包含文件名的URL,會發生什么事情呢?用戶能得到一個目錄表?一個錯誤?還是標準文件的內容?如果得到標準文件內容,是 index.html、index.jsp、default.html、default.htm或別的什么東西呢?
    Welcome-file-list 元素及其輔助的welcome-file元素解決了這個模糊的問題。例如,下面的web.xml項指出,如果一個URL給出一個目錄名但未給出文件名,服務器應該首先試用index.jsp,然后再試用index.html。如果兩者都沒有找到,則結果有賴于所用的服務器(如一個目錄列表)。
    <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.html</welcome-file>
    </welcome-file-list>
    雖然許多服務器缺省遵循這種行為,但不一定必須這樣。因此,明確地使用welcom-file-list保證可移植性是一種良好的習慣。

    8 指定處理錯誤的頁面

    現在我了解到,你在開發servlet和JSP頁面時從不會犯錯誤,而且你的所有頁面是那樣的清晰,一般的程序員都不會被它們的搞糊涂。但是,是人總會犯錯誤的,用戶可能會提供不合規定的參數,使用不正確的URL或者不能提供必需的表單字段值。除此之外,其它開發人員可能不那么細心,他們應該有些工具來克服自己的不足。
    error-page元素就是用來克服這些問題的。它有兩個可能的子元素,分別是:error-code和exception- type。第一個子元素error-code指出在給定的HTTP錯誤代碼出現時使用的URL。第二個子元素excpetion-type指出在出現某個給定的Java異常但未捕捉到時使用的URL。error-code和exception-type都利用location元素指出相應的URL。此 URL必須以/開始。location所指出的位置處的頁面可通過查找HttpServletRequest對象的兩個專門的屬性來訪問關于錯誤的信息,這兩個屬性分別是:javax.servlet.error.status_code和javax.servlet.error.message。
    可回憶一下,在web.xml內以正確的次序聲明web-app的子元素很重要。這里只要記住,error-page出現在web.xml文件的末尾附近,servlet、servlet-name和welcome-file-list之后即可。

    8.1 error-code元素
    為了更好地了解error-code元素的值,可考慮一下如果不正確地輸入文件名,大多數站點會作出什么反映。這樣做一般會出現一個404錯誤信息,它表示不能找到該文件,但幾乎沒提供更多有用的信息。另一方面,可以試一下在www.microsoft.comwww.ibm.com 處或者特別是在www.bea.com 處輸出未知的文件名。這是會得出有用的消息,這些消息提供可選擇的位置,以便查找感興趣的頁面。提供這樣有用的錯誤頁面對于Web應用來說是很有價值得。事實上rm-error-page子元素)。由form-login-page給出的HTML表單必須具有一個j_security_check的 ACTION屬性、一個名為j_username的用戶名文本字段以及一個名為j_password的口令字段。
    例如,程序清單5-19指示服務器使用基于表單的驗證。Web應用的頂層目錄中的一個名為login.jsp的頁面將收集用戶名和口令,并且失敗的登陸將由相同目錄中名為login-error.jsp的頁面報告。

    程序清單5-19 web.xml(說明login-config的摘錄)
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "

    <web-app>
    <!-- ... -->
    <security-constraint> ... </security-constraint>
    <login-config>
    <auth-method> FORM </auth-method>
    <form-login-config>
    <form-login-page>/login.jsp</form-login-page>
    <form-error-page>/login-error.jsp</form-error-page>
    </form-login-config>
    </login-config>
    <!-- ... -->
    </web-app>

    8.2 exception-type元素
    error-code元素處理某個請求產生一個特定的HTTP狀態代碼時的情況。然而,對于servlet或JSP頁面返回200但產生運行時異常這種同樣是常見的情況怎么辦呢?這正是exception-type元素要處理的情況。只需提供兩樣東西即可:即提供如下的一個完全限定的異常類和一個位置:
    <error-page>
    <exception-type>packageName.className</exception-type>
    <location>/SomeURL</location>
    </error-page>
    這樣,如果Web應用中的任何servlet或JSP頁面產生一個特定類型的未捕捉到的異常,則使用指定的URL。此異常類型可以是一個標準類型,如javax.ServletException或java.lang.OutOfMemoryError,或者是一個專門針對你的應用的異常。
    例如,程序清單5-15給出了一個名為DumbDeveloperException的異常類,可用它來特別標記經驗較少的程序員(不是說你的開發組中一定有這種人)所犯的錯誤。這個類還包含一個名為dangerousComputation的靜態方法,它時不時地生成這種類型的異常。程序清單5-16給出對隨機整數值調用dangerousCompution的一個JSP頁面。在拋出此異常時,如程序清單5-18的web.xml版本中所給出的exception-type所指出的那樣,對客戶機顯示DDE.jsp(程序清單5-17)。圖5-16和圖5-17分別給出幸運和不幸的結果。

    程序清單5-15 DumbDeveloperException.java
    package moreservlets;

    /** Exception used to flag particularly onerous
    programmer blunders. Used to illustrate the
    exception-type web.xml element.
    * <P>
    * Taken from More Servlets and JavaServer Pages
    * from Prentice Hall and Sun Microsystems Press,
    *
    http://www.moreservlets.com/.
    * &copy; 2002 Marty Hall; may be freely used or adapted.
    */

    public class DumbDeveloperException extends Exception {
    public DumbDeveloperException() {
    super("Duh. What was I *thinking*?");
    }

    public static int dangerousComputation(int n)
    throws DumbDeveloperException {
    if (n < 5) {
    return(n + 10);
    } else {
    throw(new DumbDeveloperException());
    }
    }
    }


    程序清單5-16 RiskyPage.jsp
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
    <HEAD><TITLE>Risky JSP Page</TITLE></HEAD>
    <BODY BGCOLOR="#FDF5E6">
    <H2>Risky Calculations</H2>
    <%@ page import="moreservlets.*" %>
    <% int n = ((int)(10 * Math.random())); %>
    <UL>
    <LI>n: <%= n %>
    <LI>dangerousComputation(n):
    <%= DumbDeveloperException.dangerousComputation(n) %>
    </UL>
    </BODY></HTML>


    程序清單5-17 DDE.jsp
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
    <HEAD><TITLE>Dumb</TITLE></HEAD>
    <BODY BGCOLOR="#FDF5E6">
    <H2>Dumb Developer</H2>
    We're brain dead. Consider using our competitors.
    </BODY></HTML>


    程序清單5-18 web.xml(為異常指定錯誤頁面的摘錄)
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "

    <web-app>
    <!-- ... -->
    <servlet> … </servlet>
    <!-- ... -->
    <error-page>
    <exception-type>
    moreservlets.DumbDeveloperException
    </exception-type>
    <location>/DDE.jsp</location>
    </error-page>
    <!-- ... -->
    </web-app>

    9 提供安全性

    利用web.xml中的相關元素為服務器的內建功能提供安全性。
    9.1 指定驗證的方法
    使用login-confgi元素規定服務器應該怎樣驗證試圖訪問受保護頁面的用戶。它包含三個可能的子元素,分別是:auth-method、realm-name和form-login-config。login-config元素應該出現在web.xml部署描述符文件的結尾附近,緊跟在security-constraint元素之后。
    l auth-method
    login-config的這個子元素列出服務器將要使用的特定驗證機制。有效值為BASIC、DIGEST、FORM和CLIENT-CERT。服務器只需要支持BASIC和FORM。
    BASIC指出應該使用標準的HTTP驗證,在此驗證中服務器檢查Authorization頭。如果缺少這個頭則返回一個401狀態代碼和一個WWW-Authenticate頭。這導致客戶機彈出一個用來填寫Authorization頭的對話框。此機制很少或不提供對攻擊者的防范,這些攻擊者在Internet連接上進行窺探(如通過在客戶機的子網上執行一個信息包探測裝置),因為用戶名和口令是用簡單的可逆base64編碼發送的,他們很容易得手。所有兼容的服務器都需要支持BASIC驗證。
    DIGEST指出客戶機應該利用加密Digest Authentication形式傳輸用戶名和口令。這提供了比BASIC驗證更高的防范網絡截取得的安全性,但這種加密比SSL(HTTPS)所用的方法更容易破解。不過,此結論有時沒有意義,因為當前很少有瀏覽器支持Digest Authentication,所以servlet容器不需要支持它。
    FORM指出服務器應該檢查保留的會話cookie并且把不具有它的用戶重定向到一個指定的登陸頁。此登陸頁應該包含一個收集用戶名和口令的常規HTML表單。在登陸之后,利用保留會話級的cookie跟蹤用戶。雖然很復雜,但FORM驗證防范網絡窺探并不比BASIC驗證更安全,如果有必要可以在頂層安排諸如SSL或網絡層安全(如IPSEC或VPN)等額外的保護。所有兼容的服務器都需要支持FORM驗證。
    CLIENT-CERT規定服務器必須使用HTTPS(SSL之上的HTTP)并利用用戶的公開密鑰證書(Pulic Key Certificat)對用戶進行驗證。這提供了防范網絡截取的很強的安全性,但只有兼容J2EE的服務器需要支持它。
    l realm-name
    此元素只在auth-method為BASIC時使用。它指出瀏覽器在相應對話框標題使用的、并作為Authorization頭組成部分的安全域的名稱。
    l form-login-config
    此元素只在auth-method為FORM時適用。它指定兩個頁面,分別是:包含收集用戶名及口令的HTML表單的頁面(利用form-login-page子元素),用來指示驗證失敗的頁面(利用form-error-page子元素)。由form-login-page給出的HTML表單必須具有一個j_security_check的ACTION屬性、一個名為j_username的用戶名文本字段以及一個名為j_password的口令字段。
    例如,程序清單5-19指示服務器使用基于表單的驗證。Web應用的頂層目錄中的一個名為login.jsp的頁面將收集用戶名和口令,并且失敗的登陸將由相同目錄中名為login-error.jsp的頁面報告。

    程序清單5-19 web.xml(說明login-config的摘錄)
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "

    <web-app>
    <!-- ... -->
    <security-constraint> ... </security-constraint>
    <login-config>
    <auth-method> FORM </auth-method>
    <form-login-config>
    <form-login-page>/login.jsp</form-login-page>
    <form-error-page>/login-error.jsp</form-error-page>
    </form-login-config>
    </login-config>
    <!-- ... -->
    </web-app>


    9.2 限制對Web資源的訪問
    現在,可以指示服務器使用何種驗證方法了。"了不起,"你說道,"除非我能指定一個來收到保護的 URL,否則沒有多大用處。"沒錯。指出這些URL并說明他們應該得到何種保護正是security-constriaint元素的用途。此元素在 web.xml中應該出現在login-config的緊前面。它包含是個可能的子元素,分別是:web-resource-collection、 auth-constraint、user-data-constraint和display-name。下面各小節對它們進行介紹。
    l web-resource-collection
    此元素確定應該保護的資源。所有security-constraint元素都必須包含至少一個web-resource-collection項。此元素由一個給出任意標識名稱的web-resource-name元素、一個確定應該保護的URL的url-pattern元素、一個指出此保護所適用的 HTTP命令(GET、POST等,缺省為所有方法)的http-method元素和一個提供資料的可選description元素組成。例如,下面的 Web-resource-collection項(在security-constratint元素內)指出Web應用的proprietary目錄中所有文檔應該受到保護。
    <security-constraint>
    <web-resource-coolection>
    <web-resource-name>Proprietary</web-resource-name>
    <url-pattern>/propritary/*</url-pattern>
    </web-resource-coolection>
    <!-- ... -->
    </security-constraint>
    重要的是應該注意到,url-pattern僅適用于直接訪問這些資源的客戶機。特別是,它不適合于通過MVC體系結構利用 RequestDispatcher來訪問的頁面,或者不適合于利用類似jsp:forward的手段來訪問的頁面。這種不勻稱如果利用得當的話很有好處。例如,servlet可利用MVC體系結構查找數據,把它放到bean中,發送請求到從bean中提取數據的JSP頁面并顯示它。我們希望保證決不直接訪問受保護的JSP頁面,而只是通過建立該頁面將使用的bean的servlet來訪問它。url-pattern和auth-contraint元素可通過聲明不允許任何用戶直接訪問JSP頁面來提供這種保證。但是,這種不勻稱的行為可能讓開發人員放松警惕,使他們偶然對應受保護的資源提供不受限制的訪問。
    l auth-constraint
    盡管web-resource-collention元素質出了哪些URL應該受到保護,但是auth-constraint元素卻指出哪些用戶應該具有受保護資源的訪問權。此元素應該包含一個或多個標識具有訪問權限的用戶類別role- name元素,以及包含(可選)一個描述角色的description元素。例如,下面web.xml中的security-constraint元素部門規定只有指定為Administrator或Big Kahuna(或兩者)的用戶具有指定資源的訪問權。
    <security-constraint>
    <web-resource-coolection> ... </web-resource-coolection>
    <auth-constraint>
    <role-name>administrator</role-name>
    <role-name>kahuna</role-name>
    </auth-constraint>
    </security-constraint>
    重要的是認識到,到此為止,這個過程的可移植部分結束了。服務器怎樣確定哪些用戶處于任何角色以及它怎樣存放用戶的口令,完全有賴于具體的系統。
    例如,Tomcat使用install_dir/conf/tomcat-users.xml將用戶名與角色名和口令相關聯,正如下面例子中所示,它指出用戶joe(口令bigshot)和jane(口令enaj)屬于administrator和kahuna角色。
    <tomcat-users>
    <user name="joe" password="bigshot" roles="administrator,kahuna" />
    <user name="jane" password="enaj" roles="kahuna" />
    </tomcat-users>
    l user-data-constraint
    這個可選的元素指出在訪問相關資源時使用任何傳輸層保護。它必須包含一個transport-guarantee子元素(合法值為NONE、 INTEGRAL或CONFIDENTIAL),并且可選地包含一個description元素。transport-guarantee為NONE值將對所用的通訊協議不加限制。INTEGRAL值表示數據必須以一種防止截取它的人閱讀它的方式傳送。雖然原理上(并且在未來的HTTP版本中),在 INTEGRAL和CONFIDENTIAL之間可能會有差別,但在當前實踐中,他們都只是簡單地要求用SSL。例如,下面指示服務器只允許對相關資源做 HTTPS連接:
    <security-constraint>
    <!-- ... -->
    <user-data-constraint>
    <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
    </security-constraint>
    l display-name
    security-constraint的這個很少使用的子元素給予可能由GUI工具使用的安全約束項一個名稱。
    9.3 分配角色名
    迄今為止,討論已經集中到完全由容器(服務器)處理的安全問題之上了。但servlet以及JSP頁面也能夠處理它們自己的安全問題。
    例如,容器可能允許用戶從bigwig或bigcheese角色訪問一個顯示主管人員額外緊貼的頁面,但只允許bigwig用戶修改此頁面的參數。完成這種更細致的控制的一種常見方法是調用HttpServletRequset的isUserInRole方法,并據此修改訪問。
    Servlet的 security-role-ref子元素提供出現在服務器專用口令文件中的安全角色名的一個別名。例如,假如編寫了一個調用 request.isUserInRole("boss")的servlet,但后來該servlet被用在了一個其口令文件調用角色manager而不是boss的服務器中。下面的程序段使該servlet能夠使用這兩個名稱中的任何一個。
    <servlet>
    <!-- ... -->
    <security-role-ref>
    <role-name>boss</role-name> <!-- New alias -->
    <role-link>manager</role-link> <!-- Real name -->
    </security-role-ref>
    </servlet>
    也可以在web-app內利用security-role元素提供將出現在role-name元素中的所有安全角色的一個全局列表。分別地生命角色使高級IDE容易處理安全信息。

    10 控制會話超時

    如果某個會話在一定的時間內未被訪問,服務器可把它扔掉以節約內存。可利用HttpSession的setMaxInactiveInterval方法直接設置個別會話對象的超時值。如果不采用這種方法,則缺省的超時值由具體的服務器決定。但可利用session-config和session- timeout元素來給出一個適用于所有服務器的明確的超時值。超時值的單位為分鐘,因此,下面的例子設置缺省會話超時值為三個小時(180分鐘)。
    <session-config>
    <session-timeout>180</session-timeout>
    </session-config>

    11 Web應用的文檔化

    越來越多的開發環境開始提供servlet和JSP的直接支持。例子有Borland Jbuilder Enterprise Edition、Macromedia UltraDev、Allaire JRun Studio(寫此文時,已被Macromedia收購)以及IBM VisuaAge for Java等。
    大量的web.xml元素不僅是為服務器設計的,而且還是為可視開發環境設計的。它們包括icon、display-name和discription等。
    可回憶一下,在web.xml內以適當地次序聲明web-app子元素很重要。不過,這里只要記住icon、display-name和description是web.xml的web-app元素內的前三個合法元素即可。
    l icon
    icon元素指出GUI工具可用來代表Web應用的一個和兩個圖像文件。可利用small-icon元素指定一幅16 x 16的GIF或JPEG圖像,用large-icon元素指定一幅32 x 32的圖像。下面舉一個例子:
    <icon>
    <small-icon>/images/small-book.gif</small-icon>
    <large-icon>/images/tome.jpg</large-icon>
    </icon>
    l display-name
    display-name元素提供GUI工具可能會用來標記此Web應用的一個名稱。下面是個例子。
    <display-name>Rare Books</display-name>
    l description
    description元素提供解釋性文本,如下所示:
    <description>
    This Web application represents the store developed for
    rare-books.com, an online bookstore specializing in rare
    and limited-edition books.
    </description>

    12 關聯文件與MIME類型

    服務器一般都具有一種讓Web站點管理員將文件擴展名與媒體相關聯的方法。例如,將會自動給予名為mom.jpg的文件一個image/jpeg的MIME 類型。但是,假如你的Web應用具有幾個不尋常的文件,你希望保證它們在發送到客戶機時分配為某種MIME類型。mime-mapping元素(具有 extension和mime-type子元素)可提供這種保證。例如,下面的代碼指示服務器將application/x-fubar的MIME類型分配給所有以.foo結尾的文件。
    <mime-mapping>
    <extension>foo</extension>
    <mime-type>application/x-fubar</mime-type>
    </mime-mapping>
    或許,你的Web應用希望重載(override)標準的映射。例如,下面的代碼將告訴服務器在發送到客戶機時指定.ps文件作為純文本(text/plain)而不是作為PostScript(application/postscript)。
    <mime-mapping>
    <extension>ps</extension>
    <mime-type>application/postscript</mime-type>
    </mime-mapping>


    13 定位TLD

    JSP taglib元素具有一個必要的uri屬性,它給出一個TLD(Tag Library Descriptor)文件相對于Web應用的根的位置。TLD文件的實際名稱在發布新的標簽庫版本時可能會改變,但我們希望避免更改所有現有JSP頁面。此外,可能還希望使用保持taglib元素的簡練性的一個簡短的uri。這就是部署描述符文件的taglib元素派用場的所在了。Taglib包含兩個子元素:taglib-uri和taglib-location。taglib-uri元素應該與用于JSP taglib元素的uri屬性的東西相匹配。Taglib-location元素給出TLD文件的實際位置。例如,假如你將文件chart-tags- 1.3beta.tld放在WebApp/WEB-INF/tlds中。現在,假如web.xml在web-app元素內包含下列內容。
    <taglib>
    <taglib-uri>/charts.tld</taglib-uri>
    <taglib-location>
    /WEB-INF/tlds/chart-tags-1.3beta.tld
    </taglib-location>
    </taglib>
    給出這個說明后,JSP頁面可通過下面的簡化形式使用標簽庫。
    <%@ taglib uri="/charts.tld" prefix="somePrefix" %>

    14 指定應用事件監聽程序

    應用事件監聽器程序是建立或修改servlet環境或會話對象時通知的類。它們是servlet規范的版本2.3中的新內容。這里只簡單地說明用來向Web應用注冊一個監聽程序的web.xml的用法。
    注冊一個監聽程序涉及在web.xml的web-app元素內放置一個listener元素。在listener元素內,listener-class元素列出監聽程序的完整的限定類名,如下所示:
    <listener>
    <listener-class>package.ListenerClass</listener-class>
    </listener>
    雖然listener元素的結構很簡單,但請不要忘記,必須正確地給出web-app元素內的子元素的次序。listener元素位于所有的servlet 元素之前以及所有filter-mapping元素之后。此外,因為應用生存期監聽程序是serlvet規范的2.3版本中的新內容,所以必須使用 web.xml DTD的2.3版本,而不是2.2版本。
    例如,程序清單5-20給出一個名為ContextReporter的簡單的監聽程序,只要Web應用的Servlet-Context建立(如裝載Web應用)或消除(如服務器關閉)時,它就在標準輸出上顯示一條消息。程序清單5-21給出此監聽程序注冊所需要的web.xml文件的一部分。

    程序清單5-20 ContextReporterjava
    package moreservlets;

    import javax.servlet.*;
    import java.util.*;

    /** Simple listener that prints a report on the standard output
    * when the ServletContext is created or destroyed.
    * <P>
    * Taken from More Servlets and JavaServer Pages
    * from Prentice Hall and Sun Microsystems Press,
    *
    http://www.moreservlets.com/.
    * © 2002 Marty Hall; may be freely used or adapted.
    */

    public class ContextReporter implements ServletContextListener {
    public void contextInitialized(ServletContextEvent event) {
    System.out.println("Context created on " +
    new Date() + ".");
    }

    public void contextDestroyed(ServletContextEvent event) {
    System.out.println("Context destroyed on " +
    new Date() + ".");
    }
    }

    程序清單5-21 web.xml(聲明一個監聽程序的摘錄)
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "

    <web-app>
    <!-- ... -->
    <filter-mapping> … </filter-mapping>
    <listener>
    <listener-class>package.ListenerClass</listener-class>
    </listener>
    <servlet> ... </servlet>
    <!-- ... -->
    </web-app>

    15 J2EE元素

    本節描述用作J2EE環境組成部分的Web應用的web.xml元素。這里將提供一個簡明的介紹,詳細內容可以參閱http://java.sun.com/j2ee/j2ee-1_3-fr-spec.pdf的Java 2 Plantform Enterprise Edition版本1.3規范的第5章。
    l distributable
    distributable 元素指出,Web應用是以這樣的方式編程的:即,支持集群的服務器可安全地在多個服務器上分布Web應用。例如,一個可分布的應用必須只使用 Serializable對象作為其HttpSession對象的屬性,而且必須避免用實例變量(字段)來實現持續性。distributable元素直接出現在discription元素之后,并且不包含子元素或數據,它只是一個如下的標志。
    <distributable />
    l resource-env-ref
    resource -env-ref元素聲明一個與某個資源有關的管理對象。此元素由一個可選的description元素、一個resource-env-ref- name元素(一個相對于java:comp/env環境的JNDI名)以及一個resource-env-type元素(指定資源類型的完全限定的類),如下所示:
    <resource-env-ref>
    <resource-env-ref-name>
    jms/StockQueue
    </resource-env-ref-name>
    <resource-env-ref-type>
    javax.jms.Queue
    </resource-env-ref-type>
    </resource-env-ref>
    l env-entry
    env -entry元素聲明Web應用的環境項。它由一個可選的description元素、一個env-entry-name元素(一個相對于java: comp/env環境JNDI名)、一個env-entry-value元素(項值)以及一個env-entry-type元素(java.lang程序包中一個類型的完全限定類名,java.lang.Boolean、java.lang.String等)組成。下面是一個例子:
    <env-entry>
    <env-entry-name>minAmout</env-entry-name>
    <env-entry-value>100.00</env-entry-value>
    <env-entry-type>minAmout</env-entry-type>
    </env-entry>
    l ejb-ref
    ejb -ref元素聲明對一個EJB的主目錄的應用。它由一個可選的description元素、一個ejb-ref-name元素(相對于java: comp/env的EJB應用)、一個ejb-ref-type元素(bean的類型,Entity或Session)、一個home元素(bean的主目錄接口的完全限定名)、一個remote元素(bean的遠程接口的完全限定名)以及一個可選的ejb-link元素(當前bean鏈接的另一個 bean的名稱)組成。
    l ejb-local-ref
    ejb-local-ref元素聲明一個EJB的本地主目錄的引用。除了用local-home代替home外,此元素具有與ejb-ref元素相同的屬性并以相同的方式使用

    posted @ 2008-04-06 17:42 阿偉 閱讀(490) | 評論 (0)編輯 收藏

     web.xml配置的詳細說明 2
    4 禁止激活器servlet
    對servlet或JSP頁面建立定制URL的一個原因是,這樣做可以注冊從 init(servlet)或jspInit(JSP頁面)方法中讀取得初始化參數。但是,初始化參數只在是利用定制URL模式或注冊名訪問 servlet或JSP頁面時可以使用,用缺省URL http://host/webAppPrefix/servlet/ServletName 訪問時不能使用。因此,你可能會希望關閉缺省URL,這樣就不會有人意外地調用初始化servlet了。這個過程有時稱為禁止激活器servlet,因為多數服務器具有一個用缺省的servlet URL注冊的標準servlet,并激活缺省的URL應用的實際servlet。
    有兩種禁止此缺省URL的主要方法:
    l 在每個Web應用中重新映射/servlet/模式。
    l 全局關閉激活器servlet。
    重要的是應該注意到,雖然重新映射每個Web應用中的/servlet/模式比徹底禁止激活servlet所做的工作更多,但重新映射可以用一種完全可移植的方式來完成。相反,全局禁止激活器servlet完全是針對具體機器的,事實上有的服務器(如ServletExec)沒有這樣的選擇。下面的討論對每個Web應用重新映射/servlet/ URL模式的策略。后面提供在Tomcat中全局禁止激活器servlet的詳細內容。
    4.1 重新映射/servlet/URL模式
    在一個特定的Web應用中禁止以http://host/webAppPrefix/servlet/ 開始的URL的處理非常簡單。所需做的事情就是建立一個錯誤消息servlet,并使用前一節討論的url-pattern元素將所有匹配請求轉向該 servlet。只要簡單地使用:
    <url-pattern>/servlet/*</url-pattern>
    作為servlet-mapping元素中的模式即可。
    例如,程序清單5-5給出了將SorryServlet servlet(程序清單5-6)與所有以http://host/webAppPrefix/servlet/ 開頭的URL相關聯的部署描述符文件的一部分。
    程序清單5-5 web.xml(說明JSP頁命名的摘錄)
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "

    <web-app>
    <!-- ... -->
    <servlet>
    <servlet-name>Sorry</servlet-name>
    <servlet-class>moreservlets.SorryServlet</servlet-class>
    </servlet>
    <!-- ... -->
    <servlet-mapping>
    <servlet-name> Sorry </servlet-name>
    <url-pattern>/servlet/*</url-pattern>
    </servlet-mapping>
    <!-- ... -->
    </web-app>

    程序清單5-6 SorryServlet.java
    package moreservlets;

    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;

    /** Simple servlet used to give error messages to
    * users who try to access default servlet URLs
    * (i.e.,
    http://host/webAppPrefix/servlet/ServletName)
    * in Web applications that have disabled this
    * behavior.
    * <P>
    * Taken from More Servlets and JavaServer Pages
    * from Prentice Hall and Sun Microsystems Press,
    * http://www.moreservlets.com/.
    * © 2002 Marty Hall; may be freely used or adapted.
    */

    public class SorryServlet extends HttpServlet {
    public void doGet(HttpServletRequest request,
    HttpServletResponse response)
    throws ServletException, IOException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    String title = "Invoker Servlet Disabled.";
    out.println(ServletUtilities.headWithTitle(title) +
    "<BODY BGCOLOR=\"#FDF5E6\">\n" +
    "<H2>" + title + "</H2>\n" +
    "Sorry, access to servlets by means of\n" +
    "URLs that begin with\n" +
    "http://host/webAppPrefix/servlet/\n" +
    "has been disabled.\n" +
    "</BODY></HTML>");
    }

    public void doPost(HttpServletRequest request,
    HttpServletResponse response)
    throws ServletException, IOException {
    doGet(request, response);
    }
    }


    4.2 全局禁止激活器:Tomcat
    Tomcat 4中用來關閉缺省URL的方法與Tomcat 3中所用的很不相同。下面介紹這兩種方法:
    1.禁止激活器: Tomcat 4
    Tomcat 4用與前面相同的方法關閉激活器servlet,即利用web.xml中的url-mapping元素進行關閉。不同之處在于Tomcat使用了放在 install_dir/conf中的一個服務器專用的全局web.xml文件,而前面使用的是存放在每個Web應用的WEB-INF目錄中的標準 web.xml文件。
    因此,為了在Tomcat 4中關閉激活器servlet,只需在install_dir/conf/web.xml中簡單地注釋出/servlet/* URL映射項即可,如下所示:
    <!--
    <servlet-mapping>
    <servlet-name>invoker</servlet-name>
    <url-pattern>/servlet/*</url-pattern>
    </servlet-mapping>
    -->
    再次提醒,應該注意這個項是位于存放在install_dir/conf的Tomcat專用的web.xml文件中的,此文件不是存放在每個Web應用的WEB-INF目錄中的標準web.xml。
    2.禁止激活器:Tomcat3
    在Apache Tomcat的版本3中,通過在install_dir/conf/server.xml中注釋出InvokerInterceptor項全局禁止缺省 servlet URL。例如,下面是禁止使用缺省servlet URL的server.xml文件的一部分。
    <!--
    <RequsetInterceptor
    className="org.apache.tomcat.request.InvokerInterceptor"
    debug="0" prefix="/servlet/" />
    -->

    5 初始化和預裝載servlet與JSP頁面
    這里討論控制servlet和JSP頁面的啟動行為的方法。特別是,說明了怎樣分配初始化參數以及怎樣更改服務器生存期中裝載servlet和JSP頁面的時刻。
    5.1 分配servlet初始化參數
    利用init-param元素向servlet提供初始化參數,init-param元素具有param-name和param-value子元素。例如,在下面的例子中,如果initServlet servlet是利用它的注冊名(InitTest)訪問的,它將能夠從其方法中調用getServletConfig(). getInitParameter("param1")獲得"Value 1",調用getServletConfig().getInitParameter("param2")獲得"2"。
    <servlet>
    <servlet-name>InitTest</servlet-name>
    <servlet-class>moreservlets.InitServlet</servlet-class>
    <init-param>
    <param-name>param1</param-name>
    <param-value>value1</param-value>
    </init-param>
    <init-param>
    <param-name>param2</param-name>
    <param-value>2</param-value>
    </init-param>
    </servlet>
    在涉及初始化參數時,有幾點需要注意:
    l 返回值。GetInitParameter的返回值總是一個String。因此,在前一個例子中,可對param2使用Integer.parseInt獲得一個int。
    l JSP中的初始化。JSP頁面使用jspInit而不是init。JSP頁面還需要使用jsp-file元素代替servlet-class。
    l 缺省URL。初始化參數只在通過它們的注冊名或與它們注冊名相關的定制URL模式訪問Servlet時可以使用。因此,在這個例子中,param1和 param2初始化參數將能夠在使用URL http://host/webAppPrefix/servlet/InitTest 時可用,但在使用URL http://host/webAppPrefix/servlet/myPackage.InitServlet 時不能使用。
    例如,程序清單5-7給出一個名為InitServlet的簡單servlet,它使用init方法設置firstName和emailAddress字段。程序清單5-8給出分配名稱InitTest給servlet的web.xml文件。
    程序清單5-7 InitServlet.java
    package moreservlets;

    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;

    /** Simple servlet used to illustrate servlet
    * initialization parameters.
    * <P>
    * Taken from More Servlets and JavaServer Pages
    * from Prentice Hall and Sun Microsystems Press,
    * http://www.moreservlets.com/.
    * © 2002 Marty Hall; may be freely used or adapted.
    */

    public class InitServlet extends HttpServlet {
    private String firstName, emailAddress;

    public void init() {
    ServletConfig config = getServletConfig();
    firstName = config.getInitParameter("firstName");
    emailAddress = config.getInitParameter("emailAddress");
    }

    public void doGet(HttpServletRequest request,
    HttpServletResponse response)
    throws ServletException, IOException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    String uri = request.getRequestURI();
    out.println(ServletUtilities.headWithTitle("Init Servlet") +
    "<BODY BGCOLOR=\"#FDF5E6\">\n" +
    "<H2>Init Parameters:</H2>\n" +
    "<UL>\n" +
    "<LI>First name: " + firstName + "\n" +
    "<LI>Email address: " + emailAddress + "\n" +
    "</UL>\n" +
    "</BODY></HTML>");
    }
    }


    程序清單5-8 web.xml(說明初始化參數的摘錄)
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "

    <web-app>
    <!-- ... -->
    <servlet>
    <servlet-name>InitTest</servlet-name>
    <servlet-class>moreservlets.InitServlet</servlet-class>
    <init-param>
    <param-name>firstName</param-name>
    <param-value>Larry</param-value>
    </init-param>
    <init-param>
    <param-name>emailAddress</param-name>
    <param-value>Ellison@Microsoft.com</param-value>
    </init-param>
    </servlet>
    <!-- ... -->
    </web-app>

    5.2 分配JSP初始化參數
    給JSP頁面提供初始化參數在三個方面不同于給servlet提供初始化參數。
    1)使用jsp-file而不是servlet-class。因此,WEB-INF/web.xml文件的servlet元素如下所示:
    <servlet>
    <servlet-name>PageName</servlet-name>
    <jsp-file>/RealPage.jsp</jsp-file>
    <init-param>
    <param-name>...</param-name>
    <param-value>...</param-value>
    </init-param>
    ...
    </servlet>
    2) 幾乎總是分配一個明確的URL模式。對servlet,一般相應地使用以
    http://host/webAppPrefix/servlet/ 開始的缺省URL。只需記住,使用注冊名而不是原名稱即可。這對于JSP頁面在技術上也是合法的。例如,在上面給出的例子中,可用URL http://host/webAppPrefix/servlet/PageName 訪問RealPage.jsp的對初始化參數具有訪問權的版本。但在用于JSP頁面時,許多用戶似乎不喜歡應用常規的servlet的URL。此外,如果 JSP頁面位于服務器為其提供了目錄清單的目錄中(如,一個既沒有index.html也沒有index.jsp文件的目錄),則用戶可能會連接到此 JSP頁面,單擊它,從而意外地激活未初始化的頁面。因此,好的辦法是使用url-pattern(5.3節)將JSP頁面的原URL與注冊的 servlet名相關聯。這樣,客戶機可使用JSP頁面的普通名稱,但仍然激活定制的版本。例如,給定來自項目1的servlet定義,可使用下面的 servlet-mapping定義:
    <servlet-mapping>
    <servlet-name>PageName</servlet-name>
    <url-pattern>/RealPage.jsp</url-pattern>
    </servlet-mapping>
    3)JSP頁使用jspInit而不是init。自動從JSP頁面建立的servlet或許已經使用了inti方法。因此,使用JSP聲明提供一個init方法是不合法的,必須制定jspInit方法。
    為了說明初始化JSP頁面的過程,程序清單5-9給出了一個名為InitPage.jsp的JSP頁面,它包含一個jspInit方法且放置于 deployDemo Web應用層次結構的頂層。一般,http://host/deployDemo/InitPage.jsp 形式的URL將激活此頁面的不具有初始化參數訪問權的版本,從而將對firstName和emailAddress變量顯示null。但是, web.xml文件(程序清單5-10)分配了一個注冊名,然后將該注冊名與URL模式/InitPage.jsp相關聯。

    程序清單5-9 InitPage.jsp
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
    <HEAD><TITLE>JSP Init Test</TITLE></HEAD>
    <BODY BGCOLOR="#FDF5E6">
    <H2>Init Parameters:</H2>
    <UL>
    <LI>First name: <%= firstName %>
    <LI>Email address: <%= emailAddress %>
    </UL>
    </BODY></HTML>
    <%!
    private String firstName, emailAddress;

    public void jspInit() {
    ServletConfig config = getServletConfig();
    firstName = config.getInitParameter("firstName");
    emailAddress = config.getInitParameter("emailAddress");
    }
    %>


    程序清單5-10 web.xml(說明JSP頁面的init參數的摘錄)
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "

    <web-app>
    <!-- ... -->
    <servlet>
    <servlet-name>InitPage</servlet-name>
    <jsp-file>/InitPage.jsp</jsp-file>
    <init-param>
    <param-name>firstName</param-name>
    <param-value>Bill</param-value>
    </init-param>
    <init-param>
    <param-name>emailAddress</param-name>
    <param-value>gates@oracle.com</param-value>
    </init-param>
    </servlet>
    <!-- ... -->
    <servlet-mapping>
    <servlet-name> InitPage</servlet-name>
    <url-pattern>/InitPage.jsp</url-pattern>
    </servlet-mapping>
    <!-- ... -->
    </web-app>


    5.3 提供應用范圍內的初始化參數
    一般,對單個地servlet或JSP頁面分配初始化參數。指定的servlet或JSP頁面利用ServletConfig的getInitParameter方法讀取這些參數。但是,在某些情形下,希望提供可由任意servlet或JSP頁面借助ServletContext的getInitParameter方法讀取的系統范圍內的初始化參數。
    可利用context-param元素聲明這些系統范圍內的初始化值。context-param元素應該包含param-name、param-value以及可選的description子元素,如下所示:
    <context-param>
    <param-name>support-email</param-name>
    <param-value>blackhole@mycompany.com</param-value>
    </context-param>
    可回憶一下,為了保證可移植性,web.xml內的元素必須以正確的次序聲明。但這里應該注意,context-param元素必須出現任意與文檔有關的元素(icon、display-name或description)之后及filter、filter-mapping、listener或 servlet元素之前。
    5.4 在服務器啟動時裝載servlet
    假如servlet或JSP頁面有一個要花很長時間執行的init (servlet)或jspInit(JSP)方法。例如,假如init或jspInit方法從某個數據庫或ResourceBundle查找產量。這種情況下,在第一個客戶機請求時裝載servlet的缺省行為將對第一個客戶機產生較長時間的延遲。因此,可利用servlet的load-on- startup元素規定服務器在第一次啟動時裝載servlet。下面是一個例子。
    <servlet>
    <servlet-name> … </servlet-name>
    <servlet-class> … </servlet-class> <!-- Or jsp-file -->
    <load-on-startup/>
    </servlet>
    可以為此元素體提供一個整數而不是使用一個空的load-on-startup。想法是服務器應該在裝載較大數目的servlet或JSP頁面之前裝載較少數目的servlet或JSP頁面。例如,下面的servlet項(放置在Web應用的WEB-INF目錄下的web.xml文件中的web-app元素內)將指示服務器首先裝載和初始化SearchServlet,然后裝載和初始化由位于Web應用的result目錄中的index.jsp文件產生的 servlet。
    <servlet>
    <servlet-name>Search</servlet-name>
    <servlet-class>myPackage.SearchServlet</servlet-class> <!-- Or jsp-file -->
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
    <servlet-name>Results</servlet-name>
    <servlet-class>/results/index.jsp</servlet-class> <!-- Or jsp-file -->
    <load-on-startup>2</load-on-startup>
    </servlet>

    6 聲明過濾器

    servlet版本2.3引入了過濾器的概念。雖然所有支持servlet API版本2.3的服務器都支持過濾器,但為了使用與過濾器有關的元素,必須在web.xml中使用版本2.3的DTD。
    過濾器可截取和修改進入一個servlet或JSP頁面的請求或從一個servlet或JSP頁面發出的相應。在執行一個servlet或JSP頁面之前,必須執行第一個相關的過濾器的doFilter方法。在該過濾器對其FilterChain對象調用doFilter時,執行鏈中的下一個過濾器。如果沒有其他過濾器,servlet或JSP頁面被執行。過濾器具有對到來的ServletRequest對象的全部訪問權,因此,它們可以查看客戶機名、查找到來的cookie等。為了訪問servlet或JSP頁面的輸出,過濾器可將響應對象包裹在一個替身對象(stand-in object)中,比方說把輸出累加到一個緩沖區。在調用FilterChain對象的doFilter方法之后,過濾器可檢查緩沖區,如有必要,就對它進行修改,然后傳送到客戶機。
    例如,程序清單5-11帝國難以了一個簡單的過濾器,只要訪問相關的servlet或JSP頁面,它就截取請求并在標準輸出上打印一個報告(開發過程中在桌面系統上運行時,大多數服務器都可以使用這個過濾器)。

    程序清單5-11 ReportFilter.java
    package moreservlets;

    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.util.*;

    /** Simple filter that prints a report on the standard output
    * whenever the associated servlet or JSP page is accessed.
    * <P>
    * Taken from More Servlets and JavaServer Pages
    * from Prentice Hall and Sun Microsystems Press,
    *
    http://www.moreservlets.com/.
    * © 2002 Marty Hall; may be freely used or adapted.
    */

    public class ReportFilter implements Filter {
    public void doFilter(ServletRequest request,
    ServletResponse response,
    FilterChain chain)
    throws ServletException, IOException {
    HttpServletRequest req = (HttpServletRequest)request;
    System.out.println(req.getRemoteHost() +
    " tried to access " +
    req.getRequestURL() +
    " on " + new Date() + ".");
    chain.doFilter(request,response);
    }

    public void init(FilterConfig config)
    throws ServletException {
    }

    public void destroy() {}
    }

    一旦建立了一個過濾器,可以在web.xml中利用filter元素以及filter-name(任意名稱)、file-class(完全限定的類名)和(可選的)init-params子元素聲明它。請注意,元素在web.xml的web-app元素中出現的次序不是任意的;允許服務器(但不是必需的)強制所需的次序,并且實際中有些服務器也是這樣做的。但這里要注意,所有filter元素必須出現在任意filter-mapping元素之前, filter-mapping元素又必須出現在所有servlet或servlet-mapping元素之前。
    例如,給定上述的ReportFilter類,可在web.xml中作出下面的filter聲明。它把名稱Reporter與實際的類ReportFilter(位于moreservlets程序包中)相關聯。
    <filter>
    <filter-name>Reporter</filter-name>
    <filter-class>moresevlets.ReportFilter</filter-class>
    </filter>
    一旦命名了一個過濾器,可利用filter-mapping元素把它與一個或多個servlet或JSP頁面相關聯。關于此項工作有兩種選擇。
    首先,可使用filter-name和servlet-name子元素把此過濾器與一個特定的servlet名(此servlet名必須稍后在相同的 web.xml文件中使用servlet元素聲明)關聯。例如,下面的程序片斷指示系統只要利用一個定制的URL訪問名為SomeServletName 的servlet或JSP頁面,就運行名為Reporter的過濾器。
    <filter-mapping>
    <filter-name>Reporter</filter-name>
    <servlet-name>SomeServletName</servlet-name>
    </filter-mapping>
    其次,可利用filter-name和url-pattern子元素將過濾器與一組servlet、JSP頁面或靜態內容相關聯。例如,相面的程序片段指示系統只要訪問Web應用中的任意URL,就運行名為Reporter的過濾器。
    <filter-mapping>
    <filter-name>Reporter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    例如,程序清單5-12給出了將ReportFilter過濾器與名為PageName的servlet相關聯的web.xml文件的一部分。名字 PageName依次又與一個名為TestPage.jsp的JSP頁面以及以模式http: //host/webAppPrefix/UrlTest2/ 開頭的URL相關聯。TestPage.jsp的源代碼已經JSP頁面命名的談論在前面的3節"分配名稱和定制的URL"中給出。事實上,程序清單5- 12中的servlet和servlet-name項從該節原封不動地拿過來的。給定這些web.xml項,可看到下面的標準輸出形式的調試報告(換行是為了容易閱讀)。
    audit.irs.gov tried to access
    http://mycompany.com/deployDemo/UrlTest2/business/tax-plan.html
    on Tue Dec 25 13:12:29 EDT 2001.

    程序清單5-12 Web.xml(說明filter用法的摘錄)
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "

    <web-app>
    <filter>
    <filter-name>Reporter</filter-name>
    <filter-class>moresevlets.ReportFilter</filter-class>
    </filter>
    <!-- ... -->
    <filter-mapping>
    <filter-name>Reporter</filter-name>
    <servlet-name>PageName</servlet-name>
    </filter-mapping>
    <!-- ... -->
    <servlet>
    <servlet-name>PageName</servlet-name>
    <jsp-file>/RealPage.jsp</jsp-file>
    </servlet>
    <!-- ... -->
    <servlet-mapping>
    <servlet-name> PageName </servlet-name>
    <url-pattern>/UrlTest2/*</url-pattern>
    </servlet-mapping>
    <!-- ... -->
    </web-app>


    僅列出標題
    共8頁: 上一頁 1 2 3 4 5 6 7 8 下一頁 
    主站蜘蛛池模板: a视频在线观看免费| 亚洲乱色伦图片区小说| 亚洲AV成人片色在线观看高潮| 国产亚洲精品线观看动态图| 亚洲免费一区二区| 久久国产成人亚洲精品影院| 国产成人精品日本亚洲专区| 久久久久亚洲AV成人网人人软件| 亚洲综合图色40p| 亚洲国产精品va在线播放| 亚洲AV无码乱码国产麻豆| 亚洲成在人天堂一区二区| 亚洲日韩中文字幕| 亚洲AV无码乱码在线观看代蜜桃| 精品亚洲成在人线AV无码| 2020国产精品亚洲综合网| 亚洲av无码片区一区二区三区| 国产成人亚洲精品| 久久精品国产亚洲AV| 免费国产在线精品一区 | 亚洲国产成人a精品不卡在线| 亚洲AⅤ永久无码精品AA| 亚洲国产精品日韩| 亚洲免费人成在线视频观看| 亚洲成av人影院| 亚洲国产成a人v在线| 特黄特色的大片观看免费视频| www.xxxx.com日本免费| 日韩免费电影网站| 成年网站免费视频A在线双飞| 国产男女猛烈无遮挡免费视频| 亚洲福利精品电影在线观看| 亚洲av无码成人黄网站在线观看| 亚洲视频日韩视频| 亚洲AV无码一区二区一二区 | 久久精品国产精品亚洲艾| 亚洲天堂中文字幕在线观看| 亚洲欧洲国产综合AV无码久久 | 91嫩草亚洲精品| 亚洲精品伦理熟女国产一区二区 | 亚洲乱码中文论理电影|