一、三個編譯指令
1、page指令:
首先,我們要明確一點就是page指令是一個全局指令,針對當前頁面,其次我們再來深挖他的功能,它到底有哪些功能那,在我們程序中起到什么作用???
a、語法結構:<%page %>
b、<%@page language="java"%>:這個屬性用於設定jsp的編程語言,目前java是唯一有效的編程語言。
c、<%@page extends=""%>:我們知道jsp的底層其實是Servlet,這里的這個屬性就是指我們的這個jsp是繼承那個Servlet的。這個我們一般不做修改,默認繼承的是HttpJspBase.
d、<%@page erropage=""%>:這個標簽的屬性指的是當我們的這個jsp頁面發生變化的時候,會跳轉到我們這個頁面。
e、<%@page isErrotpage=""%>:這個屬性其實是和errorpage的屬性配合使用的,如果我們把它設置成true,則該頁面就可以做為錯誤頁面。
f、<%@page contentType="text/html" charset="gb123"%>:這個屬性是我們最常用的,用於設置文件格式和編碼格式。
g、<%@page session="true"%>:指的是該頁面是否可以用到Session對象,說白了就是設置該頁面有沒有資格參與http會話。
h、<%@page import=""%>:這個屬性用來引入我們需要用到的jar包。
i、 <%@page buffer=""%>:指定到客戶輸出流的緩沖模式。如果為none,則不緩沖;如果指定數值,那么輸出就用不小於這個值的緩沖區進行緩沖。與autoFlash一起使用。默認不小於8KB,根據不同的服務器可設置。例如,buffer="64kb"。
j、<%@page autoFlash=""%>:如果為true緩沖區滿時,到客戶端輸出被刷新;如果為false緩沖區滿時,出現運行異常,表示緩沖區溢出。默認為true,例如autoFlash="true"。
k、<%@page info=""%>:關於JSP頁面的信息,定義一個字符串,可以使用servlet.getServletInfo()獲得。 默認省略。例如,info="測試頁面"。
l、<%@page isThreadSafe=""%>:用來設置JSP文件是否能多線程使用。如果設置為true,那么一個JSP能夠同時處理多個用戶的請求;相反,如果設置為false,一個JSP只能一次處理一個請求。例如,isThreadSafe="true"。
m、<%@page pageEncoding=""%>:JSP頁面的字符編碼 ,默認值為pageEncoding="iso-8859-1",例如pageEncoding="gb2312"。
2、include指令
首先,我們明確這個指令是干啥的??顧名思義,就是包含一個文件的,說白了該指令可以把外部的一個jsp頁面加載到當前的jsp頁面中,但有一點我們要注意,jsp頁面只能解析靜態的外部jsp頁面。
a、語法結構:<%include file=" "%>:file中添加我們要引入文件的url。
b、一個比較好的Include指令例子就是使用多頁面來包含一個通用的頭模塊和尾模塊的內容。
就像這樣:
header.jsp
<%! int pageCount = 0; void addCount() { pageCount++; } %> <% addCount(); %> <html> <head> <title>The include Directive Example</title> </head> <body> <center> <h2>The include Directive Example</h2> <p>This site has been visited <%= pageCount %> times.</p> </center> <br/><br/>
footer.jsp
<br/><br/> <center> <p>Copyright © 2010</p> </center> </body> </html>
main.jsp:
<%@ include file="header.jsp" %> <center> <p>Thanks for visiting my page.</p> </center> <%@ include file="footer.jsp" %>
3、taglib指令
a、這個指令是干什么的那???這個指令是引入標簽庫或者自定義標簽庫的一個指令。
b、語法結構:<%@taglib uri="" prefix="">
c、自定義taglib標簽:
第一步:開發自定義標簽類
原理:底層是由標簽處理類提供支持,從而實現簡單的標簽來封裝復雜的功能,從而使團隊更好的協作開發。
自定義標簽類都必須繼承一個父類:javax.servlet.jsp.tagext.SimpleTagSupport,或者TagSupport除此之外,JSP自定義標簽類還有如下要求。
1)、如果標簽類包含屬性,每個屬性都有對應的getter和setter方法。
2)、重寫doTag()或者doStartTag()或doEndTag()方法方法,這個方法負責生成頁面內容。
不帶屬性的標簽代碼:
public class HelloWorldTag extends TagSupport { private static final long serialVersionUID = -3382691015235241708L; @Override public int doEndTag() throws JspException { try { pageContext.getOut().write("Hello World !"); return super.doEndTag(); } catch (JspException e) { e.printStackTrace(); return 0; } catch (IOException e) { e.printStackTrace(); return 0; } } @Override public int doStartTag() { try { pageContext.getOut().write("Hello World"); return super.doStartTag(); } catch (JspException e) { e.printStackTrace(); return 0; } catch (IOException e) { e.printStackTrace(); return 0; } } }
問題1:tagsupport中的dostartTag和doEndTag這兩個方法有什么區別???
doStartTag是在掃描到起始標簽時調用,doEndTag是在掃描到結束標簽是調用。
例如:<helloWorld> helloWorld</helloWorld>
則jsp引擎分析到<helloWorld> 時調用doStratTag, 分析到</helloWorld>時調用doEndTag
第二步:建立TLD文件
TLD是Tag Library Definition的縮寫,即標簽庫定義,文件的后綴是tld,每個TLD文件對應一個標簽庫,一個標簽庫中可包含多個標簽,TLD文件也稱為標簽庫定義文件。
標簽庫定義文件的根元素是taglib,它可以包含多個tag子元素,每個tag子元素都定義一個標簽。通常我們可以到Web容器下復制一個標簽庫定義文件,並在此基礎上進行修改即可。例如Tomcat6.0,在webapps\examples\WEB-INF\jsp2路徑下包含了一個jsp2-example-taglib.tld文件,這就是示范用的標簽庫定義文件。
將該文件復制到Web應用的WEB-INF/路徑,或WEB-INF的任意子路徑下,並對該文件進行簡單修改,修改后的helloworld.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 web-jsptaglibrary_2_0.xsd" version="2.0"> <tlib-version>1.0</tlib-version> <short-name>myhelloworld</short-name> <!-- 定義該標簽庫的URI 必須添加但可以空--> <uri></uri> <!-- 定義第一個標簽 --> <tag> <!-- 定義標簽名 --> <name>helloWorld</name> <!-- 定義標簽處理類 --> <tag-class>org.lxh.taglib.HelloWorldTag</tag-class> <!-- 定義標簽體為空 --> <body-content>empty</body-content> </tag> </taglib>
二、七個動作指令
jsp:forward: 執行頁面轉向,將請求的處理轉發到下一個頁面。
jsp:param: 用於傳遞參數,必須與其他支持參數標簽一起使用。
jsp:include: 用於動態引入一個 JSP 頁面。
jsp:plugin: 用於下載 JavaBean 或 Applet 到客戶端執行。
jsp:useBean: 使用 JavaBean。
jsp:setProperty: 修改 JavaBean 實例的屬性值。
jsp:getProperty: 獲取 JavaBean 實例的屬性值。
1、forward指令
forward指令用於將頁面響應轉發給另外的頁面。既可以轉發給靜態的HTML頁面,也可以轉發到動態的JSP頁面,或者轉發到容器中的Servlet。
JSP的forward指令的格式如下。
對於JSP 1.0,使用如下語法:
<jsp:forward page="{relativeURL|<%=expression%>}"/>
對於JSP 1.1以上,可使用如下語法:
<jsp:forward page="{relativeURL|<%=expression%>}">
{<jsp:param.../>}
</jsp:forward>
第二種語法用於在轉發時增加額外的請求參數。增加的請求參數的值可以通過HttpServletRequest類的getParameter()方法獲取。
下面示例頁面使用了forward動作指令來轉發用戶請求。
<jsp:forward page="forward-result.jsp">
<jsp:param name="age" value="29"/>
</jsp:forward>
將客戶端請求轉發到forward-result.jsp頁面,轉發請求時增加了一個請求參數:參數名為age,參數值為29。
在forward-result.jsp頁面中,使用request內置對象(request內置對象是HttpServletRequest的實例)來獲取增加的請求參數值。
<!-- 使用request內置對象獲取age參數的值 -->
<%=request.getParameter("age")%>
執行forward指令轉發請求時,客戶端的請求參數不會丟失。
執行forward指令轉發請求時,用戶請求的地址沒有發生變化,但頁面內容完全變為被forward目標頁的內容。
2、include指令
include指令是一個動態include指令,也用於導入某個頁面,它不會導入被include頁面的編譯指令,僅僅將被導入頁面的body內容插入本頁面。
下面是include動作指令的語法格式:
<jsp:include page="{relativeURL│<%=expression%>}" flush="true"/>
或者
<jsp:include page="{relativeURL│<%=expression%>}" flush="true">
<jsp:param name="parameterName" value="patameterValue"/>
</jsp:include>
flush屬性用於指定輸出緩存是否轉移到被導入文件中。如果指定為true,則包含在被導入文件中;如果指定為false,則包含在原文件中。對於JSP 1.1舊版本,只能設置為false。
對於第二種語法格式,則可在被導入頁面中加入額外的請求參數。
下面頁面使用了動態導入語法來導入指定JSP頁面。
<!-- 使用動態include指令導入頁面 -->
<jsp:include page="scriptlet.jsp" />
上面頁面中粗體字代碼使用了動態導入語法來導入了scriptlet.jsp。表面上看,該頁面的執行效果與使用靜態include導入的頁面並沒有什么不同。但查看jsp-include.jsp頁面生成Servlet的源代碼,可以看到如下片段:
//使用頁面輸出流,生成HTML標簽內容
out.write("<!DOCTYPE HTML PUBLIC /"-//W3C//DTD HTML 4.0 Transitional//EN/ ">/r/n");
out.write("<HTML>/r/n");
out.write("<HEAD>/r/n");
out.write("<TITLE>jsp-include測試</TITLE>/r/n");
out.write("</HEAD>/r/n");
out.write("<BODY>/r/n");
//動態導入,直接引入scriptlet.jsp頁面
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response,
"scriptlet.jsp", out);
out.write("/r/n");
out.write("</BODY>/r/n");
out.write("</HTML>/r/n");
out.write("/r/n");
上面代碼片段中粗體字代碼顯示了動態導入的關鍵:動態導入只是使用一個include方法來插入目標頁面的內容,而不是將目標頁面完全融入本頁面中。
歸納起來,靜態導入和動態導入有如下兩點區別:
靜態導入是將被導入頁面的代碼完全融入,兩個頁面融合成一個整體Servlet;而動態導入則在Servlet中使用include方法來引入被導入頁面的內容。
靜態導入時被導入頁面的編譯指令會起作用;而動態導入時被導入頁面的編譯指令則失去作用,只是插入被導入頁面的body內容。
除此之外,執行include動態指令時,還可增加額外的請求參數。
在上面的JSP頁面中的粗體字代碼同樣使用jsp:include指令導入頁面,而且在jsp:include指令中還使用param指令傳入參數,該參數可以在forward-result.jsp頁面中使用request對象獲取。
3、UseBean指令
<jsp:useBean>標簽表示用來在JSP頁面中創建一個BEAN實例並指定它的名字以及作用范圍。
語法:
<jsp:useBean id="name" scope="page | request | session | application" typeSpec />
其中typeSpec有以下幾種可能的情況:
class="className" | class="className" type="typeName" | beanName="beanName" type="typeName" | type="typeName" |
注:
你必須使用class或type,而不能同時使用class和beanName。beanName表示Bean的名字,其形式為“a.b.c”。
4、GetProperty指令
<jsp:getProperty>標簽表示獲取BEAN的屬性的值並將之轉化為一個字符串,然后將其插入到輸出的頁面中。
語法:
<jsp:getProperty name="name" property="propertyName" />
注:
1、在使用<jsp:getProperty>之前,必須用<jsp:useBean>來創建它。
2、不能使用<jsp:getProperty>來檢索一個已經被索引了的屬性。
3、能夠和JavaBeans組件一起使用<jsp:getProperty>,但是不能與Enterprise Java Bean一起使用。
5、SetProperty指令
<jsp:setProperty>標簽表示用來設置Bean中的屬性值。
語法:
<jsp:setProperty name="beanName" prop_expr />
其中prop_expr有以下幾種可能的情形:
property="*" | property="propertyName" | property="propertyName" param="parameterName" | property="propertyName" value="propertyValue"
6、Plugin指令
<jsp:plugin>標簽表示執行一個applet或Bean,有可能的話還要下載一個Java插件用於執行它。
語法:
<jsp:plugin
type="bean | applet"
code="classFileName"
codebase="classFileDirectoryName"
[ name="instanceName" ]
[ archive="URIToArchive, ..." ]
[ align="bottom | top | middle | left | right" ]
[ height="displayPixels" ]
[ width="displayPixels" ]
[ hspace="leftRightPixels" ]
[ vspace="topBottomPixels" ]
[ jreversion="JREVersionNumber | 1.1" ]
[ nspluginurl="URLToPlugin" ]
[ iepluginurl="URLToPlugin" ] >
[ <jsp:params>
[ <jsp:param name="parameterName" value="{parameterValue | <%= expression %>}" /> ]+
</jsp:params> ]
[ <jsp:fallback> text message for user </jsp:fallback> ]
</jsp:plugin>
注:
<jsp:plugin>元素用於在瀏覽器中播放或顯示一個對象(典型的就是applet和Bean),而這種顯示需要在瀏覽器的java插件。
當Jsp文件被編譯,送往瀏覽器時,<jsp:plugin>元素將會根據瀏覽器的版本替換成<object>或者<embed>元素。注意,<object>用於HTML 4.0 ,<embed>用於HTML 3.2。
一般來說,<jsp:plugin>元素會指定對象是Applet還是Bean,同樣也會指定class的名字,還有位置,另外還會指定將從哪里下載這個Java插件。
7、param指令
param指令用於設置參數值,這個指令本身不能單獨使用,單獨的param沒有實際意義,param指令可與一下三個指令結合使用:
jsp:include
jsp:forward
jsp:plugin
param指令的語法格式如下:
<jsp:param name="paramName" value="paramValue">
三、jsp中其他要注意的問題
1、JSP的聲明(statement)
用來定義在產生的類文件中的類的屬性和方法(成員變量)。可聲明類(即是內部類)。
由於servlet是工作在多線程環境下,所以盡量不要在service方法體外聲明成員變量。
<%!.....%> //聲明時要加"!",屬於類成員,最先加載,可寫於任何位置;不加則是腳本的局部變量,必須調用前寫。
如: <%!String hello="Hello, World!";%> //變量的聲明
<%=hello%> //變量的調用
<%! private int counter=0; public int count(){ return ++counter;} %> //函數的聲明
<h1><%=count()%></h1> //函數的調用
聲明規則:
1) JSP中聲明的變量和方法對應於Servlet中的實例方法和實例變量。這些將被同時請求該頁面的所有用戶所共享;
2) 在使用變量或方法前須先定義(不是說聲明變量的位置在頁面中要處於使用變量的前面,而是指變量不聲明不能使用);
3) 聲明的變量或方法的作用域為當前頁面或包含的頁面;
4) 語句間以分號分隔。
2、JSP代碼段(Scriptlet)
<% java代碼 %>
是一段可以在處理請求時間執行的Java代碼。可以產生輸出,也可以是一些流程控制語句。
在代碼段中定義的變量為service方法中的局部變量。
1._jspService()中的局部代碼:
<% System.out.println("Hi,I like JSP."); %> //在控制台打印出,網頁上沒顯示
<% out.println("Hi,I like JSP."); %> //打印在網頁上
<% Connection conn=DriverManager.getConnection(); Statement st=conn.createStatement();
String sql="select * from users"; ResultSet rs=st.executeQuery(sql);
//……
%>
問:能否在JSP腳本里定義方法?
答:不能! //腳本相當於方法,不能在方法里定義方法
<%!public void helloworld(){}%> //可以聲明方法
<% public void helloworld(){}%> //編譯出錯;腳本不能定義方法
2.比較:
<%! int i=100;%> //成員變量
<% int i=101;%> //_jspService()方法中的局部變量
<%=i%> //同一文件里,局部變量優先
3.腳本小程序規則:
1) 你使用的腳本語言決定了腳本小程序的規則;
2) 語句間以分號分隔;
3) 可以使用默認的對象、import進的類、declaration聲明的方法和對象以及useBean tag中聲明的對象。
3、JSP表達式(expression)
<%=……%> // "="號
在JSP請求處理階段計算他的值,表達式生成的代碼是Service方法中的一個代碼片斷。
JSP對於聲明的處理:1、計算表達式的值
2、將值轉換成String
3、用out.println發送標簽;把數據輸出至頁面的當前位置
<%="Hello,JSP world!"%> //out.println("Hello,JSP world");
<%=name%> //<%!String name="GiGi";%> out.println(name);
<%=new java.util.Date()%> //out.println(new java.util.Date());
表達式規則:
1) 你使用的腳本語言決定了腳本小程序的規則;
2) 執行的順序為從左到右;
3) 分號不能用於表達式。
4、JSP中的注釋
1.java格式注釋
編譯器會忽略掉此類注釋中的內容(客戶端的源碼看不見)
<%-- JSP注釋;可多行 --%>
<%// java 單行注釋 %>
<%/* java multi lines comments */%>
<%/**java 特有的注釋*/%>
2.html風格注釋
編譯器會執行此類注釋中的代碼(客戶端的源碼看得見)
<!-- html風格注釋 --> 等價於out.println("<!-- html風格注釋 -->")
這種注釋方式不好的地方就是當頁面注釋信息太多的時候會增大服務器的負荷。
還有注釋信息需要在網絡上傳輸,從而降低效率;內部程序員的測試數據一般不能寫在這種注釋中,以免泄露。
5、JSP中的異常處理
一、try/catch/finally/throws/throw
// 在局部代碼里處理異常。
二、errorPage, isErrorPage
// 在整個頁面處理異常。
1.errorPage
形如: <%@page errorPage="error.jsp"%>
表示:需要錯誤處理的頁面
2.isErrorPage
形如: <%@page isErrorPage="true"%>
指示:錯誤頁面。其中,有一個隱式對象exception可用: <%=exception%>
產生(隱含)內建對象exception,可通過它獲得異常信息
<%=exception.getMessage() %> //把異常信息打印出來
三、聲明的方式處理異常
// 在整個應用處理異常。(范圍比前兩種更大)
1.配置: 在web.xml進行配置異常處理
…… <error-page>
<exception-type>java.lang.ArithmeticException</exception-type>
<location>/MathError.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404.jsp</location>
</error-page> ……
2.復習:Java中的異常——有2種
受查異常(Checked Exception)
非受查異常(Unchecked Exception) Java中的RuntimeException及其子類是不需要處理的(try/catch)
因為所有的RuntimeException總是可以通過優化代碼來避免,因此,這種異常被稱為"Unchecked Exception"。
3.思考:
三種異常處理方式同時啟動用,那個優先級高? 作用域越小,優先級越高。
注意:要使得頁面自動跳轉到錯誤頁面,必須關閉瀏覽器的"顯示友好HTTP錯誤信息"選項。
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException { /*只處理這兩種兼容的異常*/ …… }
安全的系統(企業級應用):
1.身份認證(合法用戶) --登錄
2.授權(靜態) --定義權限
3.訪問控制(動態) --比較
4.安全審計(日志) --修復bug (只有敏感的部門需要)
JAAS實現安全
JAAS——Java Authentication and Authorization Service
(Java認證(Authentication)與授權(Authorization)服務)
是Java EE規范之一,實現Java EE應用程序安全性的一個重要途徑
(要求:會使用,不必深入理解)