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核心標簽庫通常搭配使用效果最佳
使用前的准備
-
導入相應的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 ⚠️ 如果在后面使用中出現 500錯誤頁面,其中包含類似這樣的信息:atrribute [value] does not accpet any expressions,有可能是uri的問題,可能需要換一個uri。uri不同版本功能有差別所以會導致一些錯誤。
標簽使用語法
<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字符。有些字符如< 在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="<==when escapeXml is true==>"></c:out><br>
<c:out value="<==when escapeXml is false==>" escapeXml="false"></c:out><br>
</body>
</html>
結果
********** set & out Test **********
apple is fruit.
person1 : David is 18 years old.
person2 : person2 is null!
<==when escapeXml is true==>
<==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