JavaEE(二)JSP

JSP(java server page)

  JSP是一種語法規範,在html模板中嵌入jsp語法,其實現處理的方式是把jsp文件轉換爲servlet類
  當請求到達時,服務器若判別爲jsp請求就會轉交給jsp引擎處理,它會找到jsp文件並根據語法解析爲servlet類文件,然後編譯並加載該servlet(實際上jsp引擎會檢查相應servlet是否已加載且加載時間是否在jsp最後更改時間之後,只有該條件不成立纔會重新生成servlet並重新編譯加載,這樣減少生成編譯和加載servlet的過程以提高訪問效率)。可見jsp語法其實就是怎麼將jsp文件轉換爲servlet的語法(jsp轉換爲servlet只是實現jsp規範的一種可行方案)

JSP的生命週期

  JSP文件生成的servlet都實現了HttpJspPage接口(Servlet的子接口),對於tomcat而言,jsp頁面生成的servlet都繼承自HttpJspPage的實現類HttpJspBase。其生命週期爲:根據jsp文件生成並加載servlet->jspInit->_jspService->jspDestroy,當jsp文件發生更改重新生成並加載servlet時會先銷燬系統中原來的servlet,也就是會調用老的servlet的jspDestroy方法並調用新的servlet的jspInit方法

JSP語法

  空jsp文件生成的servlet主要只有一個_jspService方法,該方法分爲兩段,第一段把幾個有用的對象(隱式對象)列了出來,因此後面的第二段可以使用這些對象;第二段爲jsp文件的某些部分生成。解析jsp文件的時候就是把jsp的各個部分按順序插入servlet源文件的相應地方以及對插入的控制。隱式對象有9個,常用的有request(HttpServletRequst)、response(HttpServletResponse)、out(JspWriter類型表示響應的輸出流)、session(HttpSession)、application(ServletContext)、config(ServletConfig)、page(就是this關鍵字)、pageContext(PageContext類的實例,提供對JSP頁面所有對象以及命名空間的訪問)、exception(當某個頁面爲異常處理頁面時,該值爲異常發生頁面拋出的異常)

  • 模板部分(除去以下部分的其他部分),該部分的內容會封裝爲out.write(“模板部分”)插入_jspService的第二部分。
  • 註釋部分(<%-- 註釋部分 --%>),註釋部分的內容直接被忽略,不會寫入servlet,但<!-- html註釋 -->會寫入servlet,只是在客戶端不會解析顯示而已。
  • 表達式部分(<%= 表達式部分 %>),該部分的內容會封裝爲out.print(表達式部分)直接插入_jspService的第二部分。
  • 腳本部分(<% 腳本部分 %>),該部分的內容會直接插入_jspService的第二部分。
  • 聲明部分(<%! 聲明部分 %>),該部分的內容可以聲明或定義一個或多個變量、方法,會被直接寫入servlet類中與_jspService平行部分,也就是servlet的成員變量和成員函數。
  • 指令部分(<%@ directive attribute=“value” %>),用來設置整個JSP頁面相關的屬性,如網頁的編碼方式和腳本語言。其中directive可以有三個取值page、include或taglib。
  • 標籤部分 (<prefix:tag attribute=“attr”> 標籤內容 </prefix:tag>),在_jspService的第二部分新建一個Tag對象並依次調用其生命週期方法。
  • 動作部分 (<jsp:action_name attribute=“value” />),JSP動作元素在請求處理階段起作用。

JSP指令

  JSP指令用來設置整個JSP頁面相關的屬性,如網頁的編碼方式和腳本語言,格式爲<%@ directive attribute=“value” %>,其中directive可以有三個取值page、include或taglib。
  當指令部分的directive爲taglib時,表示引入標籤庫,格式爲<%@ taglib uri=“在web.xml裏面標籤庫配置的uri” prefix=“當引用該標籤庫時使用的前綴” %>。
  當directive爲include時,表示將另一個文件的內容全部放在此處,在轉換爲servlet時引入文件內容就成了整個文件的一部分並按照jsp規則解析,格式爲<%@ include file=“文件相對url地址” %>。
  當directive爲page時,attribute有很多取值來表示不同的指令

  • import:導入要使用的Java類,多個用逗號分隔或者從新使用個該標籤,如<%@ page import=“java.util.*, java.lang.*” %>
  • contentType:指定當前JSP頁面的MIME類型和字符編碼,如<%@ page language=“java” contentType=“text/html;charset=GBK” %>
  • pageEncoding:指定當前JSP頁面的字符編碼,如果指定了pageEncoding,就以它爲主,如果不存在,再找contentType的charset,如<%@ page language=“java” contentType=“text/html” pageEncoding=“GBK” %>
  • isELIgnored:是否啓用el表達式,默認false,即爲啓用,如<%@ page isELIgnored=“true”%>
  • errorPage:指定當JSP頁面發生異常時需要轉向的錯誤處理頁面,如<%@ page errorPage=“error.jsp”%>
  • isErrorPage:指定當前頁面是否可以作爲另一個JSP頁面的錯誤處理頁面,<%@ page isErrorPage=“true”%>
  • language:指定腳本語言,默認爲java,因爲我們現在只使用java,所以該值不管。

JSP動作

  JSP動作的格式爲<jsp:action_name attribute=“value” />,常用的action_name如下:

  • include:在_jspService插入一條類似於RequestDispatcher的include語句,格式爲<jsp:include page=“相對URL地址” flush=“true” />
  • forward:在_jspService插入一條類似於RequestDispatcher的forward語句,格式爲<jsp:forward page=“相對URL地址” />
  • userBean:在_jspService中聲明一個變量,並從作用域中獲取相應的對象賦值給變量,如果在作用於中不存在相應的對象就新建對象並放入相應的作用域,格式爲<jsp:userBean id=“變量名” scope=“page(默認)/request/session/application” class=“具有無參構造函數的帶包類”/>或<jsp:userBean id=“變量名” scope="" class="">這部分jsp內容會在userBean新建的時候執行,如用jsp:setProperty/來進行新建對象的初始化</jsp:userBean>
  • setProperty:設置bean的屬性,調用屬性的set方法,會依次從page、request、session、和application作用域尋找bean,格式爲<jsp:setProperty name=“變量名”, property=“屬性名” value=“屬性值”/>
  • getProperty:out.write(bean的屬性),調用bean屬性的get方法,會依次從page、request、session、和application作用域尋找bean,格式爲<jsp:getProperty name=“變量名” property=“屬性名” />

JSP表達式

  EL表達式中可以有對象、常量、標籤庫中註冊的函數以及運算符。當JSP解析器見到JSP{}格式後,JSP解析器會產生代碼來計算這個表達式,並用表達式的值來代替表達式的位置,如{fn:contains(object.attr, sub)}。
  EL支持的運算符有

  • 基本運算:+、-、*、/(div)、%(mod) 加、減、乘、除(除就是除,不是取整)、取模,只適合數字或者由數字組成的字符串
  • 邏輯運算:==(eq)、!=(ne)、<(lt)、>(gt)、<=(le)、>=(ge)、&&(and)、||(or)、!(not)
  • . 、[] 訪問一個Bean屬性或者一個映射條目,如bean.attr、bean[“attr”]、map.key、map.[“key”],若映射條目有特殊字符只能用[],數組或者鏈表只能用[],如list[1].attr
  • ( ) 組織一個子表達式以改變優先級
  • ? : 條件運算的三目運算符
  • empty 測試是否空值,當爲null、空字符串或空集合時返回true

  EL支持的隱藏對象有:pageScope、requestScope、sessionScope、applicationScope、param、paramValues、header、headerValues、initParam、cookie、pageContext。當對象引用不是以隱藏對象開頭的,那麼會依次從四大作用域中去找相應的對象

JSP標籤與函數

  標籤能過通過pageContext獲取很多對象,所以常用來進行過程處理,而函數只能拿到輸入參數並得到處理後的返回值
  函數的定義很簡單,其所在的類不需要實現和繼承任何類,但要求函數必須是public static修飾的公有靜態函數,函數的調用見EL表達式
  JSP標籤對應着一個實現了JspTag的標籤處理類,在JSP引擎解析到JSP標籤時,會在_jspService的第二部分創建標籤對應的處理類,並依次執行其生命週期方法。定義JSP標籤的過程分爲兩步,首先要實現標籤處理類,其實現方式有兩種,分別爲傳統方式和簡單方式,然後需要將處理類進行註冊,註冊到標籤庫文件中。使用標籤時需要先在web.xml中用標籤下的標籤引入標籤庫,然後需要在需要使用標籤的jsp頁面用<%@ taglib/>指令引入標籤庫。
  JSP標籤庫在一個xml格式的tld後綴文件中進行標籤與函數的註冊,其格式如下:

<?xml version="1.0" encoding="utf-8"?>

<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
        version="2.0">

    <!-- 標籤庫對應的名字,不常用 -->
    <display-name>name</display-name>
    <!-- 標籤庫的描述,不常用 -->
    <description>description</description>
    <!-- 指定標籤庫版本 -->
    <tlib-version>1.0</tlib-version>
    <!-- 在jsp中建議使用的前綴,只是建議 -->
    <short-name>myshortname</short-name>
    <!-- 指定引用該標籤的uri地址,如果標籤庫指定了該值,那麼在jsp頁面可以直接用該值引入標籤庫,而無需在web.xml中引入該標籤庫,當然也可以在web.xml中引入該標籤庫並指定一個新的uri,在jsp頁面依然可以通過新的uri引入標籤庫 -->
    <uri>http://mycompany.com</uri>

    <!-- 各個標籤的註冊,可以有多個 -->
    <tag>
        <!-- tag對應的名字,不常用 -->
        <display-name>name</display-name>
        <!-- tag的描述,不常用 -->
        <description>description</description>
        <!-- 標籤的名字,供調用 -->
        <name>tagName<name>
        <!-- 標籤處理類 -->
        <tag-class>com.ejie.MyTag</tag-class>
        <!-- 對標籤體的定義,當爲empty時,其內容就算不爲空也會被當做空,當爲JSP時會當中JSP解析出結果,當爲scriptless時,可以爲EL表達式和JSP動作元素不能爲JSP腳本如<% %>與<%= %>等,當爲tagdependent時,不會對內容做任何解析 -->
        <body-content>empty/JSP(簡單標籤不支持該值)/tagdependent/scriptless</body-content>
        <!-- 未聲明的屬性是否允許使用,默認false,不可以與attribute共存 -->
        <dynamic-attributes>true/false</dynamic-attributes>
        <!-- 定義標籤可以有的屬性,可以有多個 -->
        <attribute>
            <!-- 屬性名 -->
            <name>att</name>
            <!-- s屬性的描述,不常用 -->
            <description>description</description>
            <!-- 是否必須賦值的屬性,默認false -->
            <required>true/false</required>
            <!-- 屬性是否支持運行時表達式,如JSP表達式(<%=value%>)和EL表達式(${value}) -->
            <rtexprvalue>true/false</rtexprvalue>
            <!-- 參數類型 -->
            <type>java.lang.String</type>
        </<attribute>
    </tag>
    
    <function>
        <!-- 函數對應的名字,不常用 -->
        <display-name>name</display-name>
        <!-- 函數的描述,不常用 -->
        <description>description</description>
        <!-- 函數對應的名字,供調用 -->
        <name>funName</name>
        <!-- 函數的定義所在類 -->
        <function-class>org.apache.taglibs.standard.functions.Functions</function-class>
        <!-- 函數的簽名 -->
        <function-signature>java.lang.String substringBefore(java.lang.String, java.lang.String)</function-signature>
    </function>

</taglib>

  JSP標籤處理器的傳統定義方式都是實現了JspTag的子接口Tag,他的生命週期方法依次爲 setPageContext(PageContext pageContext)->setParent(Tag tag)->doStartTag()->doEndTag()->release()。release方法用於釋放資源,在容器關閉時纔會調用。PageContext對象可以用來獲取幾大隱藏對象。當讀到標籤時調用doStartTag方法,返回值爲SKIP_BODY(不會將標籤的內容寫入response的輸出流)與EVAL_BODY_INCLUDE(將標籤內容寫入response的輸出流),當讀到結束標籤時調用doEndTag方法,其返回值可以取EVAL_PAGE(繼續處理標籤後面的頁面)與SKIP_PAGE(該標籤後面的jsp頁面不再處理),一般繼承有Tag默認實現方法的基類BodyTagSupport
  JSP標籤處理器的簡單定義方式都是實現了JspTag的子接口SimpleTag,它是jsp2.0之後引入的,除了部分老的框架在使用傳統定義方式外,都建議使用簡單定義方式。其生命週期方法依次爲setJspContext(JspContext jspContext)->setJspBody(JspFragment jspFragment)->setParent(JspTag jspTag)->doTag()。爲了定義簡單標籤的方便,一般繼承有SimpleTag默認實現方法的基類SimpleTagSupport,幾個set方法都用javabean的方式設置了成員變量並提供了get方法,doTag方法默認爲空,一般繼承自SimpleTagSupport的標籤處理器只需要實現doTag方法,負責解析標籤就可以了。只有該標籤在另一個自定義標籤裏面的時候纔會有父標籤,否則父標籤爲null。
  在標籤處理類中定義與屬性名相同的成員變量,並定義其set方法,在doTag中就可以使用這些成員變量來獲取標籤的屬性值。獲取標籤內容的方式爲JspFragment(通過getJspBody獲取)的invoke(Writer writer)方法,當writer傳null的時候,默認爲寫入response的輸出流,如果希望自己處理,可以定義一個StringWriter獲取標籤內容,通過其toString方法獲取標籤內容。如果希望該標籤之後的jsp頁面不再處理,只需要拋出SkipPageException異常

JSTL

  JSP標準標籤庫(JSTL:Java Standard Tag Library)是一個JSP標籤集合,它封裝了JSP應用的通用核心功能,使用時需要引入相應的standard包和jstl包。主要的標籤庫有核心標籤庫、格式化標籤、SQL標籤與XML標籤以及JSTL函數。
  標準庫裏最常用的就是核心包,引用方式<%@ taglib prefix=“c” uri=“http://java.sun.com/jsp/jstl/core” %>,其標籤如下:

  • if,條件判斷,如同代碼中的if,格式爲<c:if test=“條件判斷” var=“保存判斷的結果” scope=“結果保留的作用域”>…</c:if>示例如下:
<c:if test="${booleanA}" var="result" scope="page">
    <p>booleanA = true<p>
</c:if>
<c:if test="${result}">
    <p>booleanA = false<p>
</c:if>
  • choose、when與otherwise,當某個when成立的時候,後面的when和otherwise都無用了,如同代碼中的swatch、case與default。
<c:choose>
    <c:when test="${booleanA}">
        <p>A</p>
    </c:when>
    <c:when test="${booleanB}">
        <p>B</p>
    </c:when>
    <c:otherwise>
        <p>都不是</p>
    </c:otherwise>
</c:choose>
  • forEach,循環,格式爲<c:forEach items=“被遍歷的集合對象,默認爲一個由begin-end的連續整數集合” begin=“遍歷的起始位置,默認爲0” end=“遍歷的結束位置,默認爲最後一個元素下標” step=“遍歷的步長,默認1” var=“保存遍歷出來的當前對象” varStatus=“可以通過該對象獲取如當前的索引index、第幾次進入循環count”>…</c:foreach>。
<c:forEach items="list" var="item" begin="6" end="15" step="2" varStatus="status">
    <p>${item}</p>
    <p>${status.count}</p>
    <p>${status.index}</p>
</c:forEach>
  • forTokens,循環,與forEach相似,只是items爲用符號分割的元素,因此比forEach多一個屬性delims來指定分割符號。
<c:forEach items="item1,item2,item3" var="item" begin="6" end="15" step="2" varStatus="status" delims=",">
    <p>${item}</p>
    <p>${status.count}</p>
    <p>${status.index}</p>
    </c:forEach>
</c:forEach>
  • redirect,重定向,如<c:redirect url=“url”/>
  • out,在jsp中顯示數據,如<c:out value=“輸出” default=“當value通過EL表達式取值爲null時的默認值,該屬性的默認值爲該標籤的內容” escapeXml=“true/false”/>
  • set,設置變量值或某個變量的屬性值,格式爲<c:set var=“變量名” value=“變量值” scope=""/>或<c:set target=“對象名” property=“屬性名” value=“變量值值” scope=""/>
  • catch,異常捕獲<c:catch var =“catchException”>可能發生異常的部分</c:catch>,當異常發生時異常被捕獲catchException

  標準庫裏還常用的就是函數,引用方式<%@ taglib prefix=“fn” uri=“http://java.sun.com/jsp/jstl/functions”%>,其標籤如下:

  • trim(),移除首尾的空白符,public static String trim(String input)
  • length(),返回字符串長度,public static int length(Object obj)
  • replace(),將輸入字符串中指定的位置替換爲指定的字符串然後返回,public static String replace(String input, String substringBefore, String substringAfter)
  • contains(),測試輸入的字符串是否包含指定的子串,public static boolean contains(String input, String substring)
  • containsIgnoreCase(),測試輸入的字符串是否包含指定的子串,大小寫不敏感,public static boolean containsIgnoreCase(String input, String substring)
  • substring(),返回字符串的子集,public static String substring(String input, int beginIndex, int endIndex)
  • substringBefore(),返回字符串在指定子串之前的子集,public static String substringBefore(String input, String substring)
  • substringAfter(),返回字符串在指定子串之後的子集,public static String substringAfter(String input, String substring)
  • indexOf(),返回指定字符串在輸入字符串中出現的位置,public static int indexOf(String input, String substring)
  • startsWith(),測試輸入字符串是否以指定的前綴開始,public static boolean startsWith(String input, String substring)
  • endsWith(),測試輸入的字符串是否以指定的後綴結尾,public static boolean endsWith(String input, String substring)
  • join(),將數組中的元素合成一個字符串然後輸出,public static String join(String[] array, String separator)
  • split(),將字符串用指定的分隔符分隔然後組成一個子字符串數組並返回,public static String[] split(String input, String delimiters)
  • toLowerCase(),將字符串中的字符轉爲小寫,public static String toLowerCase(String input)
  • toUpperCase(),將字符串中的字符轉爲大寫,public static String toUpperCase(String input)

JSP + Servlet

  用JSP作爲顯示層,Servlet作爲控制層,請求來到Servlet,然後Servlet將處理好的數據放在請求的attribute中,JSP從請求的attribute中獲取數據顯示

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章