JSP(Java Server Pages)是由sun公司定義的一種用于開(kāi)發(fā)動(dòng)態(tài)web資源的技術(shù)磕潮,遵循JSP/Servlet規(guī)范语泽。相當(dāng)于能夠執(zhí)行Java語(yǔ)句的Html頁(yè)面声搁,從而能夠輸出動(dòng)態(tài)內(nèi)容刽漂,本質(zhì)上就是一個(gè)封裝好的Servlet
JSP原理
JSP文件無(wú)法被直接執(zhí)行僻焚,其遵循以下執(zhí)行步驟:
(1)服務(wù)器引擎將JSP內(nèi)容翻譯成純Java代碼芹枷,并進(jìn)行編譯(可以查看目錄/work/Catalina/localhost/項(xiàng)目名/org/apache/jsp
衅疙,里面有對(duì)應(yīng)的.java
和.class
文件)
(2)執(zhí)行編譯后生成的.class
文件
(3)當(dāng).class
文件存在且JSP內(nèi)容沒(méi)被修改時(shí),則不會(huì)執(zhí)行上面步驟鸳慈,而是直接執(zhí)行.class
文件
JSP語(yǔ)法
腳本元素
主要分有三種:
1.腳本段:<% java代碼 %>
饱溢,可以放各種java代碼,這里面的變量相當(dāng)于方法內(nèi)部的臨時(shí)變量
2.聲明段:<%! 變量/方法聲明 %>
走芋,可以聲明多個(gè)變量和方法绩郎,用分號(hào)隔開(kāi)潘鲫,這里面的變量相當(dāng)于類的成員變量,在當(dāng)前整個(gè)JSP頁(yè)面中有效
3.表達(dá)式:<%=表達(dá)式%>
肋杖,輸出一個(gè)表達(dá)式結(jié)果溉仑,其本質(zhì)就相當(dāng)于out.print(表達(dá)式)
,所以后面不要有分號(hào)
注:
輸出方式有兩種状植,一個(gè)是表達(dá)式輸出浊竟,還有一個(gè)是通過(guò)out.print()
輸出,從上面可以知道表達(dá)式輸出的原理就是一個(gè)包裝好的out.print()
方法津畸,因此對(duì)于輸出表格的一列振定,前者可能是:<td><%=xxx%></td>
,而后者則是:out.print("<td>xxx</td>")
洼畅,可以看出前者很好的將HTML代碼和JSP代碼分離吩案,而后者不行,所以盡量使用第一種方法
注釋
主要分為以下幾種:
1.<帝簇!-- -->
:顯式注釋徘郭,直接用HTML代碼的注釋,前端可見(jiàn)
2.//
//* */
:隱式注釋丧肴,java代碼自帶的注釋残揉,只能在腳本段(<% %>
)中用,前端不可見(jiàn)
3.<%-- --%>
:隱式注釋芋浮,JSP自帶的注釋抱环,前端不可見(jiàn)
三個(gè)指令
指令語(yǔ)法:<%@指令 屬性1=值 屬性2=值 ...%>
,主要指令有以下幾個(gè):
1.page
指令
用于定義JSP的全局屬性纸巷,其下有常用屬性如下:
(1)contentType
:有設(shè)置MIME類型(瀏覽器的打開(kāi)方式镇草,一般設(shè)置成html),舉例:
<%page contentType="text/html; charset=GBK" %> //設(shè)置編碼
(2)pageEncoding
:設(shè)置JSP引擎的翻譯編碼
(3)import
:導(dǎo)包屬性瘤旨,導(dǎo)入可使用的java類梯啤,是page
下唯一一個(gè)可以多次設(shè)置的屬性,如果要導(dǎo)入多個(gè)包存哲,則用逗號(hào)隔開(kāi)因宇,舉例:
<%@page import="java.util.*,java.net.Socket"%>
(4)errorPage
:當(dāng)原來(lái)的JSP頁(yè)面出現(xiàn)錯(cuò)誤時(shí),將會(huì)自動(dòng)跳轉(zhuǎn)到指定頁(yè)面祟偷,默認(rèn)是相對(duì)路徑察滑,如果以/
開(kāi)頭則代表從項(xiàng)目根目錄開(kāi)始的路徑,舉例:
<%@ page errorPage="error.jsp" %>
(5)isErrorPage
:是否為錯(cuò)誤頁(yè)面修肠,默認(rèn)是false
贺辰,如果設(shè)置為true
則會(huì)多一個(gè)Throwable
對(duì)象exception
,可以用來(lái)查看錯(cuò)誤信息,舉例:
<%@ page isErrorPage="true" %>
...
<%=exception.getMessage()%>
(6)isELIgnored
:是否忽略EL表達(dá)式魂爪,默認(rèn)為false
2.include
指令
用于在JSP頁(yè)面中靜態(tài)包含一個(gè)文件先舷,可以是JSP、HTML滓侍、TXT文件等蒋川,也可以是一段Java代碼,使用該指令的JSP頁(yè)面在翻譯前會(huì)自動(dòng)插入包含的文件或者代碼撩笆,其中該指令有兩種語(yǔ)法:
<%@include file="xxx.html" %> //第一種
<jsp:include page="xxx.jsp" /> //第二種捺球,不是指令方法,屬于動(dòng)作元素
前者為靜態(tài)包含文件夕冲,其會(huì)在翻譯JSP之前就把包含文件的內(nèi)容加進(jìn)來(lái)氮兵,即合并成一個(gè)文件,然后一起翻譯歹鱼、編譯和執(zhí)行泣栈;后者為動(dòng)態(tài)包含,其會(huì)先翻譯弥姻、編譯和執(zhí)行原來(lái)的JSP文件南片,當(dāng)執(zhí)行到包含文件的語(yǔ)句時(shí),則會(huì)對(duì)該文件也進(jìn)行翻譯庭敦、編譯和執(zhí)行疼进,并且還可以在包含文件時(shí)傳入?yún)?shù),舉例:
<jsp:include page="xxx.jsp"> //按成對(duì)標(biāo)簽情況結(jié)尾沒(méi)有斜杠
<jsp:param name="xxx" value="xxx" /> //單標(biāo)簽情況結(jié)尾用斜杠結(jié)束
...
</jsp:include>
3.taglib
指令
在頁(yè)面中導(dǎo)入JSTL標(biāo)簽庫(kù)秧廉,替換JSP中的java代碼片段伞广,包括if、forEach疼电、import等
附:JSTL標(biāo)簽
Java Server Page Standard Tag Library嚼锄,JSP標(biāo)準(zhǔn)連接庫(kù),主要用于簡(jiǎn)化Java代碼蔽豺,導(dǎo)入庫(kù)方式:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> //導(dǎo)入標(biāo)簽庫(kù)灾票,并取名為c
有以下核心標(biāo)簽庫(kù):
(1)set
:聲明變量,有var
茫虽、value
、scope
三個(gè)屬性
(2)out
:輸出既们,有value
和default
屬性
(3)remove
:移除變量濒析,有var
屬性,使用舉例:
<c:set var="name" value="${1}" scope="page"/> //name=1
<c:out value="${name}"/>
<c:remove var="name"/>
<c:out value="${name}" default="nothing"/> //name不存在啥纸,輸出nothing
(4)if
:判斷語(yǔ)句号杏,當(dāng)test
屬性的內(nèi)容為true
即輸出,舉例:
<c:if test="${6>5}">
fasfdsgs
</c:if>
(5)choose
:相當(dāng)于switch
語(yǔ)句,里面用when
標(biāo)簽來(lái)選盾致,舉例:
<c:set var="score" value="${61}" />
<c:choose>
<c:when test="${score<60 && score>=0}">不及格</c:when>
<c:when test="${score>=60 && score<80}">及格</c:when>
<c:when test="${score>=80}">優(yōu)秀</c:when>
<c:otherwise>其他</c:otherwise>
</c:choose>
(6)forEach
:循環(huán)用主经,有var
、begin
庭惜、end
罩驻、step
等屬性,舉例:
<c:forEach var="i" begin="1" end="10" step="2">
${i}
</c:forEach>
該標(biāo)簽下還有items
屬性护赊,主要用于存放迭代器和數(shù)組等惠遏,還有varStatus
屬性代表給迭代器取名,則該迭代器下有自帶的四個(gè)屬性(通過(guò)getter方法調(diào)用):index
(從0開(kāi)始的索引)骏啰,count
(從1開(kāi)始的計(jì)數(shù))节吮,first
/last
(是否為第一個(gè)/最后一個(gè)),舉例:
<%
ArrayList li = new ArrayList();
li.add("aaa");
li.add("bbb");
li.add("ccc");
String[] s = { "dsa", "Fsdg", "Hrhe" };
request.setAttribute("list", s);
%>
<table border="1">
<c:forEach items="${list}" var="l" varStatus="vs">
<tr>
<td>${l}</td>
<td>${vs.index}</td>
<td>${vs.count}</td>
<td>${vs.first}</td>
<td>${vs.last}</td>
</tr>
</c:forEach>
</table>
結(jié)果為:
dsa 0 1 true false
Fsdg 1 2 false false
Hrhe 2 3 false true
六個(gè)動(dòng)作
與指令元素不同判耕,動(dòng)作元素在請(qǐng)求處理階段起作用透绩,使用XML語(yǔ)法,語(yǔ)法格式:
<jsp:動(dòng)作 屬性=值 ... /> //格式1
<jsp:動(dòng)作 屬性=值 ... >...</jsp:動(dòng)作> //格式2
可以看出在格式2中可以多個(gè)動(dòng)作元素進(jìn)行嵌套使用壁熄。常用的有以下幾種:
1.<jsp:include page="" />
:動(dòng)態(tài)包含文件
2.<jsp:param name="" value="" />
:設(shè)置請(qǐng)求參數(shù)值帚豪,相當(dāng)于url?name=value
3.<jsp:forward page="" />
:跳轉(zhuǎn)到頁(yè)面,為服務(wù)端跳轉(zhuǎn)请毛,假如后面還有語(yǔ)句志鞍,則不會(huì)執(zhí)行
4.<jsp:useBean id="實(shí)例化對(duì)象" class="對(duì)象對(duì)應(yīng)的包.類" scope="對(duì)象使用范圍" />
:用于創(chuàng)建javabean對(duì)象,舉例:
<jsp:useBean id="user" class="cn.aaa.User" scope="page" />
實(shí)質(zhì)上就相當(dāng)于:
<%
User user = new User();
%>
5.<jsp:setProperty name="javabean對(duì)象" property="屬性" />
:設(shè)置javabean對(duì)象屬性值方仿,其中有四種方法設(shè)置:
<jsp:setProperty name="XXX" property="*" /> //根據(jù)參數(shù)名稱自動(dòng)進(jìn)行設(shè)置固棚,利用了反射機(jī)制,通過(guò)傳遞的參數(shù)找到對(duì)應(yīng)方法
<jsp:setProperty name="XXX" property="yyy" /> //指定屬性
<jsp:setProperty name="XXX" property="yyy" param="zzz" /> //將指定參數(shù)的值給指定屬性
<jsp:setProperty name="XXX" property="yyy" value="zzz" /> //設(shè)置指定值給指定屬性
第一種方法將根據(jù)前端傳來(lái)的參數(shù)名稱自動(dòng)匹配仙蚜,舉例:
javabean對(duì)象:
public class User {
String name;
String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
表單數(shù)據(jù):
<form action="index.jsp" method="post">
<input type="text" name="name">
<input type="password" name="password">
<input type="submit" value="submit">
</form>
jsp中:
<jsp:useBean id="u1" class="com.aaa.User" />
<jsp:setProperty property="*" name="u1"/>
<jsp:getProperty property="name" name="u1"/>
<jsp:getProperty property="password" name="u1"/>
結(jié)果將會(huì)自動(dòng)設(shè)置name和password的值并獲取此洲。
6.<jsp:getProperty name="javabean對(duì)象" property="屬性"/>
:獲取指定對(duì)象屬性
九大內(nèi)置對(duì)象
Java中一般使用對(duì)象前需要進(jìn)行實(shí)例化,而下面的9個(gè)對(duì)象則可以無(wú)需實(shí)例化直接調(diào)用委粉,即內(nèi)置對(duì)象
1.pageContext
當(dāng)前頁(yè)面上下文呜师,其可以獲得request
/session
等對(duì)象,因此也可以操作requset
/session
/application
的數(shù)據(jù)贾节,常用方法:
(1)getRequest()
:獲取當(dāng)前頁(yè)面的request
對(duì)象汁汗,其他幾個(gè)對(duì)象也都可以通過(guò)相應(yīng)的get方法獲得,如:getResponse()
栗涂、getServletContext()
知牌、getOut()
等
(2)setAttribute()
:設(shè)置屬性值,還有對(duì)應(yīng)的getAttribute()
和removeAttribute()
斤程,但和其他的屬性操作方法不同的是角寸,這三個(gè)方法可以比原來(lái)都多1個(gè)參數(shù),用來(lái)設(shè)置作用域,舉例:
pageContext.setAttribute("aaa", "bbb", pageContext.APPLICATION_SCOPE); //提供了四個(gè)作用域常量扁藕,分別對(duì)應(yīng)數(shù)字1-4
(3)findAttribute()
:和getAttribute()
一樣是獲取屬性沮峡,但是該方法可以無(wú)視作用域,依次從page
->request
->session
->application
里面查找亿柑,找到則取值并結(jié)束查找
(4)forward()
:跳轉(zhuǎn)
(5)include()
:包含
2.request
常用方法:
(1)getParameter()
:接收表單參數(shù)
(2)setCharacterEncoding(編碼)
:上面的方式直接接收數(shù)據(jù)容易出現(xiàn)亂碼邢疙,于是最好通過(guò)該方法先設(shè)置接收編碼,舉例:
<% String name = request.getParameter("username"); %>
(3)getParameterValues()
:當(dāng)遇到像復(fù)選框這樣有多個(gè)參數(shù)的情況橄杨,上面的方法只能接收到第一個(gè)參數(shù)秘症,因此需要使用該方法來(lái)接收一組參數(shù),返回的是個(gè)數(shù)組
(4)getRemoteAddr()
:取得客戶端的IP地址
(5)getCookies()
:獲取所有cookie對(duì)象式矫,返回一個(gè)cookie數(shù)組乡摹,舉例:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int i = 0;
Cookie cs[] = request.getCookies();
for (Cookie c : cs) {
System.out.println(c.getName() + ":" + c.getValue());
}
response.addCookie(new Cookie("name", "" + i++));
}
(6)getSession()
:返回一個(gè)HttpSession
對(duì)象
3.response
常用方法:
(1)setHeader(name, value)
:設(shè)置頭信息的內(nèi)容,獲取頭信息則可以用getHeader(name)
采转,如果要獲取所有頭信息名字聪廉,則用:getHeaderNames()
,其中有個(gè)定時(shí)跳轉(zhuǎn)的屬性為refresh
故慈,舉例:
response.setHeader("refresh","1"); //1秒刷新一次
response.setHeader("refresh","2;URL=xxx.jsp"); //2秒后跳轉(zhuǎn)到xxx.jsp板熊,此處為客戶端跳轉(zhuǎn)
(2)sendRedirect(url)
:重定向到頁(yè)面,為客戶端跳轉(zhuǎn)察绷,并且如果后面還有語(yǔ)句干签,則會(huì)在后面的語(yǔ)句都執(zhí)行完后才進(jìn)行跳轉(zhuǎn),也可以通過(guò)設(shè)置響應(yīng)頭來(lái)實(shí)現(xiàn)拆撼。
(3)addCookie(cookie)
:給客戶端設(shè)置cookie容劳,需要建立個(gè)Cookie
對(duì)象來(lái)設(shè)置cookie,舉例:
Cookie c1 = new Cookie("name","aaa");
Cookie c2 = new Cookie("password","bbb");
response.addCookie(c1);
response.addCookie(c2);
(4)setContentType(type)
:設(shè)置內(nèi)容的返回類型
4.session
對(duì)于服務(wù)器來(lái)說(shuō)闸度,每一個(gè)上網(wǎng)者是通過(guò)session id來(lái)區(qū)分的竭贩,而該id是用戶第一次連接到服務(wù)器時(shí)服務(wù)器自動(dòng)分配的,常用于系統(tǒng)登錄中莺禁。有以下常用方法:
(1)isNew()
:是否為新session
(2)getId()
:返回session id
(3)invalidate()
:讓session失效
5.application
即Servlet中的ServletContext
留量,常用方法:
(1)getRealPath()
:獲取虛擬目錄對(duì)應(yīng)的真實(shí)路徑
注:
一般很少直接用application
,而用getServletContext()
來(lái)表示application
6.config
ServletConfig對(duì)象
7.out
相當(dāng)于PrintWriter
對(duì)象哟冬,即輸出頁(yè)面信息用的
8.page
當(dāng)前Servlet實(shí)例對(duì)象楼熄,即this
9.exception
當(dāng)設(shè)置isErrorPage
為true
時(shí)才存在,可以輸出錯(cuò)誤信息
四大域?qū)ο?/h3>
屬性范圍即設(shè)置的屬性可以在經(jīng)過(guò)多少個(gè)頁(yè)面后仍可訪問(wèn)的范圍浩峡,范圍越大孝赫,越影響性能
1.page
僅能在當(dāng)前頁(yè)中取得,通過(guò)pageContext
來(lái)設(shè)置
2.request
在一次服務(wù)器的跳轉(zhuǎn)中有效红符,所以只要是服務(wù)器跳轉(zhuǎn),就可以將屬性一直傳遞(所以使用超鏈接跳轉(zhuǎn)則屬性消失)
3.session
一個(gè)用戶設(shè)置的內(nèi)容,只要和該用戶相關(guān)的頁(yè)面都可訪問(wèn)预侯,所以不論怎么跳轉(zhuǎn)都可以取到值致开,但是新開(kāi)一個(gè)瀏覽器,則無(wú)法取得屬性
4.application
整個(gè)服務(wù)器上設(shè)置的屬性萎馅,所有人都可以訪問(wèn)双戳,但是服務(wù)器一旦關(guān)閉,該屬性也會(huì)隨之消失糜芳,并且因?yàn)榉秶箪酰绊懶剩也话踩涂ⅲM量少用
屬性操作
對(duì)于上面的幾種屬性范圍塘辅,都提供了以下的幾個(gè)屬性操作方法:
(1)setAttribute(name, value)
:設(shè)置屬性
(2)getAttribute(name)
:獲取屬性,返回Object
對(duì)象皆撩,需要進(jìn)行強(qiáng)轉(zhuǎn)
(3)removeAttribute(name)
:刪除屬性
使用舉例:
<%
pageContext.setAttribute("name", "aaa"); //設(shè)置page屬性
%>
EL表達(dá)式
expression language扣墩,即表達(dá)式語(yǔ)言,用于簡(jiǎn)化java代碼扛吞,是JSP中獲取數(shù)據(jù)的一種規(guī)范
格式及原理
格式一——獲取域?qū)ο髷?shù)據(jù)
${內(nèi)容}
舉例:
<%=request.getAttribute("aaa") %>
<%=session.getAttribute("aaa") %>
那么上面兩個(gè)語(yǔ)句都可以用下面這一句來(lái)表示:
${aaa}
但有點(diǎn)不同的是如果獲取的數(shù)據(jù)不存在呻惕,則不是null
,而是空字符串滥比。從以上可以發(fā)現(xiàn)EL表達(dá)式的底層代碼差不多就是:
out.print(pageContext.findAttribute("aaa") != null?pageContext.findAttribute("aaa"):"");
格式二——獲取數(shù)據(jù)屬性
${對(duì)象.xxx}
${對(duì)象["xxx"]} //用單引號(hào)也可以
對(duì)于獲取的數(shù)據(jù)如果是對(duì)象亚脆,則可以用.屬性
或者["屬性"]
來(lái)獲取屬性,如果獲取的屬性還是個(gè)對(duì)象盲泛,還能繼續(xù)用該方法繼續(xù)往下獲取屬性...但這些表達(dá)式獲取屬性的本質(zhì)是調(diào)用了對(duì)象的getter方法濒持,而并非直接調(diào)用屬性。
兩種獲取屬性區(qū)別:
前者能做到的查乒,后者都能做到弥喉,但是在比如列表索引下標(biāo)時(shí),只有后者能夠做到
格式三——判空運(yùn)算
${ empty 內(nèi)容}
判斷內(nèi)容是否為空玛迄,是則為true
由境,舉例:
<%
request.setAttribute("l1", new ArrayList());
request.setAttribute("l2", new String[10]);
request.setAttribute("l3", "");
%>
${empty l1} //空列表,為true
${empty l2} //10個(gè)null的數(shù)組蓖议,為false
${empty l3 ? "空字符串":"非空字符串"} //空字符串
格式四——引用隱式對(duì)象
${隱式對(duì)象.內(nèi)容}
可以獲得指定對(duì)象的數(shù)據(jù)虏杰,舉例:
<%
pageContext.setAttribute("aaa", "aaa", 1);
pageContext.setAttribute("aaa", "bbb", 2);
pageContext.setAttribute("aaa", "ccc", 3);
pageContext.setAttribute("aaa", "ddd", 4);
%>
${applicationScope.aaa} //指定獲取application對(duì)象的aaa,因此輸出ddd
${param.aaa} //url?aaa=asd勒虾,則輸出asd
其中其包括11個(gè)隱式對(duì)象:
(1)pageContext
(2)pageScope
:頁(yè)面范圍的數(shù)據(jù)
(3)requestScope
:請(qǐng)求范圍的數(shù)據(jù)
(4)sessionScope
:會(huì)話范圍的數(shù)據(jù)
(5)applicationScope
:應(yīng)用范圍的數(shù)據(jù)
(6)param
:一個(gè)請(qǐng)求參數(shù)纺阔,相當(dāng)于request.getParameter()
(7)paramValues
:重名請(qǐng)求參數(shù)(如多選框)
(8)header
:請(qǐng)求消息頭
(9)headerValues
:重名請(qǐng)求消息頭
(10)initParam
:web.xml的全局參數(shù)
(11)cookie
:cookie對(duì)象的name