2013年4月26日 星期五

SCWCD重點整理-9.JSTL(Jsp Standard Tag Library)

JSP的taglib指令的uri對映到tld的方式可區分為顯性與隱性。所謂的顯性(JSP2.0以前)就是指在DD中會去設定uri對映到tld檔的方式,如下:
     <taglib>
        <taglib-uri>ooxx</taglib-uri>
        <taglib-location>/tld/c.tld</taglib-location>
     </taglib>    
所以根據web.xml的taglib設定,若在Jsp中要使用此自訂標籤,會這樣打
<%@taglib prefix="c" uri="ooxx" %>
而隱性(JSP2.0)則是不在DD中設定,container會自動建立tld檔與uri的對映關係,但前提是tld檔必須放到特定的目錄下
1. /WEB-INF/下
2. /WEB-INF/子目錄
3.JAR檔( 在WEB-INF/lib目錄下)的META-INF下
4.JAR檔( 在WEB-INF/lib目錄下)的META-INF子目錄下


網站的輸出盡量使用<c:out>標籤輸出,如<c:out value='${userName}' default='guest' />
可防止 跨網站指令稿攻擊(XSS、cross-site scripting或 cross-site hacking),這是因為使用<c:out>標籤輸出時,預設escapeXml是開啟的狀態,會將html的特殊自元轉換成等效的html實體,如<轉成&lt , >轉成 &gt,因此可以防止<script></script>被瀏覽器解譯成javascript的標籤,從而防止了XSS的攻擊。
ps: 跨網站指令稿攻擊是攻擊者以特定的第三方網站當作攻擊媒介,將惡意的javascript輸入到最常使用的comment欄位,儲存入網站的資料庫後,讓下一位閱讀者在瀏覽該網站時,同時也去下載到攻擊者的惡意javascript並執行,來達到惡意攻擊效果。


<c:forEach>標籤如同for 迴圈,可以針對群集裡的每一個元素執行一次標籤的主體
群集: 廣義解釋為 陣列、collection、Map或者以逗號分隔的字串。
        <% 
           List colorList=new ArrayList();
           colorList.add("Blue");
           colorList.add("Black");
           colorList.add("Red");
           request.setAttribute("optionList", colorList);
        %>
        <select>
          <c:forEach varStatus="counter" var="option" items="${optionList}" >
                  <option value="${counter.count}" >${option}</option>
              </c:forEach>
        </select>
varStatus是一個指向 javax.servlet.jsp.jstl.core.LoopTagStatus的實例,可利用LoopTagStatus.count來當計數器,就如同for迴圈的 i 一般。


<c:if>標籤用來提供如if 判斷式的功能,用法如下
<c:if test="${ isLogin ==true }" > 已登入 </c:if>,若isLogin等於ture,則顯示 已登入


<c:choose>標籤與<c:when>、<c:otherwise>標籤合用,可達到如 if...else if...else if....else 的效果
       <c:choose>
                   <c:when test="${choice eq 'A'}" >Your Choice is A</c:when>
                   <c:when test="${choice eq 'B'}" >Your Choice is B</c:when>
                   <c:when test="${choice eq 'C'}" >Your Choice is C</c:when>
                   <c:otherwise >Your Choice is D</c:otherwise>
       </c:choose>


<c:set >標籤 可以用來設定Map的值、增加Map的項目或是增加某個作用域的屬性。它有兩種版本,var 與 target 。

var 是用來設定屬性值,設定屬性值時可將設定值放在value中,或是直接放到 <c:set > </c:set>的主體之中

        在value中設定值
        <c:set var="userName" scope="session"  value="John" />
       
        在session中設定屬性userName等於"John" 
        
        放到主體中設定
        <c:set var="welcomeString" scope="session"  >
              how are you ${sessionScope.userName}
        </c:set>
        在session中設定屬性userName等於"how are you " + 上列設的名稱 "John"

        <c:out value="${sessionScope.welcomeString}" />
        顯示結果 = how are you John 

        <c:set var="userName" scope="session"  value="${noValue}" />
        若 noValue這各EL被評算成null,則 userName這各屬性若存在於session,userName將會從
        session移除,若沒有指定scope,則會從page scope開始找起,若能在任一scope找到
        userName這各屬性,則將其從該scope移除!

target 是用來設定Map的key/value或是bean的特性/value,同樣的在設定值時,標籤也會分成沒有主體的設定方式跟有主體的設定方式


       <!-- c:set 設定Map/Bean範例 沒有主體 
         target屬性值必須是一個真的被評算成物件實體的EL
         不能只是代表"id"的字串實字
         -->
         <c:set target="${employee}" property="name" value="Justin" />
         設定employee的名稱=<c:out value="${employee.name}" />
         
         <br />
         <!-- c:set 設定Map/Bean範例 有主體 -->
         <c:set target="${employee}" property="name" >
              ${settingName}
         </c:set>
若employee是一個Map,那麼property就代表它的key,value就是要設定給key的值。若employee是一個Bean,則property就是Bean的特性,value就是要設定給特性的值。
如範例程式的註解,target不能是一個字串實字,它可以是代表真實物件的 EL表達式${...}或是Scripting<%=... %>,又或者是 <jsp:attribute>。
若target評算出來不是Map或Bean,則Container會丟出例外。
若評算出來target是bean,但此bean找不到與property指定相符的特性,則Container也會丟出例外。

<c:remove>標籤可以移除特定作用域的某個屬性,使用方式如下:
    <c:remove var="employee"  scope="request" />
其中 var必須是字串實字,不能是EL表達式;scope若不指定,則employee屬性會從所有作用域被移除,若不是真要從所有作用域將這各屬性移除,還是養成較好的習慣,指定 要移除的scope。


在JSP中,有三種嵌入內容的方式:

1.include 指令 : <%@ include file="xxx.jsp | xxx.html" %>  ,是一種靜態的嵌入方式 ,在轉譯
(即tmp.jsp->_tmpServlet.java)期間將 file屬性指定的內容增加到當前頁面。

2.<jsp:include>標準動作:<jsp:include page="xxx.jsp",是一種動態的嵌入方式,在請求期間將page屬性指定的內容增加到當前頁面。可與 <jsp:param name="pageTitle" value="welcome Justin" /> 合用

3.<c:import>JSTL標籤: <c:import url="http://www.example.com/header.jsp" />,是動態的,在請求期間將url屬性指定的內容增加到當前的頁面,用法與<jsp:include>很像,但<c:import>能嵌入Container以外的外部內容,所以更具彈性。
可與<c:param name="pageTitle" value="welcome Justin"  /> 合用。


<c:url>標籤可以讓JSP中的超連結 有URL重寫的能力,若再配合<c:param>標籤的使用,可以讓URL的參數一併被編碼,讓一些不安全的字元或被保留字元替換成其他字元。
        <c:set var="name" scope="request" value="Justin Yang"  />
        <c:url value="/welcomePage.jsp" var="welcomeHref"  >
            <c:param name="wholeName" value="${name}" />
        </c:url>
        產生的超連結:${welcomeHref}
 ${welcomeHref}實際產生出來的連結會像
/contextName/welcomePage.jsp?wholeName=Justin+Yang ,其中Justin Yang中間的空白會被自動編碼為'+',以讓超連結是一串正確的連結。



JSTL規格書下載

2013年4月25日 星期四

SCWCD重點整理-8.不含Script的JSP

8.不含Script的Jsp
  1. Jsp的生命週期: 到第五項僅會執行一次,之後每次接收到request會直接執行_jspService()
    1. Jsp轉譯(translate)成Servlet,此時為java檔
    2. 將.java編譯為.class
    3. 載入此servlet的class
    4. 產生此class的instance
    5. 呼叫jspInit():
    6. 呼叫_jspService()
    7. 呼叫jspDestory()
  2. Jsp語法元素
    元素




  3. Jsp的隱含物件
         API                             隱含物件
  4.     JspWriter                      out
        HttpServletRequest       request
        HttpServletResponse    response
        HttpSession                  session
        ServletContext              application
        ServletConfig                config
        Throwable                    exception
        PageContext                 pageContext
        Object                          page

9.EL (Expression Language)
  1. EL的隱含變數
    作用隱含變數使用範例
    對應於各作用域屬性的MappageScope ${pageScope.參數名稱}
    requestScope${requestScope.參數名稱}
    sessionScope${sessionScope.參數名稱}
    applicationScope${applicationScope.參數名稱}
    對應於請求參數的Mapparam${param.參數名稱}
    paramValues${paramValues.參數名稱[N]}, N由0開始
    對應於請求標頭的Mapheader${header["User-Agent"]} ,不能寫成 ${header.User-Agent}, 因"-"在EL為特殊自元
    headerValues${headerValues[參數名稱][0]}
    含cookie的Mapcookiecookie.參數名稱
    對應於Context初始參數的Map(not Servet的初始)initParam${initParam.參數名稱}(在web.xml中的context-param
    在EL中唯一非Map的隱含物件,指向pageContext的實際參考pageContext${pageContext.request.method}:取得發出的請求是用get還是post
  2. EL自定方法:利用EL呼叫java方法並傳回結果
    1. 在一個類別中,寫一個內涵公用且靜態方法的method,public and static,假設方法為 public static roll() {  }
    2. 撰寫TLD(Tag Library Descriptor) :須放置在WEB-INF底下或其子目錄下
      http://com.element.el 
      
          random
          com.element.el.DiceRoller
           
             java.lang.String roll()
          
      
      
    3. 在jsp中加上taglib ,ex: <%@ taglib prefix="test"  uri="http://com.element.el" %>,與tld的uri必須相同
    4. 在jsp即可透過 ${test : random()} 呼叫EL函式

10.在JSP中使用標準動作標籤

利用 標準動作(standard action)將Scripting程式碼取代掉
使用Scripting...
    <html><body>
       <% example.Employee emp= (example.Employee) request.getAttribute("employee");
        Person is: <%=emp.getName() %>
       </body></html>
利用usebean與 getproperty拿掉
      
    <html><body>
   
          Person is:
   
   </body></html>

當 <jsp:userBean>無法在指定的作用域找到名為employee的屬性時,自行建立一個新的bean,並且執行<jsp:useBean>主體內的動作,將值設定給employee的name
      
    <html><body>
   
          
   
   </body></html>

若想利用多型的方式使用bean,像是宣告的參考型別為Person,而實際產生的物件為employee時,達到像右邊程式的宣告效果  Person emp=new Employee() ,就必須使用type
      
    <html><body>
         
    </body></html>
type就是可以放抽像類別、介面等可當成參考型別;而class正是實體化時必須使用的真正物件型別

若在useBean只有 使用type,而沒有使用class,則useBean的主體永遠不會執行,因為只有當新建一個bean時,才會去執行useBean的主體
      
    <html><body>
   
          
   
   </body></html>

透過param,可將 request送出的請求參數值設定給指定的bean特性,此例是將 html form中欄位名稱為userName的值assingn給 employee的 name特性
      
    <html><body>
   
           
   
   </body></html>

若能遵守 html表單的欄位 name皆與 bean的name相同,則無須指定param與property的對映,<jsp:setProperty>會自動找出與bean特性相符的請求參數並將它們的值設定給名稱相符的bean特性
    <html><body>
   
           
   
   </body></html>

2013年4月23日 星期二

SCWCD重點整理-10.開發自訂標籤

1.自訂標籤延伸API部署於 javax.servlet.jsp.tagext套件中,其API類別圖如下:
自訂標籤API類別關係圖
自訂標籤API類別關係圖


  • Tag File :
    • 副檔名為tag、tagx
    • 合法的body-content元素:empty | scriptless | tagdependent
    • 只有Tag File才有的指令:tag 、attribute:、variable
    • Containe會去哪裡找Tag File?
      • /WEB-INF/tags目錄下
      • /WEB-INF/tags的子目錄下
      • /在WEB-INF/lib/下的JAR檔中的META-INF/tags目錄下
      • /在WEB-INF/lib/下的JAR檔中的META-INF/tags子目錄下
      • 若Tag file被部屬在jar檔中,JAR檔中的META-INF/TLDS必須有tld檔
      • 詳細的實作設定可參考良葛格學習筆記-TLD檔案
  • SimpleTagSupport:
    • 實做SimpleTag
    • 在doTag()中,利用getJspContext()取得 JspContext後,可使用setAttribute,將value寫入 pageScope中.
    • getJspBody.invoke(null),設定為null,表示資訊預設寫入getJspContext().getOut所取得的JspWriter中,整各指令作用為呼叫標籤主體。
    • body-content不能為Jsp,即標籤的body不能使用Scripting.(包含<% %>,<%= %>,    <%! %>等
  • Classic Tag:
    • Tag Support :
      • 繼承此類別的標籤處理器,不具有修改bodyContent的能力
      • 從IterationTag得到的doAfterBody()方法讓標籤處理器能重複繞行標籤主體
      • doStartTag()、doAfterBody預設傳回SKIP_BODY(不評算主體)
      • doStartTag()回傳EVAL_BODY_INCLUDE,表示評算主體
      • doEndTag()回傳EVAL_PAGE,評算標籤結束後的剩餘頁面
    • BodyTagSupport:
      • 繼承此類別可直接存取主體內容並且以某種方式修改
      • 當doStartTag()回傳EVAL_BODY_BUFFERED時,會先執行:
        • setBodyContent(BodyContent)
        • doInitBody()
        • 再繼續評算標籤主體
      • doStartTag()預設傳回EVAL_BODY_BUFFERED
    • Classic Tag透過Tag.getParent()回傳Tag,故僅能有Classic Tag的父標籤
      • 若想讓內層的Classic Tag取得外層為SimpleTag的取法:
         TagAdapter tagAdapter=(TagAdapter)this.getParent();
         out.println(tagAdapter.getAdaptee());
        
        此處是利用 TagAdapter將外層為JspTag介面的SimpleTag包裝起來後,再由tagAdapter.getAdaptee()取出真正的SimpleTag
    • 而SimpleTag透過SimpleTag.getParent()回傳的是JspTag,故其父標籤可以是Classic Tag或是SimpleTag

2013年4月18日 星期四

SCWCD重點整理-11.Web應用程式的部署

  1. WAR檔:
    • 將整各應用程式結構壓縮起來,不包含web應用程式的context目錄-WEB-INF的上一層
    • 其實就是jar,只是將附檔名改成war
    • 是應用程式的快照(snapshot),有良好的可攜性的壓縮格式
    • 在WAR檔中的 META-INF/MANIFEST.MF可以宣告程式庫相依性,在部署期間即可檢查應用程式所依賴的套件與類別是否存在。
  2. Servlet與URL對映的運作:
    • http://domainName:port/context/test.do這樣的請求進來時,若透過如下的 Servlet與url對映,則會由 com.example.TestServlet負責處理這各請求
         
      
            
                 MyServlet 
                 com.example.TestServlet
            
            
                 MyServlet 
                /test.do
            
  3. <url-pattern>的三種型態(優先順序高低由A~C)
    1. 完全相符,必須以斜線開頭 ex: <url-parrern> /Beer/SelectBeer.do</url-pattern>
    2. 目錄相符,必須以斜線開頭,總是以斜線星號結尾
      ex:<url-parrern> /Beer/*</url-pattern>
    3. 副檔名相符,必須以星號開頭,且星號後面必須有點號加副檔名
      ex:<url-parrern>*.do</url-pattern>
  4. 當有一個以上的狀況符合時,以越明確的符合狀況優先,即request的url與url-pattern符合的長度越長,代表越明確。
  5. DD中組態歡迎檔
    • 檔案不能以斜線開頭或結束<welcome-file>index.html</welcome>
  6. DD中組態錯誤頁面
    • 宣告一網打盡錯誤頁面
            
                 java.lang.Throwable
                 /errorPage.jsp
            
      
    • 針對Http代碼,宣告特定錯誤頁面
            
                 404
                 /notFoundError.jsp
            
  7.  response.sendError(int):要求Container送出錯誤代碼