JSP、EL表達式、JSTL標簽庫干貨(建議收藏)


JSP(Java Server Pages)類似於ASP技術,它是在傳統的網頁HTML文件(.htm,.html)中插入Java程序段(Scriptlet)JSP標記(tag),從而形成JSP文件,后綴名為(.jsp)。JSP本質上是一個簡化的Servlet設計,JSP的實現過程: .jsp 文件會被JSP引擎(由服務器提供,如Tomcat的Jasper)譯為 .java 文件,最終生成 .class 文件。


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標簽庫的使用等。

作用:用來指明JSP頁面內使用的JSP標簽庫,taglib指令有兩個屬性,uri為類庫的地址,prefix為標簽的前綴

  • 例:<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

JSP的9個內置對象

使用內置對象進行便捷的開發,大部分都是HttpServlet中使用的對象(除了pageContext和out),關於HttpServlet請看上一篇博文

對象 類型 簡述
request HttpServletRequest 該對象是客戶端的HTTP請求,作用域為一次請求,包含頭信息、系統信息、請求方式等
response HttpServletResponse HTTP響應對象,作用域為該 JSP頁面
session HttpSession 作用域為一次會話
application ServletContext 作用域為Servlet容器,直到服務器關閉前都有效
config ServletConfig 服務器的配置信息。config在上一篇博文的Servlet級始化參數中使用過。
page HttpServlet 指該 JSP編譯為Java代碼中的Servlet類的對象(Servlet是單實例的,所以這個指向是明確的),相當於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👉request👉session👉application順序讀取,域的范圍是從小到大

  • 關於集合的展示 🔻
<%
	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}<br/>		<!--直接輸出數組-->
${aList[0]}<br/>	<!--按下標讀取數組-->
${aList[2]}<br/>	<!--按下標讀取數組-->
${aMap}<br/>		<!--直接輸出映射-->
${aMap.shape}<br/>	<!--按鍵讀取映射-->
  • 下面是在網頁中輸出的結果 🔻
[one, two, three]
one
three
{color=red, shape=square}
square
對象的展示
  • 測試🔻
<%
	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}<br/>

下面是在網頁中輸出的結果 🔻

Tom is a boy

可以看出來EL對於對象的展示其實就是調用了toString()方法,包括集合也一樣。如果這個對象沒有重寫toString()方法,那么機會調用父類toString()方法。比如父類是Object,那么就會輸出hashcode。

對象的字段(屬性)的獲取
  • 獲取方式: ${object.field} 即可獲取對象的字段(屬性)
  • 測試代碼🔻

com.java.webtest.Student

package com.java.webtest;

public class Student {
    private String name = "Jack";
    public String getName() {
        return name;
    }
}

myTest.jsp

<%@ page import="com.java.webtest.Student" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>myTest</title>
</head>
<body>
    <%
        Student s1 = new Student();
        pageContext.setAttribute("s1",s1);
    %>
    name = ${s1.name}<br/>
</body>
</html>
  • 運行結果
name = Jack

⚠️ 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
  • 做一個測試 🔻
<%
    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}<br/>
1 - 2 = ${1 - 2}<br/>
3 * 3 = ${3 * 3}<br/>
10 / 3 = ${10 / 3}<br/>
10 div 3 = ${10 div 3}<br/>
10 % 3 = ${10 % 3}<br/>
10 mod 3 = ${10 mod 3}<br/>
true and false -> ${true and false}<br/>
true && false ->${true && false}<br/>
true or false -> ${true or false}<br/>
true || false -> ${true || false}<br/>
not true -> ${not true}<br/>
!true -> ${!true}<br/>
666 == 666 -> ${666 == 666}<br/>
p1 == p2 -> ${p1 == p2}<br/>
p1 == p3 -> ${p1 == p3}<br/>
"ABCDEFG" == "abcdefg" -> ${"ABCDEFG" == "abcdefg"}<br/>
"ABCDEFG" == "ABCDEFG" -> ${"ABCDEFG" == "ABCDEFG"}<br/>
"ABCDEFG" eq "abcdefg" -> ${"ABCDEFG" eq "abcdefg"}<br/>
"ABCDEFG" eq "ABCDEFG" -> ${"ABCDEFG" eq "ABCDEFG"}<br/>
"ABCDEFG" != "abcdefg" -> ${"ABCDEFG" != "abcdefg"}<br/>
"ABCDEFG" != "ABCDEFG" -> ${"ABCDEFG" != "ABCDEFG"}<br/>
"ABCDEFG" ne "abcdefg" -> ${"ABCDEFG" ne "abcdefg"}<br/>
"ABCDEFG" ne "ABCDEFG" -> ${"ABCDEFG" ne "ABCDEFG"}<br/>
10 < 3 -> ${10 < 3}<br/>
10 lt 3 -> ${10 lt 3}<br/>
10 > 3 -> ${10 > 3}<br/>
10 gt 3 -> ${10 gt 3}<br/>
10 <= 3 -> ${10 <= 3}<br/>
10 le 3 -> ${10 le 3}<br/>
10 >= 3 -> ${10 >= 3}<br/>
10 ge 3 -> ${10 ge 3}<br/>
empty "" -> ${empty ""}<br/>
empty null -> ${empty null}<br/>
empty 666 -> ${empty 666}<br/>
55 > 60 ? "you pass!" : "you fail..." -> ${55 > 60 ? "you pass!" : "you fail..."}<br/>
  • 頁面的輸出結果🔻
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核心標簽庫通常搭配使用效果最佳

使用前的准備

標簽使用語法

<prefix:tag attribute="value" ... >
	...
</prefix:tag>

重要標簽

🙌 免責聲明:以下標簽屬性總結並不全面,只講比較常用的屬性;並且由於uri不同屬性不同。具體內容請查看你導入的standard.jar

<c:tag>標簽

使用標簽前不要忘記導入標簽,不過IDEA也會自動導入。核心標簽按照功能可以分為👇

  • 表達式操作: out、set、remove、catch
  • 流程控制: if、choose、when、otherwise
  • 迭代操作: forEach、forTokens
  • URL操作: import、param、url、redirect
<c:set>標簽
屬性 缺省 說明
value - 向域中存入的變量值
var - 向域中存入的變量名
scope page 指定存儲在4個域中的哪一個
target - Java對象
property - Java對象的字段(屬性)。因為使用的是反射技術,與前面EL表達式獲取字段值同理:該字段必須有set方法
<c:out>標簽
屬性 缺省 說明
value - 需要顯示出來的值
default - 如果value的值為null,則顯示default的值
escapeXml true 是否轉義xml字符。有些字符如&lt在xml中被認為是<,若要它的字面意思,就需要使用轉移

案例 👇

com.java.testclass.Person

package com.java.testclass;

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return name+" is "+age+" years old.";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

JSTL-test.jsp

<%@ page import="com.java.testclass.Person" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %>
<html>
<head>
    <title>JSTL-test</title>
</head>
<body>

<%
    pageContext.setAttribute("person1",new Person("Tom",18));
    pageContext.setAttribute("person2",null);
%>

<h6>********** set & out Test **********</h6>
<%--向域中存值--%>
<c:set var="fruit" value="apple"></c:set>
<c:set var="fruit" value="banana" scope="session"></c:set>
<%--設置Java對象的字段--%>
<c:set value="David" target="${person1}" property="name"></c:set>
<c:set target="${person1}" property="age">18</c:set><br>
<%--輸出--%>
<c:out value="${fruit} is fruit." default="fruit is null!"></c:out><br>
person1 : ${person1}<br>
person2 : <c:out value="${person2}" default="person2 is null!"></c:out><br>
<c:out value="&lt==when escapeXml is true==&gt"></c:out><br>
<c:out value="&lt==when escapeXml is false==&gt" escapeXml="false"></c:out><br>

</body>
</html>

結果

********** set & out Test **********

apple is fruit.
person1 : David is 18 years old.
person2 : person2 is null!
&lt==when escapeXml is true==&gt
<==when escapeXml is false==>
<c:if>標簽
屬性 缺省 說明
test - if 的條件表達式
var - 定義一個變量存儲if 條件表達式的結果
scope page var變量的JSP范圍
<c:choose>標簽
屬性 缺省 說明
test 如果表達式的結果為true,則執行體內容,false則相反
<c:choose>
    <c:when test="boolean表達式">
    </c:when>
    <c:otherwise>
    </c:otherwise>
</c:choose>
<c:forEach>標簽

用於遍歷集合元素

屬性 缺省 說明
var - 遍歷用的循環變量
items - 被遍歷的集合對象
varStatus - 存放本輪循環變量的相關參數
begin 0 遍歷起點下標
end 最后元素下標 遍歷終點下標
step 1 每次迭代的間隔數

直接看例子 👇

<%
    int[] arr = {100,200,300,400,500,600,700,800,900,1000};
    pageContext.setAttribute("arr",arr);
%>

<h6>********** process control Test **********</h6>
foreach arr
<c:forEach items="${arr}" var="it" begin="1" end="7" step="2" varStatus="status">
    <c:if test="${status.count==1}">
        from ${status.begin} to ${status.end} by step = ${status.step}<br>
    </c:if>
    arr[${status.index}] = ${it} , count = ${status.count}<br>
</c:forEach>

結果

********** process control Test **********

foreach arr from 1 to 7 by step = 2
arr[1] = 200 , count = 1
arr[3] = 400 , count = 2
arr[5] = 600 , count = 3
arr[7] = 800 , count = 4

從結果count屬性並不是與index屬性關聯的值,index是數組的下標count僅作為循環的計數器

<fmt:tag>標簽

<fmt:formatDate>標簽

該標簽用於格式化輸出Date類型變量,比較常用

屬性 缺省 說明
value - 用於指定被格式化對象
pattern - 格式化的模式,與SimpleDateFormat的參數設置一樣
var - 指定產生的格式化字符串所存放的變量,若不指定則直接輸出在頁面中
scope page 指定var變量的存儲域
type date 說明value對象包含時間或包含日期還是兩者兼具。取值為date/time/both
<fmt:parseDate>標簽

<fmt:formatDate>的逆向過程,用於將指定字符串轉化為日期類型

屬性 說明
value 用於指定被轉化的字符串
pattern 指定解析字符串的格式
var 指定生成的時間對象所存放的變量

請看測試代碼 👇

<%
    pageContext.setAttribute("now",new Date());
%>

<h6>******************** fmt Test ********************</h6>
before formatting : ${now}. <br>
<fmt:formatDate value="${now}" pattern="yyyy-MM-dd" var="parse_date"></fmt:formatDate>
after formatting  : ${parse_date}. <br>
<fmt:parseDate value="${parse_date}" var="gotten_date" pattern="yyyy-MM-dd"></fmt:parseDate>
date get from string : ${gotten_date}. <br>

結果

******************** fmt Test ********************

before formatting : Sat Mar 13 23:03:16 CST 2021.
after formatting : 2021-03-13.
date get from string : Sat Mar 13 00:00:00 CST 2021

❕ 注意第一個日期與第三個日期的差別,這是由於第一次轉換的時候丟失了時間信息

<fmt:formatNumber>標簽

主要用於控制數字的展示格式。還記得前面EL運算10/3的結果展示為3.3333333333333335,通常我們不想展示這么多小數位。

屬性 說明
maxIntegerDigits 整數部分最多的位數
minIntegerDigits 整數部分最少的位數
maxFrctionDigits 小數部分最多的位數
minFrctionDigits 小數部分最少的位數
var 指定存儲格式化結果的變量
scope 指定var屬性的作用域



Java學習路線正在建造中歡迎學習討論:https://www.cnblogs.com/dai-blog/ 😁
轉載請注明出處:https://www.cnblogs.com/dai-blog/p/JSP-EL-JSTL-essence.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM