1. 程式人生 > >JSP、EL表示式、JSTL標籤庫乾貨(建議收藏)

JSP、EL表示式、JSTL標籤庫乾貨(建議收藏)

> JSP(Java Server Pages)類似於[ASP](https://www.w3school.com.cn/asp/asp_intro.asp)技術,它是**在傳統的網頁HTML**檔案(.htm,.html)中**插入Java程式段(Scriptlet)**和**JSP標記(tag**),從而形成JSP檔案,字尾名為(.jsp)。JSP本質上是一個簡化的Servlet設計,**JSP的實現過程:** .jsp 檔案會被**[JSP引擎](https://www.cnblogs.com/xing901022/p/4592159.html)**(由伺服器提供,如Tomcat的Jasper)譯為 .java 檔案,最終生成 .class 檔案。 [TOC]
## JSP語法 > 除了HTML語法,擴充套件的其他內容如下 ### 巢狀Java程式碼的格式 - **宣告標籤:**`<%!` `變數宣告或方法宣告` `%>` - **表示式標籤:**`<%=` `表示式` `%>` 表示式的值將輸出到JSP頁面的相應位置 - **程式碼標籤:** `<%` `Java程式碼` `%>` 頁面上動態顯示的內容
## JSP指令 > 用於**宣告** JSP 頁面的**屬性**,如編碼方式、文件型別等等。一共有三種指令:page、include、taglib。 ### 指令使用格式 `<%@` `directive ` `attribute1="value1"` `attribute2="value2"` `...` `%>` - **`directive `:** 指 page、include、taglib其中之一 - **`attribute`:**屬性名 - **`value`:**屬性值 - **`...`:**這個不是語法哦,指其他未寫出的 `attribute="value"` ### page指令 | 屬性名 | 屬性值 | 描述 | | ----------- | -------------------- | ----------------------------------------- | | **language** | java | 解釋JSP檔案時採用的語言。預設為java | | extends | 類的全名 | 由該JSP檔案生成的類繼承哪個類,JSP為Servlet,因此當指明繼承普通類時需要實現Servlet的init、destroy等方法 | | **import** | 包名/類名 | import是唯一可以宣告多次的page指令屬性。一次可以匯入多個類,中間用英文逗號隔開 | | **session** | true/false | 是否內建session物件。預設為true | | autoFlush | true/false | true代表使用out.println()等方法輸出的字串暫時存到快取裡,當快取滿了或者程式行完畢或者執行out.flush()操作時才輸出到客戶端。預設為true | | buffer | none/nKB | 指定快取大小,例如 4KB | | isThreadSafe | true/false | 是否執行緒安全。值為true時允許多執行緒執行該JSP,否則必須排隊執行。預設為false | | **isErrorPage** | true/false | 該 JSP頁面是否為錯誤顯示頁面。為true時該JSP擁有內建exception物件,否則沒有。預設為false | | **errorPage** | 某個JSP頁面的相對路徑 | 指明一個錯誤頁面,如果該JSP程式丟擲一個未捕捉的異常,則將該異常傳遞給errorPage指定JSP頁面並跳轉至errorPage指定JSP頁面 | | **contentType** | 文件型別 | 客戶端瀏覽器根據該屬性判斷文件型別。例如,HTML:text/html、純文字:text/plain、JPG影象:image/jpeg、GIF影象:image/gif、WORD文件:application/msword | | **pageEncoding** | 字符集 | 指定該JSP頁面的字符集,如UTF-8、ISO-8859-1等 | ### include指令 > 將其他 JSP檔案、HTML檔案、文字包含到該 JSP中一併編譯。這是一種**靜態包含**,相當於直接複製貼上進來,所以在編譯該JSP檔案的時候將會**一併編譯被包含的檔案** - **屬性名:**file - **屬性值:**URL相對路徑 - **例:**`<%@` `include` `file="檔案相對 url 地址"` `%>` ### taglib指令 JSP**支援標籤技術**,後面會講到標籤的用法,[JSTL標籤庫](#JSTL標籤庫)的使用等。 作用:用來指明JSP頁面內使用的JSP標籤庫,taglib指令有兩個屬性,**uri**為類庫的地址,**prefix**為標籤的字首 - **例:**`<%@` `taglib` `uri="http://java.sun.com/jsp/jstl/core"` `prefix="c"` `%>`
## JSP的9個內建物件 > 使用內建物件進行便捷的開發,大部分都是HttpServlet中使用的物件(除了pageContext和out),關於HttpServlet請看[上一篇博文](https://www.cnblogs.com/dai-blog/p/Servlet-analysis-use.html) | 物件 | 型別 | 簡述 | | ----------- | ------------------- | ------------------------------------------------------------ | | request | HttpServletRequest | 該物件是客戶端的HTTP請求,作用域為一次請求,包含頭資訊、系統資訊、請求方式等 | | response | HttpServletResponse | HTTP響應物件,作用域為該 JSP頁面 | | session | HttpSession | 作用域為一次會話 | | application | ServletContext | 作用域為Servlet容器,直到伺服器關閉前都有效 | | config | ServletConfig | 伺服器的配置資訊。config在上一篇博文的[Servlet級始化引數](https://www.cnblogs.com/dai-blog/p/Servlet-analysis-use.html#%E8%8E%B7%E5%BE%97%E5%88%9D%E5%A7%8B%E5%8C%96%E5%8F%82%E6%95%B0)中使用過。 | | page | HttpServlet | 指該 JSP編譯為Java程式碼中的Servlet類的物件(Servlet是[單例項](https://www.cnblogs.com/dai-blog/p/Servlet-analysis-use.html#servlet%E5%AE%B9%E5%99%A8)的,所以這個指向是明確的),相當於this | | exception | Exception | 只有當前頁面是錯誤頁面(`<%@` `page` `isErrorPage="true"` `%>`)才能使用,若不是錯誤頁面使用exception會導致編譯報錯。 | | out | JspWriter | 用於向頁面輸出(包括js程式碼),上面提到的page指令的autoFlush屬性就是控制這個物件 | | pageContext | PageContext | 表示頁面的上下文,可以獲取request、response、session、application、config等 |
## EL表示式 > EL(Expression Language)表示式可以更方便的展示變數和物件,避免在HTML中嵌入Java程式碼(顯的很混亂) #### 基本使用格式 `${EL表示式} ` *變數名不用加引號* #### 獲取4個域(pageContext、request、session、application)中值 > EL表示式**只能獲取域中的值**,不能獲取Java程式碼中的值!需要使用的變數一定要先存在域中。 > > 例如:`<%` `session.setAttribute("score",99)` `%>` ,此時可以讀取score這個值`${score}` > > 另外一點,如果**找不到值會返回空字串""**,而不是null ##### 完全限定
獲取方式 - 獲取pageContext域的變數:`${pageScope.key}` - 獲取request域的變數:`${requestScope.key}` - 獲取session域的變數:`${sessionScope.key}` - 獲取application域的變數:`${applicationScope.key}` ##### 隱式獲取 **`${key}` :** 將會以*pageContext:point_right:request:point_right:session:point_right:application*順序讀取,域的範圍是**從小到大** - 關於**集合**的展示 :small_red_triangle_down: ```jsp <% List list = new ArrayList(); list.add("one"); list.add("two"); list.add("three"); pageContext.setAttribute("aList",list); Map map = new HashMap(); map.put("color","red"); map.put("shape","square"); pageContext.setAttribute("aMap",map); %> ${aList}
${aList[0]}
${aList[2]}
${aMap}
${aMap.shape}
``` - 下面是在網頁中輸出的結果 :small_red_triangle_down: ``` [one, two, three] one three {color=red, shape=square} square ``` ##### 物件的展示
- 測試:small_red_triangle_down: ```jsp <% class Student{ private final String name = "Tom"; private final String sex = "boy"; @Override public String toString() { return name+" is a "+sex; } } Student student = new Student(); pageContext.setAttribute("aStudent",student); %> ${aStudent}
``` 下面是在網頁中輸出的結果 :small_red_triangle_down: ``` Tom is a boy ``` 可以看出來EL對於物件的展示其實就是**呼叫了`toString()`方法**,包括集合也一樣。如果這個物件沒有重寫`toString()`方法,那麼機會呼叫父類`toString()`方法。比如父類是Object,那麼就會輸出hashcode。 ##### 物件的欄位(屬性)
的獲取 - **獲取方式:** `${object.field}` 即可獲取物件的欄位(屬性) - 測試程式碼:small_red_triangle_down: ***com.java.webtest.Student*** ```java package com.java.webtest; public class Student { private String name = "Jack"; public String getName() { return name; } } ``` ***myTest.jsp*** ```jsp <%@ page import="com.java.webtest.Student" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <% Student s1 = new Student(); pageContext.setAttribute("s1",s1); %> name = ${s1.name}
``` - 執行結果 ``` name = Jack ``` :warning: EL表示式獲取物件欄位(屬性)是通過**反射**機制。`${s1.name}` 底層邏輯是將首字母"n"大寫再在前面拼接一個"get",然後反射獲取"getName"方法。所以物件必須提供欄位的get方法,才能使用EL表示式 `${object.field}` ,如果不寫就會報錯,或者你讓get方法返回一個和相應欄位無關的東西來證明確實是呼叫了get方法得到值的。 #### EL的運算 | 運算型別 | 描述 | | -------- | ------------------------------------------------------------ | | 算術型 | 加`+` 減`-` 乘`*` 除`/`、 `div` 取餘`%` 、`mod` | | 邏輯型 | `and`、`&&`、`or`、`||`、`!`、`not` | | 關係型 | `==`、`eq`、`!=`、`ne`、`<`、`lt`、`>`、`gt`、`<=`、`le`、`>=`、`ge` | | empty | 判斷一個值是否為null或者為empty,如`${empty ""}` 返回值為true | | 三目運算 | `expression ? valueA : valueB` 若expression為true返回valueA否則返回valueB | - 做一個測試 :small_red_triangle_down: ```jsp <% class Person{ private int id; private String sex; public Person(int id,String sex){ this.id = id; this.sex = sex; } @Override public boolean equals(Object o) { return id == ((Person) o).id; } } Person p1 = new Person(777,"boy"); Person p2 = new Person(777,"girl"); Person p3 = new Person(666,"boy"); pageContext.setAttribute("p1",p1); pageContext.setAttribute("p2",p2); pageContext.setAttribute("p3",p3); %> 1 + 2 = ${1 + 2}
1 - 2 = ${1 - 2}
3 * 3 = ${3 * 3}
10 / 3 = ${10 / 3}
10 div 3 = ${10 div 3}
10 % 3 = ${10 % 3}
10 mod 3 = ${10 mod 3}
true and false -> ${true and false}
true && false ->${true && false}
true or false -> ${true or false}
true || false -> ${true || false}
not true -> ${not true}
!true -> ${!true}
666 == 666 -> ${666 == 666}
p1 == p2 -> ${p1 == p2}
p1 == p3 -> ${p1 == p3}
"ABCDEFG" == "abcdefg" -> ${"ABCDEFG" == "abcdefg"}
"ABCDEFG" == "ABCDEFG" -> ${"ABCDEFG" == "ABCDEFG"}
"ABCDEFG" eq "abcdefg" -> ${"ABCDEFG" eq "abcdefg"}
"ABCDEFG" eq "ABCDEFG" -> ${"ABCDEFG" eq "ABCDEFG"}
"ABCDEFG" != "abcdefg" -> ${"ABCDEFG" != "abcdefg"}
"ABCDEFG" != "ABCDEFG" -> ${"ABCDEFG" != "ABCDEFG"}
"ABCDEFG" ne "abcdefg" -> ${"ABCDEFG" ne "abcdefg"}
"ABCDEFG" ne "ABCDEFG" -> ${"ABCDEFG" ne "ABCDEFG"}
10 < 3 -> ${10 < 3}
10 lt 3 -> ${10 lt 3}
10 > 3 -> ${10 > 3}
10 gt 3 -> ${10 gt 3}
10 <= 3 -> ${10 <= 3}
10 le 3 -> ${10 le 3}
10 >= 3 -> ${10 >= 3}
10 ge 3 -> ${10 ge 3}
empty "" -> ${empty ""}
empty null -> ${empty null}
empty 666 -> ${empty 666}
55 > 60 ? "you pass!" : "you fail..." -> ${55 > 60 ? "you pass!" : "you fail..."}
``` - 頁面的輸出結果:small_red_triangle_down: ``` 1 + 2 = 3 1 - 2 = -1 3 * 3 = 9 10 / 3 = 3.3333333333333335 10 div 3 = 3.3333333333333335 10 % 3 = 1 10 mod 3 = 1 true and false -> false true && false ->false true or false -> true true || false -> true not true -> false !true -> false 666 == 666 -> true p1 == p2 -> true p1 == p3 -> false "ABCDEFG" == "abcdefg" -> false "ABCDEFG" == "ABCDEFG" -> true "ABCDEFG" eq "abcdefg" -> false "ABCDEFG" eq "ABCDEFG" -> true "ABCDEFG" != "abcdefg" -> true "ABCDEFG" != "ABCDEFG" -> false "ABCDEFG" ne "abcdefg" -> true "ABCDEFG" ne "ABCDEFG" -> false 10 < 3 -> false 10 lt 3 -> false 10 > 3 -> true 10 gt 3 -> true 10 <= 3 -> false 10 le 3 -> false 10 >= 3 -> true 10 ge 3 -> true empty "" -> true empty null -> true empty 666 -> false 55 > 60 ? "you pass!" : "you fail..." -> you fail... ``` - 我認為應該**特別注意**兩點 - 兩個**整數相除**的結果並不是整數 - *p1 == p2 -> true* 和 *"ABCDEFG" == "ABCDEFG" -> true*。**顯然不同於Java,EL表示式過載了 `==`** ,物件之間使用 `==` 比較的時候,並不是比較物件的引用變數(也就是物件地址或指標),而是使用了 `equals(Object o)` 方法。`!=` 比較物件也是同理,可以自己測試一下。 ## JSTL標籤庫 > JSTL(Java server pages standarded tag library)是一個JSP標準標籤庫,它封裝了JSP應用的通用核心功能。JSTL支援**通用的、結構化的任務**,比如迭代,條件判斷,XML文件操作,國際化標籤,SQL標籤。 除了這些,它還提供了一個框架來使用整合JSTL的自定義標籤。下文將闡述*部分常用的JSTL標籤。***EL和JSTL核心標籤庫通常搭配使用效果最佳** ### 使用前的準備 - 匯入相應的jar包:standard.jar 和 jstl.jar - JSP頁面引入標籤庫 **`<%@` `taglib` `prefix="字首"` `uri="功能範圍路徑"` `%>`** | 功能範圍 | prefix | uri | | --------- | ------- | --------------------------------------- | | **core** | **c** | **http://java.sun.com/jsp/jstl/core** | | **i18n** | **fmt** | **http://java.sun.com/jsp/jstl/fmt_rt** | | sql | sql | http://java.sun.com/jsp/jstl/sql | | xml | x | http://java.sun.com/jsp/jstl/xml | | functions | fn | http://java.sun.com/jsp/jstl/function | :warning: 如果在後面使用中出現 500錯誤頁面,其中包含類似這樣的資訊:*atrribute [value] does not accpet any expressions*,有可能是uri的問題,可能需要換一個uri。uri不同版本功能有差別所以會導致一些錯誤。 ### 標籤使用語法 ```jsp ``` ### 重要標籤 > :raised_hands: 免責宣告:以下標籤屬性總結並不全面,只講比較常用的屬性;並且由於uri不同屬性不同。具體內容請檢視你匯入的standard.jar ####