1.java web簡介
1.1靜態頁面與動態頁面
表現形式 | 所需技術 | |
靜態網頁 | 網頁內容固定,不會更新 | html,css |
動態網頁 | 網頁內容由程序動態顯示,自動更新 | html,css,DB,java/c#/php,javascript,xml,主流的動態網頁腳本(jsp,asp.net,php) |
1.2搭建java web開發環境
jdk1.7+tomcat7.0+MyEclipse10。關於MyEclipse的安裝和配置請參見http://blog.sina.com.cn/s/blog_907043b301016jtp.html。Tomcat服務器是Apache Jakarta的開源項目,是Jsp/Servlet容器。安裝Tomcat只需要解壓zip包到指定目錄即可。新建一個環境變量CATALINA_HOME,變量的值是Tomcat的根目錄D:\Program Files (x86)\apache-tomcat-7.0.57。全部的環境變量如下:
變量名 | 變量值 |
JAVA_HOME | D:\Program Files (x86)\Java\jdk1.7.0_40 |
Path | C:\Program Files\Microsoft SQL Server\100\DTS\Binn\;%JAVA_HOME%\bin;D:\Program Files\Sublime Text 3;D:\Program Files\MySQL\MySQL Utilities 1.3.6\ |
classpath | .;%JAVA_HOME%\lib\rt.jar;%JAVA_HOME%\lib\tools.jar; |
CATALINA_HOME | D:\Program Files (x86)\apache-tomcat-7.0.57 |
之后我們測試一下Tomcat的首頁:
進入Tomcat服務器根目錄下面的bin目錄,以管理員方式運行startup.bat,如果運行結果如下就表示Tomcat服務器啟動成功。
注意:不要關閉這個窗口(關閉窗口就意味着關閉了Tomcat服務器,將其最小化)。
在瀏覽器地址欄輸入http://localhost:8080/回車得到如下頁面:
1.3Tomcat目錄結構
1.4手工編寫第一個web應用程序
在項目文件夾中創建一個index.jsp:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>手工編寫的第一個java web項目</title> 6 </head> 7 <body> 8 <h1>這是手工編寫的第一個java web項目——jsp</h1> 9 <hr /> 10 </body> 11 </html>
在項目目錄中創建一個WEB-INF目錄拷貝/webapps/examples/WEB-INFO/web.xm到自己項目的/myJspProject/WEB-INFO中,在/myJspProject/WEB-INFO中創建兩個文件夾:classes和lib。最后的項目目錄應該是這樣:
測試:瀏覽器輸入:http://localhost:8080/myJspProject/index.jsp回車,運行結果如下:
解決方法:更改瀏覽器編碼為指定編碼:
1.5WEB-INF目錄詳解
該目錄是java web應用的安全目錄。所謂安全目錄就是客戶端無法訪問只有服務端可以訪問的目錄。其中web.xml是項目部署文件,classes目錄:存放*.class文件,lib目錄存放需要的jar包。例如:我們在WEB-INF中創建一個test.html,下面我們通過瀏覽器訪問:
web.xml配置文件可以配置歡迎頁面默認的歡迎頁面是項目下面的index.jsp,加入我們需要將項目下的haha.jsp,在/WEB-INF/web.xml的web-app標記中添加以下代碼:
1 <welcome-file-list> 2 <welcome-file>/haha.jsp</welcome-file> 3</welcome-file-list>
運行結果:
1.6實用Eclipse編寫第一個web應用程序
注意:如果要使用Eclipse編寫java web應用應該使用Eclipse的J2EE版本。並在Eclipse中配置Tomcat服務器Window-Preference-Server-Runtime Environment-Add,然后在WebContent目錄下新建jsp文件,按下Ctrl+F11(或者在項目中右鍵-Run On Server)就可以使用內置瀏覽器訪問建立的網站。
1.7用MyEclipse編寫第一個web應用程序
在新建項目之前首先在MyEclipse中配置jre和tomcat。步驟Window-Preference-Java-Install JREs-Add;Window-MyEclipse-Servers-Tomcat(注意設置tomcat的jre並將服務器設置為Enabled)。
接下來在MyEclipse中啟動Tomcat服務器:
測試首頁http://localhost:8080/證明Tomcat正常啟動,我們就可以在MyEclipse中啟動和發布Web應用程序了。
New一個WebProject會生成以下的目錄結構(默認在WebRoot目錄下有一個index.jsp)。
發布該WebApp。
1.8理解項目的虛擬路徑
該虛擬路徑是可以修改的項目上右鍵屬性-MyEclipse-Web。
重新部署,瀏覽器需要使用使用http://localhost:8080/hello/index.jsp訪問了。
1.7修改Tomcat默認端口
修改conf目錄下的server.xml的以下標記:
<Connector connectionTimeout="20000" port="8888" protocol="HTTP/1.1" redirectPort="8443"/>
2.jsp語法基礎
2.1jsp簡介
jsp的全名是Java Server Page,是一個簡化的Servlet設計,它實現了在java當中使用html標記。jsp是一種動態網頁技術,符合J2EE標准。jsp和Servlet一樣也是在服務器端執行的。
2.2常見動態網站開發技術對比
平台 | 特點 |
jsp | 跨平台,安全性高,適合開發大型的、企業級的Web應用、分布式應用(Hadoop)。例如:12306、10086.cn、網上銀行 |
asp.net | 簡單易學,安全性和跨平台性差 |
php | 簡單、高效、成本低、開發周期短,適合中小型企業的Web應用開發(LAMP) |
2.3jsp頁面元素簡介以及page指令
page指令語法:
<%@ page 屬性1="屬性值" 屬性2="屬性值1,屬性值2" 屬性n="屬性值n"%>
屬性 | 描述 | 默認值 |
language | jsp頁面所使用的腳本語言 | java |
import | 引用腳本語言中所要使用的類文件 | 無 |
contentType | 指定jsp頁面的編碼 | text/html,ISO-8859-1 |
新建一個java web工程默認的jsp頁面開頭有一個page指令:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
默認的編碼是ISO-8859-1,不支持中文,這里建議使用另一個屬性contentType。將第一行改為如下:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
這樣就支持中文了。
page指令的全部屬性如下:
1 <%@page 2 [language="Java"] 3 [extends="package.class"] // 指定JSP頁面編譯所產生的Java類所繼承的父類,或所實現的接口。 4 [import="package.class│package.*,…"] 5 [session="true│false"] 6 [buffer="none│8kb│size kb"] 7 [autoFlush="true│false"] 8 [isThreadSafe="true│false"] 9 [info="text"] 10 [errorPage="relativeURL"] // 指定錯誤處理頁面。因為JSP內建了異常機制支持,所以JSP可以不處理異常。 11 [contentType="mimeType[;charset=characterSet]"│"text/html;charSet=ISO8859-1"] 12 [isErrorPage="true│false"] // 設置本JSP頁面是否為錯誤處理程序。 13 %>
注意:除page指令中的import屬性之外,其他屬性均只能設置一次。
2.4jsp注釋
分為3種:html注釋,jsp注釋,jsp腳本注釋。語法:
1 <!-- html注釋 --> 2 <%-- jsp注釋 --%> 3 <% 4 /*這里是jsp腳本注釋 有兩種*/ 5 6 //單行注釋 7 8 /*多行注釋*/ 9 %>
例如:
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 12 <title>My JSP 'index.jsp' starting page</title> 13 <meta http-equiv="pragma" content="no-cache"> 14 <meta http-equiv="cache-control" content="no-cache"> 15 <meta http-equiv="expires" content="0"> 16 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 17 <meta http-equiv="description" content="This is my page"> 18 <!-- 19 <link rel="stylesheet" type="text/css" href="styles.css"> 20 --> 21 </head> 22 23 <body> 24 <h1>歡迎你</h1> 25 <!-- 這是html注釋,客戶端可可見 --> 26 <%-- 這是jsp注釋,客戶端不可見 --%> 27 <% 28 /*這里是jsp腳本注釋 29 有兩種*/ 30 //單行注釋 31 /*多行注釋*/ 32 %> 33 </body> 34 </html>
將項目部署到Tomcat,客戶端用瀏覽器查看源代碼:
2.5jsp腳本
在jsp頁面中執行的java代碼。語法:
<% java代碼 %>
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 12 <title>My JSP 'index.jsp' starting page</title> 13 <meta http-equiv="pragma" content="no-cache"> 14 <meta http-equiv="cache-control" content="no-cache"> 15 <meta http-equiv="expires" content="0"> 16 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 17 <meta http-equiv="description" content="This is my page"> 18 <!-- 19 <link rel="stylesheet" type="text/css" href="styles.css"> 20 --> 21 </head> 22 23 <body> 24 <h1>歡迎你</h1> 25 <hr> 26 <% 27 out.println("通過jsp內置對象out對象打印輸出"); 28 %> 29 </body> 30 </html>
2.6jsp聲明
jsp頁面中定義變量或者方法。語法:
<%! java代碼 %>
例如:
1 <%! 2 String s = "張三"; //聲明一個String類型的變量 3 int add(int x,int y){ //聲明一個返回值為int類型的方法 4 return x+y; 5 } 6 %>
2.7jsp表達式
jsp頁面中執行的表達式。語法(注意=緊挨着百分號,表達式末尾沒有分號):
<%=表達式 %>
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 12 <title>My JSP 'index.jsp' starting page</title> 13 <meta http-equiv="pragma" content="no-cache"> 14 <meta http-equiv="cache-control" content="no-cache"> 15 <meta http-equiv="expires" content="0"> 16 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 17 <meta http-equiv="description" content="This is my page"> 18 <!-- 19 <link rel="stylesheet" type="text/css" href="styles.css"> 20 --> 21 </head> 22 23 <body> 24 <h1>歡迎你</h1> 25 <hr> 26 <!-- 這是html注釋,客戶端可可見 --> 27 <%! 28 String s = "張三"; //聲明一個String類型的變量 29 int add(int x,int y){ //聲明一個返回值為int類型的方法 30 return x+y; 31 } 32 %> 33 你好:<%=s %><br> 34 令x=10,y=5,則x+y = <%=add(10, 5) %> 35 </body> 36 </html>
運行結果:
2.8jsp頁面生命周期
jspService()方法被調用來處理客戶端的請求。對每一個請求,JSP引擎創建一個新的線程來處理該請求。如果有多個客戶端同時請求你該jsp文件,則jsp引擎會創建多個線程(每一個客戶端請求對應一個線程)。以多線程的方式執行可以大大降低對系統的資源需求,提高系統的並發量以及縮短服務器的響應時間——但是同時要注意多線程的同步問題。由於該Servlet常駐內存,所以響應是非常快的。
當頁面沒有被訪問的時候work目錄下沒有相關的Servlet。如果頁面被訪問之后就會在work目錄的對應目錄生成響應的Servlet。如圖:
打開index_jsp.java會看到以下的初始化方法:
然后該Servlet常駐內存,創建線程處理每一個客戶端的請求。由每一個線程調用_jspService()方法來處理請求。
如果jsp頁面內容發生了改變,jsp引擎就需要重新編譯jsp頁面。我們修改index.jsp,用瀏覽器重新訪問,則:
2.9階段項目(九九乘法表)
1 <%@page import="java.io.IOException"%> 2 <%@ page language="java" import="java.util.*" 3 contentType="text/html; charset=utf-8"%> 4 <% 5 String path = request.getContextPath(); 6 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 7 %> 8 9 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 10 <html> 11 <head> 12 <base href="<%=basePath%>"> 13 14 <title>My JSP 'multiplicationTable.jsp' starting page</title> 15 16 <meta http-equiv="pragma" content="no-cache"> 17 <meta http-equiv="cache-control" content="no-cache"> 18 <meta http-equiv="expires" content="0"> 19 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 20 <meta http-equiv="description" content="This is my page"> 21 22 23 </head> 24 25 <body> 26 <h1>九九乘法表</h1> 27 <h2>表達式的方式打印乘法表</h2> 28 <%! 29 //聲明表達式 30 String printMultiTable(){ 31 StringBuilder s = new StringBuilder(); 32 for(int i=1;i<=9;i++){ 33 for(int j=1;j<=i;j++){ 34 s.append(i+" * "+j+" = "+i*j+"\t"); 35 } 36 s.append("<br />");//追加換行標記,注意不能使用\n 37 } 38 return s.toString(); 39 } 40 %> 41 <%=printMultiTable() //調用表達式 42 %> 43 44 <h2>使用腳本的方式打印九九乘法表</h2> 45 <%! 46 //jsp小腳本 47 void printMultiTable2(JspWriter out) throws IOException{ 48 StringBuilder s = new StringBuilder(); 49 for(int i=1;i<=9;i++){ 50 for(int j =1;j<=i;j++){ 51 s.append(i+" * "+j+" = "+i*j+"\t"); 52 } 53 s.append("<br />"); 54 } 55 out.println(s.toString()); 56 } 57 %> 58 59 <% 60 //調用腳本 61 printMultiTable2(out); 62 %> 63 </body> 64 </html>
運行結果:
3.jsp內置對象
3.1jsp內置對象簡介
JSP內置對象是Web容器創建的一組對象,不需要使用new關鍵字,JSP規范將它們完成了默認初始化(由JSP頁面對應Servlet的_jspService()方法來創建這些實例)。例如打印九九乘法表的jsp小腳本中使用的out對象就是jsp內置對象。
1 <%! 2 //jsp小腳本 3 void printMultiTable2(JspWriter out) throws IOException{ 4 StringBuilder s = new StringBuilder(); 5 for(int i=1;i<=9;i++){ 6 for(int j =1;j<=i;j++){ 7 s.append(i+" * "+j+" = "+i*j+"\t"); 8 } 9 s.append("<br />"); 10 } 11 out.println(s.toString());//這里的out就是jsp內置對象 12 } 13 %>
JSP一共有9個內置對象,其中常用的內置對象有5個,如圖所示:
3.3out對象
緩沖區(Buffer)就是內存中用來保存臨時數據的一塊區域。關於緩沖區有一個很形象的例子:比如我們煮好了飯放在鍋里,如果我們一粒一粒地來吃米飯就不知道吃到猴年馬月,拿來一個碗來一碗一碗吃,豈不快哉!這里的碗就充當了緩沖區的概念。其實IO的本質就是直接操作字節,但是效率太慢所以引入了緩沖區。
out對象是JspWriter類的一個實例——是向客戶端輸出內容的常用對象,該對象的常用方法:
1 void println(String message); // 向客戶端打印字符串 2 void clear(); // 清除緩沖區內容,如果在flush之后調用會拋出異常 3 void clearBuffer(); // 清除緩沖區內容,如果在flush之后調用不會拋出異常 4 void flush(); // 將緩沖區的內容輸出到客戶端 5 int getBufferSize(); // 返回緩沖區的大小(字節),默認是0 6 int getRemaining(); // 返回緩沖區可用容量 7 boolean isAutoFlush(); // 返回緩沖區滿的時候是自動清空還是拋出異常 8 void close(); // 關閉輸出流
下面是一個簡單的示例:
1 <h1>JSP的out內置對象</h1> 2 <% 3 //jsp腳本 4 out.println("<h2>靜夜思</h2>"); 5 out.println("李白<br /><br />"); 6 out.println("窗前明月光,<br />"); 7 out.println("疑是地上霜。<br />"); 8 out.println("舉頭望明月,<br />"); 9 out.println("低頭思故鄉。<hr />"); 10 %> 11 <!-- JSP表達式 --> 12 緩沖區大小:<%=out.getBufferSize() %>字節。<br /> 13 剩余緩沖區(可用緩沖區):<%=out.getRemaining() %>字節。<br /> 14 是否自動清空緩沖區:<%=out.isAutoFlush() %><br />
運行結果:
1 <h1>JSP的out內置對象</h1> 2 <% 3 //jsp腳本 4 out.println("<h2>靜夜思</h2>"); 5 out.println("李白<br /><br />"); 6 out.println("窗前明月光,<br />");
7 out.flush();//將緩沖區中的內容輸出到客戶端
8 out.println("疑是地上霜。<br />"); 9 out.println("舉頭望明月,<br />"); 10 out.println("低頭思故鄉。<hr />"); 11 %> 12 <!-- JSP表達式 --> 13 緩沖區大小:<%=out.getBufferSize() %>字節。<br /> 14 剩余緩沖區(可用緩沖區):<%=out.getRemaining() %>字節。<br /> 15 是否自動清空緩沖區:<%=out.isAutoFlush() %><br />
如果在第7行強制刷新緩沖區,則輸出的頁面不會有任何變化,僅僅是可用緩沖區的數量變多了而已【因為flush清空了緩沖區】
1 <% 2 //jsp腳本 3 out.println("<h2>靜夜思</h2>"); 4 out.println("李白<br /><br />"); 5 out.println("窗前明月光,<br />"); 6 7 out.flush();//將緩沖區中的內容輸出到客戶端 8 out.clear();//在flush之后調用clear,將會拋出異常 9 10 out.println("疑是地上霜。<br />"); 11 out.println("舉頭望明月,<br />"); 12 out.println("低頭思故鄉。<hr />"); 13 %>
運行結果:
1 <% 2 //jsp腳本 3 out.println("<h2>靜夜思</h2>"); 4 out.println("李白<br /><br />"); 5 out.println("窗前明月光,<br />"); 6 7 out.flush();//將緩沖區中的內容輸出到客戶端 8 out.clearBuffer();//在flush之后調用clearBuffer不會拋出異常 9 10 out.println("疑是地上霜。<br />"); 11 out.println("舉頭望明月,<br />"); 12 out.println("低頭思故鄉。<hr />"); 13 %>
運行結果:
3.4post和get提交方式的區別
<form name="regForm" action="處理腳本" method="提交方式[post|get]"></form>
- get:以明文的方式通過URL提交數據,提交的數據最大不超過2K。適合提交數據量小,安全性不高的數據【例如:搜索和查詢】
- post:將用戶提交的數據封裝在URL HEADER內。適合提交數據量大,安全性高的數據【例如:注冊、修改、上傳】 下面以用戶登錄的例子比較兩者的區別:
-
login.jsp頁面
1 請輸入用戶名和密碼: 2 <form name = "loginForm" action = "dologin.jsp" method = "get"> 3 用戶名:<input type="text" name="username" value="" maxlength = "15" /><br /> 4 密碼:<input type="password" name="password" maxlength="16" value="" /><br /> 5 <input type="submit" value="提交" /> 6 </form>
處理登錄的動作腳本dologin.jsp僅僅是顯示一句話"登錄成功"。
運行結果:
將用戶登錄表單的get方式改為post。
3.5request對象
客戶端的請求被封裝在request對象中,通過它才能了解到客戶端的需求,然后做出響應。它是HttpServletRequest對象的實例。request對象具有請求域,即:完成客戶端的請求之前,該對象一直有效。常用方法如下:
/* 兩個比較常用的方法 */
1 String getParameter(String name); // 返回name指定參數的參數值 2 String[] getParameterValues(String name); // 返回包含name的所有值的數組
3 void setAttribute(String,Object); // 存儲此請求中的屬性 4 String getContentType(); // 返回請求體的MIME類型 5 Stirng getProtocol(); // 返回請求所用的協議和版本號 6 String getServerName(); // 返回接受請求的服務器的主機名 7 int getServerPort(); // 返回服務器接受此請求所用的端口號 8 String getCharacterEncoding(); // 返回字符編碼方式【只能解決post方式的亂碼問題】 9 void setCharacterEncoding(); // 設置請求的字符編碼方式 10 int getContentLength(); // 返回請求體的長度(字節) 11 String getRemoteAddr(); // 返回發送此請求的客戶端IP 12 String getRealPath(String path); // 返回虛擬路徑的真實路徑 13 String request.getContextPath(); // 返回上下文路徑
以用戶注冊頁面為例(用戶在注冊頁reg.jsp完善信息后提交給request.jsp來處理):
用戶注冊頁reg.jsp
1 請輸入相關信息完成注冊<br /> 2 <form action="request.jsp" name="regForm" method="post"> 3 用戶名:<input type="text" name = "username" /><br /> 4 密碼:<input type="password" name = "password" /><br /> 5 愛好: 6 <input type="checkbox" name = "favorite" value="read"/>讀書 7 <input type="checkbox" name = "favorite" value="music"/>音樂 8 <input type="checkbox" name = "favorite" value="movie"/>電影 9 <input type="checkbox" name = "favorite" value="internet"/>上網<br /> 10 <input type="submit" value="提交" /> 11 </form>
處理用戶注冊頁的request.jsp
1 <h1>request內置對象</h1><br /> 2 3 用戶名:<%=request.getParameter("username") %><br /> 4 密碼:<%=request.getParameter("password") %><hr /> 5 愛好:<br /> 6 <% 7 String[]favorites = request.getParameterValues("favorite"); 8 for(String str:favorites){ 9 out.print(str+" "); 10 } 11 %>
運行結果:
但是以上頁面存在一個問題:假如我們在用戶名中輸入中文:
這時只要再request.jsp中設置字符集和reg.jsp一樣即可:
1 <h1>request內置對象</h1><br /> 2 <!-- 設置字符集,防止出現中文亂碼 --> 3 <% request.setCharacterEncoding("utf-8"); %>
4 用戶名:<%=request.getParameter("username") %><br /> 5 密碼:<%=request.getParameter("password") %><hr /> 6 愛好:<br /> 7 <% 8 String[]favorites = request.getParameterValues("favorite"); 9 for(String str:favorites){ 10 out.print(str+" "); 11 } 12 %>
除了可以使用表單的方式傳遞數據給request對象,也可以使用URL傳參的方式傳遞數據給request對象:
reg.jsp
<a href="request.jsp?username=root&password=toor&favorite=read&favorite=internet">測試URL傳參</a>
request.jsp(不變)
1 <h1>request內置對象</h1><br /> 2 <!-- 設置字符集,防止出現中文亂碼 --> 3 <% request.setCharacterEncoding("utf-8"); %> 4 用戶名:<%=request.getParameter("username") %><br /> 5 密碼:<%=request.getParameter("password") %><hr /> 6 愛好:<br /> 7 <% 8 String[]favorites; 9 if((favorites=request.getParameterValues("favorite"))!=null){ 10 for(String str:favorites){ 11 out.print(str+" "); 12 } 13 } 14 %>
運行結果:
如果我們在URL傳參中傳入了中文數據,同樣會出現亂碼問題:
<a href="request.jsp?username=你好&password=toor&favorite=read&favorite=internet">測試URL傳參</a>
此時通過request.setCharacterEncoding()方法就無法解決亂碼問題了【一個良好的解決方案是修改tomcat的配置文件server.xml】
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="utf-8"/>
向request對象中添加鍵值對:
reg.jsp:
1 請輸入相關信息完成注冊<br /> 2 <form action="request.jsp" name="regForm" method="post"> 3 用戶名:<input type="text" name = "username" /><br /> 4 密碼:<input type="password" name = "password" /><br /> 5 愛好: 6 <input type="checkbox" name = "favorite" value="read"/>讀書 7 <input type="checkbox" name = "favorite" value="music"/>音樂 8 <input type="checkbox" name = "favorite" value="movie"/>電影 9 <input type="checkbox" name = "favorite" value="internet"/>上網<br /> 10 <input type="submit" value="提交" /> 11 </form>
request.jsp
1 <h1>request內置對象</h1><br /> 2 <!-- 設置字符集,防止出現中文亂碼 --> 3 <% request.setCharacterEncoding("utf-8"); %> 4 <% 5 //在request對象中保存一個email屬性 6 request.setAttribute("email","io@gmail.com"); 7 8 %> 9 用戶名:<%=request.getParameter("username") %><br /> 10 密碼:<%=request.getParameter("password") %><hr /> 11 愛好:<br /> 12 <% 13 String[]favorites; 14 if((favorites=request.getParameterValues("favorite"))!=null){ 15 for(String str:favorites){ 16 out.print(str+" "); 17 } 18 } 19 %> 20 <br />郵箱:<%=request.getAttribute("email") %>
運行結果:
1 <h1>request內置對象</h1><br /> 2 <!-- 設置字符集,防止出現中文亂碼 --> 3 <% request.setCharacterEncoding("utf-8"); %> 4 <% 5 //在request對象中保存一個email屬性 6 request.setAttribute("email","io@gmail.com"); 7 8 %> 9 用戶名:<%=request.getParameter("username") %><br /> 10 密碼:<%=request.getParameter("password") %><hr /> 11 愛好:<br /> 12 <% 13 String[]favorites; 14 if((favorites=request.getParameterValues("favorite"))!=null){ 15 for(String str:favorites){ 16 out.print(str+" "); 17 } 18 } 19 %> 20 <br />郵箱:<%=request.getAttribute("email") %> <hr /> 21 請求體的MIME類型:<%=request.getContentType() %><br /> 22 請求體的協議及版本號:<%=request.getProtocol() %><br /> 23 服務器主機名:<%=request.getServerName() %><br /> 24 服務器端口號:<%=request.getServerPort() %><br /> 25 請求的字符編碼:<%=request.getCharacterEncoding() %><br /> 26 請求的文件長度:<%=request.getContentLength() %>字節<br /> 27 請求的客戶端的IP:<%=request.getRemoteAddr() %><br /> 28 請求的真實路徑:<%=request.getRealPath("request.jsp") %><br /> 29 請求的上下文路徑:<%=request.getContextPath() %>
運行結果:
3.6response對象
response對象包含了響應客戶請求的相關信息,但是在JSP中很少直接使用到它。它是HttpServletResponse類的實例。response對象具有頁面作用域——即:訪問一個頁面時,該頁面的response只對本次訪問有效,其他頁面的response對象對當前頁面無效。常用方法如下:
1 String getCharacterEncoding(); // 返回響應所用的編碼 2 void setContentType(); // 設置響應的MIME類型 3 PrintWriter getPrintWriter(); // 返回一個可以向客戶端輸出字符的對象【注意區別於out內置對象】 4 sendRedirect(String location); // 重定向客戶端的請求
response.jsp
1 <%@page import="java.io.PrintWriter"%> 2 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 3 <% 4 response.setContentType("text/html;charset=utf-8");//設置響應的MIME類型 5 6 out.println("<h1>response內置對象</h1><hr />"); 7 8 PrintWriter outer = response.getWriter();//獲得輸出流對象 9 outer.println("我是response對象生成的outter對象,在頁面中總是在前面輸出"); 10 %>
運行結果:
運行結果很是奇怪:明明out對象的輸出在代碼中位於前面。但是結果卻是PrintWriter的打印結果在前面,根本原因就是:PrintWriter的對象的輸出總是在最前面。如果我們需要讓標題先輸出,可以使用內置對象out的flush()方法強制刷新緩沖,向頁面輸出——保證標題出現在最前面。
請求重定向——當用戶請求response.jsp的時候馬上跳轉到login.jsp
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> <% response.sendRedirect("login.jsp"); // 請求重定向 %>
3.7請求重定向與請求轉發的區別
- 請求重定向:客戶端行為response.sendResponse(),從本質上講相當於兩次請求,前一次的請求對象不會保存,瀏覽器的URL欄會改變。
- 請求轉發:服務器行為request.getRequestDipatcher().forword(req,resp);是一次請求,轉發后請求對象會被保存,瀏覽器的URL不會改變。 例如還是用原來的例子:我們在reg.jsp中指定處理頁面的腳本是response.jsp而在response.jsp中我們重定向到request.jsp。觀察request.jsp的輸出:
如果我們在response.jsp中使用請求轉發:
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 //請求轉發 4 request.getRequestDispatcher("request.jsp").forward(request, response); 5 %>
運行結果:
3.8session對象
Session客戶端與服務器的一次會話。Web中的Session表示用戶在瀏覽某個網站時,從進入網站到瀏覽器關閉所經過的這段時間——也就是用戶瀏覽這個網站所花費的時間。在服務器的內存中保存着不同用戶的Session。
session對象的常用方法:
1 long getCreationTime(); // 返回session的創建時間 2 String getId(); // 返回session創建時JSP引擎為它設定的唯一ID號 3 Object setAttribute(String name,Object value); // 使用指定名稱將對象綁定到此會話 4 Object getAttribute(String name); // 返回此會話中的指定名稱綁定在一起的對象,如果沒有對象綁定在該名稱下則返回null 5 String[] getValueNames(); // 返回一個包含此Session所有可用屬性的數組 6 int getMaxInactiveInterval(); // 返回兩次請求間隔多長時間此session被取消【單位:秒】
sesseion_page1.jsp
1 <h1>session內置對象</h1> 2 <h2>session_page1.jsp</h2> 3 <% 4 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 5 String date = sdf.format(new Date(session.getCreationTime())); 6 out.print("session的創建時間:" + date); 7 session.setAttribute("username", "admin"); // 向session中設置屬性 8 %> 9 <br />Session的ID號:<%=session.getId() %><br /> 10 從session中獲取用戶名:<%=session.getAttribute("username") %> 11 12 <a href="session_page2.jsp" target="_blank">以新窗口的方式打開session_page2.jsp</a>
session_page2.jsp
1 <h2>session_page2.jsp</h2> 2 <% 3 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 4 String date = sdf.format(new Date(session.getCreationTime())); 5 out.print("session的創建時間:" + date); 6 %> 7 <br />Session的ID號:<%=session.getId() %><br /> 8 從session中獲取用戶名:<%=session.getAttribute("username") %>
運行結果:
可以獲取session中保存的屬性集合以及設置session的有效期:
1 <% 2 session.setMaxInactiveInterval(5);//設置session的有效期為5s 3 4 session.setAttribute("username", "admin"); // 向session中設置屬性 5 session.setAttribute("password", "123456"); 6 session.setAttribute("age", 16); 7 %> 8 9 <% 10 //獲取session中保存的屬性 11 String[]names=session.getValueNames(); 12 if(names!=null){ 13 for(String str:names){ 14 out.print(str+"\t"); 15 } 16 } 17 %>
Session的生命周期:
- 創建:當客戶端第一次訪問某個jsp頁面或者Servlet的時候,服務器會為當前會話創建一個SessionId。每次客戶端向服務器發送請求的時候都會攜帶此SessionId,服務端會對此SessionId進行檢驗——判斷是否屬於同一次會話。
- 活動階段:某次會話中通過超鏈接打開新的頁面;只要當前頁面沒有全部關閉,打開新的瀏覽器窗口訪問同一項目資源也屬於同一會話。注意:原有的會話仍然存在,只不過再也沒有客戶端會攜帶此sessionId交給服務器檢驗。——創建一個新的會話並不意味着原有會話消失,除非超時。
- 銷毀。
Tomcat如何進入后台管理系統?
修改/conf/tomcat-user.xml為以下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <tomcat-users> 3 <role rolename="admin-gui"/> 4 <role rolename="manager-gui"/> 5 <user username="admin" password="admin" roles="admin-gui,manager-gui"></user> 6 </tomcat-users>
在瀏覽器中打開session_page1.jsp然后通過session_page1.jsp的超鏈接打開session_page2.jsp在后台管理系統中查看:
如果我們在session創建之后調用session.invalidate()方法,例如:我們在session_page1.jsp中這樣寫:
1 <h1>session內置對象</h1> 2 <h2>session_page1.jsp</h2> 3 <% 4 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 5 String date = sdf.format(new Date(session.getCreationTime())); 6 out.print("session的創建時間:" + date); 7 10 session.setAttribute("username", "admin"); // 向session中設置屬性 11 session.setAttribute("password", "123456"); 12 session.setAttribute("age", 16); 13 %> 14 <br />Session的ID號:<%=session.getId() %><hr /> 15 session中保存的屬性有:<br /> 16 <% 17 //獲取session中保存的屬性 18 String[]names=session.getValueNames(); 19 if(names!=null){ 20 for(String str:names){ 21 out.print(str+"\t"); 22 } 23 } 24 session.invalidate();//銷毀session 25 %> 26 <a href = "session_page2.jsp" target = "_blank">點擊在新標簽頁中打開session_page2.jsp</a>
運行結果(不斷刷新瀏覽器):
Session默認session超時是30min設置session對象的超時有兩種方式:
- session.setMaxInactiveInterval(5);單位是秒
- 在web.xml中配置(單位是分鍾):
-
<session-config> <session-timeout>30</session-timeout> </session-config>
3.9application對象
- application對象實現了用戶間數據的共享,可以存放全局變量。
- application對象開始於服務器的啟動,結束於服務器的關閉。
- 在用戶的前后連接或者不同用戶之間,可以對統一個application對象的屬性進行操作。
- 在任何地方對application對象屬性的操作將會影響到其他用戶對此的訪問。
- application對象是ServletContext類的實例。 該對象的常用方法如下:
1 void setAttribute(String name,Object value); // 指定名稱將對象綁定到此會話 2 Object getAttribute(String name); // 返回此會話中和指定名稱綁定在一起的對象,如果沒有對象綁定在該名稱下則返回null 3 Enumeration getAttributeNames(); // 返回所有可用屬性名的枚舉 4 String getServerInfo(); // 返回JSP(Servlet)引擎名和版本號
1 <h1>application對象</h1> 2 <% 3 //在application中保存3個鍵值對 4 application.setAttribute("city", "北京"); 5 application.setAttribute("zipcode", "10000"); 6 application.setAttribute("email", "io@gmail.com"); 7 %> 8 所在城市:<%=application.getAttribute("city") %><hr> 9 application中存放的屬性有:<br> 10 <% 11 Enumeration attrs = application.getAttributeNames(); 12 while(attrs.hasMoreElements()){ 13 out.print(attrs.nextElement()+"<br>"); 14 } 15 %> 16 <hr> 17 jsp(Servlet)引擎:<%=application.getServerInfo() %><br>
運行效果:
3.10page對象
page對象就是指向當前jsp頁面本身(就好像類中的this),是java.lang.Object類的實例,常用方法和Object類的方法一致。例如它的toString()方法:
1 <h1>page內置對象</h1> 2 當前頁面的page對象的字符串描述:<br /> 3 <%=page.toString() %>
運行結果:
我們打開tomcat的work目錄(編譯生成的Servlet目錄)看到它的包結構是org.apache.jsp,在該目錄下有一系列的*_jsp.java和*_jsp.class文件。我們打開page_jsp.java發現類名就是page_jsp。
3.11pageContext對象
- 提供了對JSP頁面內所有的對象及名字空間的訪問。
- 可以訪問到本頁所在的session,也可以取本頁面所在的application的某一屬性值
- 相當於頁面中所有功能的集大成者。
- pageContext對象的本類名也叫pageContext。 常用方法:
1 JspWriter getOut(); // 返回當前客戶端響應被使用的JspWriter流(out) 2 HttpSession getSession(); // 返回當前頁中的HttpSession對象(session) 3 Object getPage(); // 返回當前頁面的Object對象(page) 4 ServletRequest getRequest(); // 返回當前頁面的ServletRequest對象(request) 5 ServletResponse getResponse(); // 返回當前頁面的ServletResponse對象(response) 6 void setAttribute(String name,Object value); // 設置屬性鍵值對 7 Object getAttribute(String name,int scope); // 在指定范圍內取屬性值 8 void forward(String relativeUrlPath); // 將當前頁面重定向到另一頁面 9 void include(String relativeUrlPath); // 在當前頁面包含另一文件
我們在session_page1.jsp中向session中設置了用戶名:
<% session.setAttribute("username", "admin"); %>
現在我們在pageContext.jsp中取出session中存儲的用戶名(注意要先打開session_page1.jsp):
<h1>pageContext內置對象</h1> 用戶名:<%=pageContext.getSession().getAttribute("username") %>
運行結果:
用pageContext實現頁面跳轉:
<% pageContext.forward("reg.jsp"); %>
運行結果:
新建一個include.jsp(頁面用於向頁面輸出當前的日期):
1 <%@page import="java.text.SimpleDateFormat"%> 2 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 3 <% 4 out.print(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())); 5 %>
下面我們在pageContext.jsp頁面中包含include.jsp:
1 <h1>pageContext內置對象</h1> 2 用戶名:<%=pageContext.getSession().getAttribute("username") %><hr> 3 4 <!-- 包含其他頁面 --> 5 <%pageContext.include("include.jsp"); %>
3.12config對象
該對象是一個在servlet初始化時,jsp引擎向它傳遞信息時使用的,此信息包含Servlet初始化時所用到的參數(鍵-值對)以及服務器的相關信息(通過傳遞一個ServletContext對象),常用方法:
1 ServletContext getServletContext(); // 返回服務器相關信息的ServletContext對象 2 String getInitParameter(String name);// 返回初始化參數的值 3 Enumeration getInitParameterNames(); // 返回Servlet初始化時所有需要參數的枚舉
3.13exception對象
該對象是一個異常對象,如果一個頁面在運行過程中出現了異常就會產生這個對象。如果一個JSP頁面需要應用此對象,就必須把isErrorPage設為true——否則無法編譯。它實際上是java.lang.Throwable的對象,常用方法:
1 String getMessage(); // 返回異常的描述信息 2 String toString(); // 返回關於異常的簡短描述信息 3 void printStackTrace(); // 顯示異常及其棧軌跡 4 Throwable FillInStackTrace(); // 重寫異常的執行棧軌跡
首先建立一個會出現異常的頁面exception_text.jsp(並指定處理異常的頁面):
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8" errorPage="exception.jsp"%> 2 <!-- 在errorPage中指定處理異常的頁面 --> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>這個頁面肯定會出現異常</title> 7 </head> 8 9 <body> 10 <h1>測試異常對象</h1><hr /> 11 <% 12 out.println(100/0);//肯定會拋出運行時異常【算術異常】 13 %> 14 </body> 15 </html>
然后建立處理異常的頁面exception.jsp:
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8" isErrorPage="true"%> <!-- isErrorPage設為true表示這是一個異常處理頁面 --> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'exception.jsp' starting page</title> </head> <body> <h1>Exception內置對象</h1> 異常消息是:<%=exception.getMessage() %><br> 異常的字符串描述:<%=exception.toString() %> </body> </html>
運行結果:
3.14階段案例——實現用戶登錄
這個案例比較簡單:用戶名和密碼都是admin(沒有使用數據庫),如果用戶名和密碼相符,則頁面跳轉到login_success.jsp【服務器內部轉發】,提示用戶登錄成功;如果用戶登錄失敗,則頁面跳轉到login_failure.jsp【請求重定向】,提示用戶登錄失敗。
整個項目的截圖:
項目地址:https://git.oschina.net/gaopengfei/JSPLogin.git
4.java beans
JavaBean是使用Java語言開發的一個可重用的組件,在JSP的開發中可以使用JavaBean減少重復的代碼,使整個JSP代碼的開發更加簡潔。JSP配置JavaBean使用有以下優點:
1. 將html和java大媽分離,為日后的維護提供了方便。
2. 可以利用JavaBean的優點將常用到的程序寫成JavaBean組件,節省開發時間。
簡單JavaBean有以下幾個名詞:
VO:值對象,存放所有的傳遞數據的操作上
POJO:簡單java對象
TO:傳輸對象,必須實現Serializable接口
WEB開發的標准目錄結構
實際上在WEB-INF中的lib和classes目錄就相當於一個默認的classpath(類執行時所需要的一個重要的環境屬性)。當Tomcat啟動之后,WEB-INF/lib和WEB-INF/classes都會自動配置到classpath中。
4.1java bean簡介與設計原則
Javabeans就是符合某種特定規范的的Java類。它的好處有:
一個Javabean要滿足4個規范:
例如以下的學生類就是一個Javabean:
1 /** 2 * 這是一個典型的JavaBean 3 */ 4 5 // 1.這是一個共有的類 6 public class Student { 7 // 2.屬性私有 8 private String name; 9 private int age; 10 11 // 3.有共有的無參構造 12 public Student() { 13 } 14 15 // 4.getter和setter 16 public String getName() { 17 return name; 18 } 19 20 public void setName(String name) { 21 this.name = name; 22 } 23 24 public int getAge() { 25 return age; 26 } 27 28 public void setAge(int age) { 29 this.age = age; 30 } 31 32 }
JavaBean有2種應用方式:
4.2jsp動作元素【運行時】
JSP動作元素(action elements),動作元素為請求處理階段提供信息。動作元素遵循XML元素的語法——有一個元素名的開始標簽,可以有屬性、可選的內容、與開始標簽匹配的結束標簽。
4.3普通方式應用java bean
像使用普通java類一樣,創建javabean實例。在MyEclipse項目的src目錄下新建類Users:
1 package org.po; 2 3 /** 4 * 用戶類-符合Javabean的實際原則 5 */ 6 public class Users { 7 private String username; 8 private String password; 9 10 public Users() { 11 12 } 13 14 public String getUsername() { 15 return username; 16 } 17 18 public void setUsername(String username) { 19 this.username = username; 20 } 21 22 public String getPassword() { 23 return password; 24 } 25 26 public void setPassword(String password) { 27 this.password = password; 28 } 29 30 }
下面我們在javabean_page1.jsp中使用以上的Javabean:
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!-- 使用import指令導入Javabean --> 3 <%@ page import="org.po.Users" %> 4 5 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 6 <html> 7 <head> 8 <title>JavaBeans范例</title> 9 </head> 10 11 <body> 12 <h1>使用普通方式創建Javabean的實例</h1> 13 <% 14 //使用普通方式創建JavaBean 15 Users user = new Users(); 16 user.setUsername("admin"); 17 user.setPassword("admin"); 18 %> 19 用戶名:<%=user.getUsername() %><br /> 20 密碼:<%=user.getPassword() %> 21 </body> 22 </html>
運行結果:
4.4useBean動作元素
<jsp:useBean>用於在jsp頁面中實例化或者在指定范圍內使用JavaBean。基本操作是首先使用id和作用域查找一個現有的對象,如果在指定的作用域中沒有找到具有指定id的對象,那么它會試圖使用其他屬性創建一個新實例。語法如下:
<jsp:useBean id="標示符" class="java類名" scope="作用域" />
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!-- 這里不需要page指令來導入User類了 --> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>使用useBean動作指令來使用JavaBean</title> 7 </head> 8 9 <body> 10 <h1>使用<jsp:useBean>動作指令來使用JavaBean</h1> 11 <!-- useBean指令 --> 12 <jsp:useBean id="myUsers" class="org.po.Users" scope="page"></jsp:useBean> 13 用戶名:<%=myUsers.getUsername() %><br/> 14 密碼:<%=myUsers.getPassword() %> 15 </body> 16 </html>
運行結果:
4.5setProperty
上一個jsp頁面中取得的用戶名和密碼都為null,原因就是我們使用僅僅是實例化了Users對象,並沒有為其成員變量執行屬性。當然你也可以使用setXXX來給已經實例化的JavaBean設置屬性,不過我更推薦使用setProperty指令。
<jsp:setProperty>的主要作用就是給已經實例化的JavaBean的屬性賦值,一共有4種形式:
1 <jsp:setProperty name="JavaBean實例名" property="*" /> <!-- 和表單關聯,全部屬性 --> 2 <jsp:setProperty name="JavaBean實例名" property="JavaBean屬性名" /> <!-- 和表單關聯,指定屬性 --> 3 <jsp:setProperty name="JavaBean實例名" property="JavaBean屬性名" value = "BeanValue" /> <!-- 手工設置 --> 4 <jsp:setProperty name="JavaBean實例名" property="propertyName" param="request對象中的參數名"/> <!-- 和request參數關聯,URL傳參 -->
方式一:【表單內容的自動全部匹配】
新建一個用戶登錄表單login.jsp:
1 <form action="dologin.jsp" method="post" name="loginForm"> 2 用戶名:<input type="text" name="username"/><br /> 3 密碼:<input type="password" name="password" /> 4 <input type="submit" value="提交" /> 5 </form>
處理用戶登錄的頁面dologin.jsp
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 <title>用戶登錄處理頁面</title> 12 </head> 13 14 <body> 15 16 <!-- 實例化javaBean對象 --> 17 <jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> 18 19 <h1>setPerpority動作元素</h1><hr /> 20 21 <!-- 根據表單自動匹配所有的屬性並設置 --> 22 <jsp:setProperty property="*" name="myUsers"/> 23 用戶名:<%=myUsers.getUsername() %><br> 24 密碼:<%=myUsers.getPassword() %> 25 26 </body> 27 </html>
運行結果:
這實際上以依靠表單中的name屬性來匹配javabean中的成員變量。例如:在用戶登錄表單中input標記的屬性有一個name="username",那么使用這種自動匹配的方式就會把這個username與javabean中的屬性挨個查找,如果找到了就為這個字段設定相應的值——換言之:表單中的name屬性要和要和javabean中的屬性對應相同。
方式二:部分匹配表單的屬性(dologin.jsp):
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 <title>用戶登錄處理頁面</title> 12 </head> 13 14 <body> 15 16 <!-- 實例化javaBean對象 --> 17 <jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> 18 19 <h1>setPerpority動作元素</h1><hr /> 20 21 <!-- 根據表單匹配部分屬性 --> 22 <jsp:setProperty property="username" name="myUsers"/> 23 用戶名:<%=myUsers.getUsername() %><br> 24 密碼:<%=myUsers.getPassword() %> 25 26 </body> 27 </html>
運行結果:
僅僅匹配了用戶名屬性,由於密碼屬性沒有匹配,所以為null。這種方式也要注意表單的name屬性要和javabean的屬性相同。
方式三:手工給javabean的屬性賦值——與表單無關(dologin.jsp):
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 <title>用戶登錄處理頁面</title> 12 </head> 13 14 <body> 15 16 <!-- 實例化javaBean對象 --> 17 <jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> 18 19 <h1>setPerpority動作元素</h1><hr /> 20 21 <!-- 與表單無關,通過手工給javabean的屬性賦值 --> 22 <jsp:setProperty property="username" name="myUsers" value="root"/> 23 <jsp:setProperty property="password" name="myUsers" value="123456"/> 24 用戶名:<%=myUsers.getUsername() %><br> 25 密碼:<%=myUsers.getPassword() %> 26 27 </body> 28 </html>
方式四(通過URL傳參的方式給javabean賦值):
login.jsp:
<a href="dologin.jsp?id=root&sn=123456">通過url傳參的方式給javabean的屬性賦值</a>
dologin.jsp:
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 <title>用戶登錄處理頁面</title> 12 </head> 13 14 <body> 15 16 <!-- 實例化javaBean對象 --> 17 <jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> 18 19 <h1>setPerpority動作元素</h1><hr /> 20 21 <!-- 通過URL傳參的方式給javabean屬性賦值--> 22 <jsp:setProperty property="username" name="myUsers" param="id"/> 23 <jsp:setProperty property="password" name="myUsers" param="sn"/> 24 用戶名:<%=myUsers.getUsername() %><br> 25 密碼:<%=myUsers.getPassword() %> 26 27 </body> 28 </html>
運行結果:
4.6getProperty
<jsp:getProperty>獲取指定JavaBean對象的屬性值【String類型】。語法:
<jsp:getProperty name="JavaBean實例名" property="屬性名" />
前面的例子已經通過URL傳遞參數的方式指定了javabean的屬性值,現在通過getProperty的方式獲得javabean的屬性值:
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 <title>用戶登錄處理頁面</title> 12 </head> 13 14 <body> 15 16 <!-- 實例化javaBean對象 --> 17 <jsp:useBean id="myUsers" class="org.po.Users"></jsp:useBean> 18 19 <h1>setPerpority動作元素</h1><hr /> 20 21 <!-- 通過URL傳參的方式給javabean屬性賦值--> 22 <jsp:setProperty property="username" name="myUsers" param="id"/> 23 <jsp:setProperty property="password" name="myUsers" param="sn"/> 24 25 <!-- 通過getter獲得javabean的屬性值 --> 26 <%-- 27 用戶名:<%=myUsers.getUsername() %><br> 28 密碼:<%=myUsers.getPassword() %> 29 --%> 30 31 <!-- 通過getProperty獲得javabean的屬性值 --> 32 用戶名:<jsp:getProperty property="username" name="myUsers"/><br /> 33 密碼:<jsp:getProperty property="password" name="myUsers"/> 34 </body> 35 </html>
運行結果:
4.7java bean的4個作用域范圍
使用useBean的scope屬性可以指定javabean的作用域。
1 page // 當前頁面有效,可以通過PageContext.getAttribute()獲得JavaBean對象。 2 request // 同一個請求有效,可通過HttpRequest.getAttibute()方法獲得JavaBean對象。 3 session // 同一個session有效,可通過HttpSession.getAttribute()方法獲得JavaBean對象。 4 application // 同一個application有效,可通過application.getAttribute()方法獲得JavaBean對象。
下面是一個簡單的測試4個作用范圍的示例:
dolog.jsp以URL傳參的方式為javabean指定屬性值:
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <html> 4 <head> 5 <title>用戶登錄處理頁面</title> 6 </head> 7 8 <body> 9 10 <!-- 實例化javaBean對象,並制定作用域為application --> 11 <jsp:useBean id="myUsers" class="org.po.Users" scope="application"></jsp:useBean> 12 13 <h1>setPerpority動作元素</h1><hr /> 14 15 <!-- 通過URL傳參的方式給javabean的屬性賦值--> 16 <jsp:setProperty property="username" name="myUsers" param="id"/> 17 <jsp:setProperty property="password" name="myUsers" param="sn"/> 18 19 <a href="test_scope.jsp">測試javabean的4個作用域范圍</a> 20 21 </body> 22 </html>
dologin.jsp中有一個跳轉鏈接test_scope.jsp用於跳轉頁面,下面是test_scope.jsp。
1 <%@page import="org.po.Users"%> 2 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 3 4 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 5 <html> 6 <head> 7 <title>檢驗useBean的4個作用域</title> 8 </head> 9 10 <body> 11 <h1>檢驗useBean的4個作用域</h1><hr> 12 13 <jsp:useBean id="myUsers" class="org.po.Users" scope="application"></jsp:useBean> 14 <!-- 通過getProperty獲取javabean屬性值 --> 15 <h2>用jsp動作元素獲取javabean的屬性值</h2> 16 用戶名:<jsp:getProperty property="username" name="myUsers"/><br /> 17 密碼:<jsp:getProperty property="password" name="myUsers"/><hr> 18 19 <!-- 通過內置對象獲取javabean的屬性值 --> 20 <h2>通過內置對象獲取javabean的屬性值</h2> 21 用戶名:<%=((Users)application.getAttribute("myUsers")).getUsername() %><br> 22 密碼:<%=((Users)application.getAttribute("myUsers")).getPassword() %> 23 </body> 24 </html>
按照上面的例子分別將scope換成session、request和page得到如下如下結果:javabean的作用域范圍從大到小依次是:application、session、request、page。
4.8JavaBean的刪除
JavaBean雖然使用了<jsp:useBean>標簽進行創建,但是其操作仍然依靠的是4種屬性范圍。如果一個JavaBean不再使用的話,則可以使用對應的removeAttribute()方法進行刪除。
1 pageContext.removeAttribute(JavaBean名稱) // 刪除page范圍內的JavaBean 2 request.removeAttribute(JavaBean名稱) // 刪除request范圍內的JavaBean 3 session.removeAttribute(JavaBean名稱) // 刪除session范圍內的JavaBean 4 application.removeAttribute(JavaBean名稱) // 刪除application范圍內的JavaBean

1 package org.gpf; 2 3 public class Count { 4 5 private int count = 0; 6 7 public Count() { 8 System.out.println("======== 一個新的Count實例產生了 ========"); 9 } 10 11 public int getCount() { 12 return ++count; 13 } 14 15 }

1 <%@ page language="java" contentType="text/html; charset=utf-8"%> 2 <!-- 創建JavaBean,指定作用域為session --> 3 <jsp:useBean id="c" class="org.gpf.Count" scope="session"></jsp:useBean> 4 count = <jsp:getProperty property="count" name="c"/> 5 <% 6 session.removeAttribute("c"); // 刪除javaBean 7 %>
我們本來設置的是session范圍內的JavaBean,刷新頁面不應該有新的JavaBean產生,但是我們在最后使用了session.removeAttribute()方法將創建的JavaBean刪除了,因而每次請求都會產生新的JavaBean。
4.9model 1(JSP+JavaBean)簡介
Model 1模型出現以前,整個Web應用幾乎全部由JSP頁面組成,JSP頁面接收處理客戶端請求,對請求處理后直接響應。這樣做的一個弊端就是:在界面層(JSP頁面)中充斥着大量的業務邏輯代碼和數據訪問層的代碼,Web程序的可擴展性和可維護性非常差。
JavaBean的出現可以使得可以在JSP頁面中調用JavaBean封裝的數據或者業務邏輯代碼,大大提升了程序的可維護性。下面的這張圖簡單描述了Model 1.
模型一體現了一種Web應用的分層架構。
4.9階段項目(使用Model 1完成用戶登錄)
首先建立一個用戶類Users(javabean):
1 package org.po; 2 3 /** 4 * 用戶類-javabean 5 */ 6 public class Users { 7 private String username; 8 private String passwordString; 9 10 public Users() { 11 } 12 13 public String getUsername() { 14 return username; 15 } 16 17 public void setUsername(String username) { 18 this.username = username; 19 } 20 21 public String getPasswordString() { 22 return passwordString; 23 } 24 25 public void setPasswordString(String passwordString) { 26 this.passwordString = passwordString; 27 } 28 29 }
下面編寫一個用戶業務邏輯類:
1 package org.dao; 2 3 import org.po.Users; 4 5 /** 6 * 用戶的業務邏輯類 7 */ 8 public class UsersDAO { 9 public boolean isUserLogin(Users users) { 10 return "admin".equals(users.getUsername()) 11 && "admin".equals(users.getPassword()); 12 } 13 }
業務邏輯處理的頁面dologin.jsp:
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!-- 引入實體類Users --> 4 <jsp:useBean id="loginUser" class="org.po.Users"></jsp:useBean> 5 <!-- 引入業務邏輯類UsersDAO --> 6 <jsp:useBean id="userDAO" class="org.dao.UsersDAO"></jsp:useBean> 7 8 <!-- 為javaBean loginUser設置屬性,使用表單自動設置全部的值 --> 9 <jsp:setProperty property="*" name="loginUser"/> 10 11 <!-- 調用業務邏輯代碼 --> 12 <% 13 request.setCharacterEncoding("utf-8");//防止中文亂碼 14 if(userDAO.isUserLogin(loginUser)){ 15 //如果用戶登錄成功則向session中設置用戶名和密碼 16 session.setAttribute("username", loginUser.getUsername()); 17 session.setAttribute("password", loginUser.getPassword()); 18 //請求轉發 19 request.getRequestDispatcher("login_success.jsp").forward(request, response); 20 }else{ 21 //重定向 22 response.sendRedirect("login_failure.jsp"); 23 } 24 %>
項目地址:https://git.oschina.net/gaopengfei/loginDemoByModel1.git
該項目中主要的修改的dologin.jsp在該頁面中沒有使用request對象直接從表單中讀出數據,而是從javabean中取出屬性,並且用戶合法性的判斷也放在了javabean中很好的體現了Web的分層思想(邏輯與頁面分離)。
5.jsp狀態管理
5.1http協議的無狀態性
http的無狀態性是指:當瀏覽器發送請求給服務器的時候,服務器響應客戶端的請求。但是當瀏覽器再次發送請求給服務器的時候,服務器並不知道它就是剛剛的那個瀏覽器。——服務器不會記住你。為了保存用戶的狀態有兩種機制:
5.2Cookie
Cookie是Web服務器保存在客戶端的一系列文本信息。
- Cookie的典型應用一:判斷注冊用戶是否已經登錄網站。保存用戶的登錄狀態,簡化登錄的手續(記住密碼)。
- Cookie的典型應用二:“購物車”的處理。
- Cookie的典型應用三:視頻網站播放記錄的存儲。
在JSP頁面中創建和使用Cookie
1 Cookie newCookie = new Cookie(String key,Object value); // 創建Cookie對象 2 response.add(newCookie); // 寫入Cookie對象 3 Cookie[] cookies = request.getCookies(); // 讀取Cookie對象
Cooike對象的常用方法:
1 void setMaxAge(int expiry); // 設置cookie的有效期【秒】 2 void setValue(String value);// 對已經實例化的cookie對象賦值 3 String getName(); // 獲得cookie的名稱 4 String getValue(); // 獲得cookie的值 5 int getMaxAge(); // 獲得cookie的有效時間【秒】
注意:以上方法中的setValue(String value)和String getValue()方法的返回值都是字符串類型——因為Cookie本質上就是一個字符串存儲在客戶端,無論對它存值還是取值都應該是字符串類型。
5.3案例:Cookie在登錄中的應用:
實現記憶用戶名和密碼的功能。
用戶登陸頁login.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>用戶登錄</title> 7 </head> 8 9 <body> 10 <% 11 /*獲得Cookie中保存的用戶名和密碼*/ 12 String username = ""; 13 String password = ""; 14 15 Cookie[]cookies = request.getCookies(); 16 if(cookies!=null&&cookies.length>0){ 17 for(Cookie c:cookies){ 18 if(c.getName().equals("username")){ 19 username = c.getValue(); 20 } 21 if(c.getName().equals("password")){ 22 password = c.getValue(); 23 } 24 } 25 } 26 %> 27 28 請輸入用戶名和密碼: 29 <br /> 30 <form action="dologin.jsp" name="loginForm" method="post"> 31 用戶名:<input type="text" name="username" value="<%= username%>" /><br /> 32 密碼:<input type="password" name="password" value="<%= password%>"><br /> 33 <input type="checkbox" checked="checked" name="isUseCookie"> 34 十天內記住我<br /> <input type="submit" value="登錄" /> 35 </form> 36 37 </body> 38 </html>
處理用戶登錄的頁面dologin.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>處理用戶登錄</title> 7 </head> 8 9 <body> 10 <h1>登錄成功!</h1> 11 <hr /> 12 <% 13 //判斷用戶是否選擇了記住密碼 14 String[] isUseCookie = request.getParameterValues("isUseCookie"); 15 if(isUseCookie!=null&&isUseCookie.length>0){ 16 /*把用戶名和密碼保存在Cookie對象中*/ 17 String username = request.getParameter("username"); 18 String password = request.getParameter("password"); 19 //創建2個Cookie對象 20 Cookie usernameCookie = new Cookie("username",username); 21 Cookie passwordCookie = new Cookie("password",password); 22 usernameCookie.setMaxAge(3600*24*10);//設置cookie生存期10天 23 passwordCookie.setMaxAge(3600*24*10); 24 25 //在客戶端保存Cookie對象,需要依賴response對象的addCookie方法 26 response.addCookie(usernameCookie); 27 response.addCookie(passwordCookie); 28 }else{ 29 /*使已經保存的cookie對象失效*/ 30 Cookie[]cookies = request.getCookies();//得到客戶端保存的cookie 31 if(cookies!=null&&cookies.length>0){ 32 //遍歷Cookie數組 33 for(Cookie c:cookies){ 34 if(c.getName().equals("username")||c.getName().equals("password")){ 35 c.setMaxAge(0);//設置Cookie的有效期是0,讓其馬上失效 36 response.addCookie(c);//重新向客戶端保存Cookie 37 } 38 } 39 } 40 } 41 %> 42 <a href="users.jsp">點擊查看用戶信息</a> 43 </body> 44 </html>
用戶信息顯示頁users.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>用戶信息顯示</title> 7 </head> 8 9 <body> 10 <h1>用戶信息</h1> 11 <hr /> 12 <% 13 /*獲得Cookie中保存的用戶名和密碼*/ 14 String username = ""; 15 String password = ""; 16 17 Cookie[]cookies = request.getCookies(); 18 if(cookies!=null&&cookies.length>0){ 19 for(Cookie c:cookies){ 20 if(c.getName().equals("username")){ 21 username = c.getValue(); 22 } 23 if(c.getName().equals("password")){ 24 password = c.getValue(); 25 } 26 } 27 } 28 %> 29 用戶名:<%=username %><br /> 密碼:<%=password %> 30 </body> 31 </html>
該項目一般情況下能夠正常運行,但是當我們輸入中文用戶名的時候,服務器會拋出一個500的錯誤。要解決這個問題就需要依靠java網絡包中的URLEncoder和URLDecoder,除此之外不要忘記了在每次使用request對象之前首先要設置request對象的編碼方式。完整的代碼如下:
login.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <%@page import="java.net.URLDecoder"%> 4 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 5 <html> 6 <head> 7 <title>用戶登錄</title> 8 </head> 9 10 <body> 11 <% 12 /*獲得Cookie中保存的用戶名和密碼*/ 13 String username = ""; 14 String password = ""; 15 16 request.setCharacterEncoding("utf-8"); 17 Cookie[]cookies = request.getCookies(); 18 if(cookies!=null&&cookies.length>0){ 19 for(Cookie c:cookies){ 20 if (c.getName().equals("username")) { 21 username = URLDecoder.decode(c.getValue(), "utf-8"); 22 } 23 if (c.getName().equals("password")) { 24 password = URLDecoder.decode(c.getValue(), "utf-8"); 25 } 26 } 27 } 28 %> 29 30 請輸入用戶名和密碼: 31 <br /> 32 <form action="dologin.jsp" name="loginForm" method="post"> 33 用戶名:<input type="text" name="username" value="<%= username%>" /><br /> 34 密碼:<input type="password" name="password" value="<%= password%>"><br /> 35 <input type="checkbox" checked="checked" name="isUseCookie"> 36 十天內記住我<br /> <input type="submit" value="登錄" /> 37 </form> 38 39 </body> 40 </html>
dologin.jsp
1 <%@page import="java.net.URLEncoder"%> 2 <%@ page language="java" import="java.util.*" 3 contentType="text/html; charset=utf-8"%> 4 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 5 <html> 6 <head> 7 <title>處理用戶登錄</title> 8 </head> 9 10 <body> 11 <h1>登錄成功!</h1> 12 <hr /> 13 <% 14 //判斷用戶是否選擇了記住密碼 15 request.setCharacterEncoding("utf-8"); 16 String[] isUseCookie = request.getParameterValues("isUseCookie"); 17 if (isUseCookie != null && isUseCookie.length > 0) { 18 /*把用戶名和密碼保存在Cookie對象中*/ 19 //得到登錄表單中的內容並編碼 20 String username = URLEncoder.encode( 21 request.getParameter("username"), "utf-8"); 22 String password = URLEncoder.encode( 23 request.getParameter("password"), "utf-8"); 24 //創建2個Cookie對象 25 Cookie usernameCookie = new Cookie("username", username); 26 Cookie passwordCookie = new Cookie("password", password); 27 usernameCookie.setMaxAge(3600 * 24 * 10);//設置cookie生存期10天 28 passwordCookie.setMaxAge(3600 * 24 * 10); 29 30 //在客戶端保存Cookie對象,需要依賴response對象的addCookie方法 31 response.addCookie(usernameCookie); 32 response.addCookie(passwordCookie); 33 } else { 34 /*使已經保存的cookie對象失效*/ 35 Cookie[] cookies = request.getCookies();//得到客戶端保存的cookie 36 if (cookies != null && cookies.length > 0) { 37 //遍歷Cookie數組 38 for (Cookie c : cookies) { 39 if (c.getName().equals("username") 40 || c.getName().equals("password")) { 41 c.setMaxAge(0);//設置Cookie的有效期是0,讓其馬上失效 42 response.addCookie(c);//重新向客戶端保存Cookie 43 } 44 } 45 } 46 } 47 %> 48 <a href="users.jsp">點擊查看用戶信息</a> 49 </body> 50 </html>
users.jsp
1 <%@page import="java.net.URLDecoder"%> 2 <%@ page language="java" import="java.util.*" 3 contentType="text/html; charset=utf-8"%> 4 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 5 <html> 6 <head> 7 <title>用戶信息顯示</title> 8 </head> 9 10 <body> 11 <h1>用戶信息</h1> 12 <hr /> 13 <% 14 /*獲得Cookie中保存的用戶名和密碼*/ 15 String username = ""; 16 String password = ""; 17 18 request.setCharacterEncoding("utf-8"); 19 Cookie[] cookies = request.getCookies(); 20 if (cookies != null && cookies.length > 0) { 21 for (Cookie c : cookies) { 22 if (c.getName().equals("username")) { 23 username = URLDecoder.decode(c.getValue(), "utf-8"); 24 } 25 if (c.getName().equals("password")) { 26 password = URLDecoder.decode(c.getValue(), "utf-8"); 27 } 28 } 29 } 30 %> 31 用戶名:<%=username%><br /> 密碼:<%=password%> 32 </body> 33 </html>
修正后的項目就支持中文用戶名了。Cookie與Session的區別是Cookie存放於瀏覽器中,瀏覽器關閉后再打開,已經保存的cookie還是存在。
5.4Session與Cookie對比
Session | Cookie | |
保存位置 | 服務端保存用戶信息 | 客戶端保存用戶信息 |
保存類型 | Session中保存的是Object類型 | Cookie中保存的是String類型 |
生命周期 | 會話結束,則存儲的數據銷毀 | Cookie可長期保存在客戶端 |
重要性 | 保存重要信息 | 保存不重要信息 |
6.jsp指令【編譯時】與動作【運行時】元素
6.1include指令(可以包含其他頁面)
語法:
<%@ include file="URL"%>
例如我們要在include_command.jsp中包含date.jsp的頁面——即:在include_command中顯示date.jsp的內容:
date.jsp
1 <%@page import="java.text.SimpleDateFormat"%> 2 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 3 <% 4 out.print(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())); 5 %>
include_command.jsp
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <html> 4 <head> 5 <title>在該頁面中使用include指令將剛剛寫的date.jsp包含進來</title> 6 </head> 7 8 <body> 9 <h1>在該頁面中使用include指令將剛剛寫的date.jsp包含進來</h1><hr /> 10 <%@include file="date.jsp" %> 11 </body> 12 </html>
運行結果:
6.2include動作
include動作實際上是JSP動作標簽,語法:
<jsp:include page="URL" flush="true|false" />
其中page屬性是需要包含的頁面的URL,而flush屬性制定了被包含的頁面是否從緩沖區中讀取。
demo:使用include動作在include_action.jsp中包含date.jsp
include_action.jsp
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <html> 4 <head> 5 <title>include動作</title> 6 </head> 7 8 <body> 9 <h1>在該頁面中使用include動作將剛剛寫的date.jsp包含進來</h1><hr /> 10 <jsp:include page="date.jsp" flush="false"></jsp:include> 11 </body> 12 </html>
使用include動作和include指令在jsp頁面的執行效果上沒有任何區別。
6.3include指令與include動作的區別
在Tomcat服務器的work目錄中刪除剛剛發布的工程:
先訪問include_command.jsp
work目錄生成以下內容:
打開include_005fcommand_jsp.java發現在它的源代碼中有date.jsp的源代碼:
out.print(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));
include指令主頁面和被包含的頁面轉換成了同一個Servlet。
在Tomcat的work目錄中刪除編譯生成的Servlet,訪問include_action.jsp生成以下文件:
打開include_005faction_jsp.java發現源代碼中並沒有包含date.jsp的源代碼,而是由下面的一條代碼將date.jsp的輸出結果包含到該jsp頁面:
// 該語句相當於調用date.jsp,並將date.jsp的輸出結果返回給該頁面 org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "date.jsp", out, false);
6.4forward動作
服務器內部轉發指令,語法:
1 <jsp:forward page="URL" /> 2 3 // 相當於 4 request.getRequestDispatcher("url").forward(request,response);
例如:在登陸頁中將用戶的表單處理交給forward_action.jsp頁面處理,forward_action.jsp將該請求通過forward動作轉發給users.jsp,users.jsp從request對象中取得用戶名和密碼給予顯示:
login.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>用戶登錄</title> 7 </head> 8 9 <body> 10 請輸入用戶名和密碼: 11 <br /> 12 <form action="forward_action.jsp" name="loginForm" method="post"> 13 用戶名:<input type="text" name="username" /><br /> 14 密碼:<input type="password" name="password" /><br /> 15 <input type="submit" value="登錄" /> 16 </form> 17 </body> 18 </html>
forward_action.jsp
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <html> 4 <head> 5 <title>forward動作</title> 6 </head> 7 8 <body> 9 <h1>該頁面處理用戶提交的表單信息</h1> 10 <h2>forward動作</h2> 11 <jsp:forward page="users.jsp"></jsp:forward> 12 <!-- 上面這條語句和下面的這條語句相當 --> 13 <%-- 14 request.getRequestDispatcher("users.jsp").forward(request, response); 15 --%> 16 </body> 17 </html>
users.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>用戶信息顯示</title> 7 </head> 8 9 <body> 10 <h1>用戶信息</h1> 11 <hr /> 12 <% 13 request.setCharacterEncoding("utf-8"); 14 15 String username = ""; 16 String password = ""; 17 if(request.getParameter("username")!=null){ 18 username = request.getParameter("username"); 19 } 20 if(request.getParameter("password")!=null){ 21 password = request.getParameter("password"); 22 } 23 %> 24 用戶名:<%=username %><br /> 密碼:<%=password %> 25 </body> 26 </html>
運行結果:
6.5param動作
語法:
1 <jsp:param name="參數名" value="參數名" /> 2 <!-- 該動作常常作為<jsp:forward>的子標簽,和它一起使用 -->
用戶將提交的表單交給dologin.jsp處理,dologin.jsp通過forward動作把請求轉發給users.jsp(並人為添加表單中沒有的內容:郵箱,修改表單中提交的用戶名為root),users.jsp通過request.getParamer()方法獲得用戶名、密碼、郵箱並予以顯示:
login.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>用戶登錄</title> 7 </head> 8 9 <body> 10 請輸入用戶名和密碼: 11 <br /> 12 <form action="dologin.jsp" name="loginForm" method="post"> 13 用戶名:<input type="text" name="username" /><br /> 14 密碼:<input type="password" name="password" /><br /> 15 <input type="submit" value="登錄" /> 16 </form> 17 </body> 18 </html>
dologin.jsp
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <jsp:forward page="users.jsp"> 3 <jsp:param value="io@gmail.com" name="email"/> 4 <jsp:param value="root" name="username"/> 5 </jsp:forward>
users.jsp
1 <%@ page language="java" import="java.util.*" 2 contentType="text/html; charset=utf-8"%> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <title>用戶信息顯示</title> 7 </head> 8 9 <body> 10 <h1>用戶信息</h1> 11 <hr /> 12 <% 13 request.setCharacterEncoding("utf-8"); 14 15 String username = ""; 16 String password = ""; 17 String email = ""; 18 if(request.getParameter("username")!=null){ 19 username = request.getParameter("username"); 20 } 21 if(request.getParameter("password")!=null){ 22 password = request.getParameter("password"); 23 } 24 if(request.getParameter("email")!=null){ 25 email = request.getParameter("email"); 26 } 27 %> 28 用戶名:<%=username %><br /> 密碼:<%=password %><br>郵箱:<%=email %> 29 </body> 30 </html>
效果圖:
7.jsp案例項目——商品瀏覽記錄的實現
該項目使用Model1(JSP+JavaBean)使用Cookie機制實現。該項目使用到了數據庫(數據庫中存放了商品表)。實現步驟如下:
DB-->JavaBean-->JSP。項目的目錄結構:
一、實現DBHelper類:
該類的主要作用是取得數據庫的連接並關閉相關資源。

1 package util; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.PreparedStatement; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 9 public class DBHelper { 10 private static final String DRIVER = "com.mysql.jdbc.Driver"; 11 private static final String URL = "jdbc:mysql://localhost:3306/shopping?useUnicode=true&characterEncoding=UTF-8"; 12 private static final String USER = "root"; 13 private static final String PASSWORD = "mysqladmin"; 14 15 private static Connection coon = null;// DB連接對象 16 17 /** 靜態代碼塊加載DB驅動 */ 18 static { 19 try { 20 Class.forName(DRIVER); 21 } catch (ClassNotFoundException e) { 22 e.printStackTrace(); 23 } 24 } 25 26 /** Singleton設計模式返回DB連接對象 */ 27 public static Connection getConnection() throws SQLException { 28 if (coon == null) { 29 coon = DriverManager.getConnection(URL, USER, PASSWORD); 30 return coon; 31 } 32 return coon; 33 } 34 35 /** 清理資源-關閉DB結果集、釋放語句對象 */ 36 public static void relsaseResource(ResultSet rs,PreparedStatement pstmt){ 37 // 釋放結果集 38 if (rs != null) { 39 try { 40 rs.close(); 41 rs = null; 42 } catch (SQLException e) { 43 e.printStackTrace(); 44 } 45 } 46 // 釋放語句對象 47 if (pstmt != null) { 48 try { 49 pstmt.close(); 50 pstmt = null; 51 } catch (SQLException e) { 52 e.printStackTrace(); 53 } 54 } 55 } 56 57 /** 測試DB連接 */ 58 public static void main(String[] args) { 59 try { 60 Connection connection = DBHelper.getConnection(); 61 if(connection!=null){ 62 System.out.println("數據庫連接成功!"); 63 }else { 64 System.out.println("數據庫連接異常!"); 65 } 66 } catch (SQLException e) { 67 e.printStackTrace(); 68 } 69 } 70 }
如果shopping數據庫沒有創建可能會拋出異常只需要執行:
create database shopping;
二、商品實體類的設計:
在創建實體類之前先建立好數據庫表:
數據庫腳本:items.sql

1 /* 2 Navicat MySQL Data Transfer 3 4 Source Server : MySQL50 5 Source Server Version : 50067 6 Source Host : localhost:3306 7 Source Database : shopping 8 9 Target Server Type : MYSQL 10 Target Server Version : 50067 11 File Encoding : 65001 12 13 Date: 2014-08-27 12:12:31 14 */ 15 16 SET FOREIGN_KEY_CHECKS=0; 17 18 -- ---------------------------- 19 -- Table structure for items 20 -- ---------------------------- 21 DROP TABLE IF EXISTS `items`; 22 CREATE TABLE `items` ( 23 `id` int(11) NOT NULL auto_increment, 24 `name` varchar(50) default NULL, 25 `city` varchar(50) default NULL, 26 `price` int(11) default NULL, 27 `number` int(11) default NULL, 28 `picture` varchar(500) default NULL, 29 PRIMARY KEY (`id`) 30 ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8; 31 32 -- ---------------------------- 33 -- Records of items 34 -- ---------------------------- 35 INSERT INTO `items` VALUES ('1', '沃特籃球鞋', '佛山', '180', '500', '001.jpg'); 36 INSERT INTO `items` VALUES ('2', '安踏運動鞋', '福州', '120', '800', '002.jpg'); 37 INSERT INTO `items` VALUES ('3', '耐克運動鞋', '廣州', '500', '1000', '003.jpg'); 38 INSERT INTO `items` VALUES ('4', '阿迪達斯T血衫', '上海', '388', '600', '004.jpg'); 39 INSERT INTO `items` VALUES ('5', '李寧文化衫', '廣州', '180', '900', '005.jpg'); 40 INSERT INTO `items` VALUES ('6', '小米3', '北京', '1999', '3000', '006.jpg'); 41 INSERT INTO `items` VALUES ('7', '小米2S', '北京', '1299', '1000', '007.jpg'); 42 INSERT INTO `items` VALUES ('8', 'thinkpad筆記本', '北京', '6999', '500', '008.jpg'); 43 INSERT INTO `items` VALUES ('9', 'dell筆記本', '北京', '3999', '500', '009.jpg'); 44 INSERT INTO `items` VALUES ('10', 'ipad5', '北京', '5999', '500', '010.jpg');
在MySQL中查詢:
建立實體類(Items):也就是javabean其屬性與DB中的各個字段一一對應。

1 package entity; 2 3 /** 4 * 商品類(與DB中的表名一致)-javabean 屬性和DB中表的字段完全一致 5 */ 6 public class Items { 7 private int id; 8 private String name; 9 private String city; 10 private int price; 11 private int number; 12 private String picture; 13 14 public Items() { 15 } 16 17 public int getId() { 18 return id; 19 } 20 21 public void setId(int id) { 22 this.id = id; 23 } 24 25 public String getName() { 26 return name; 27 } 28 29 public void setName(String name) { 30 this.name = name; 31 } 32 33 public String getCity() { 34 return city; 35 } 36 37 public void setCity(String city) { 38 this.city = city; 39 } 40 41 public int getPrice() { 42 return price; 43 } 44 45 public void setPrice(int price) { 46 this.price = price; 47 } 48 49 public int getNumber() { 50 return number; 51 } 52 53 public void setNumber(int number) { 54 this.number = number; 55 } 56 57 public String getPicture() { 58 return picture; 59 } 60 61 public void setPicture(String picture) { 62 this.picture = picture; 63 } 64 65 }
三、實現業務邏輯類(數據訪問層DAO)
該類需要完成的功能:
分析:
1.在index.jsp中我們需要展示所有的商品信息。——獲得所有商品
2.當用戶點擊任意一種商品后會將id通過URL傳遞給details.jsp,而在details.jsp中我們需要——根據id獲得對應商品。
3.根據Cookie傳入的字符串獲得最近瀏覽的5條記錄。
思考:如何將瀏覽記錄保存在Cookie中?
回答:只需要保存商品的ID即可,因為每個商品的ID是唯一的。
實現:把每次瀏覽的商品ID保存一個字符串中,將這個字符串保存在Cookie中,ID和ID之間用分隔符分隔,每次取出前5條記錄。
顯示所有商品的主頁index.jsp

1 <%@page import="entity.Items"%> 2 <%@page import="dao.ItemsDAO"%> 3 <%@ page language="java" import="java.util.*" 4 contentType="text/html; charset=utf-8"%> 5 <!-- 顯示所有的商品信息 --> 6 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 7 <html> 8 <head> 9 <title>歡迎光臨網上商城</title> 10 <style type="text/css"> 11 div { 12 float: left; 13 margin: 10px; 14 } 15 16 div dd { 17 margin: 0px; 18 font-size: 10pt; 19 } 20 21 div dd.dd_name { 22 color: blue; 23 } 24 25 div dd.dd_city { 26 color: #000; 27 } 28 </style> 29 </head> 30 31 <body> 32 <h1>商品展示</h1> 33 <hr> 34 <center> 35 <table width="750" height="60" cellpadding="0" cellspacing="0" 36 border="0"> 37 <tr> 38 <td> 39 <!-- 商品循環開始 --> 40 <% 41 ItemsDAO itemsDAO = new ItemsDAO(); 42 ArrayList<Items>list = itemsDAO.getAllItems(); 43 if(list!=null&&list.size()>0){ 44 //遍歷所有的商品 45 for(Items item:list){ 46 %> 47 <div> 48 <dl> 49 <dt> 50 <a href="details.jsp?id=<%=item.getId() %>"> 51 <img src="images/<%=item.getPicture() %>" width="120" height="90" border="1"/> 52 </a> 53 </dt> 54 <dd class="dd_name"><%=item.getName() %></dd> 55 <dd class="dd_city">產地:<%=item.getCity() %> 價格:¥<%=item.getPrice() %></dd> 56 </dl> 57 </div> 58 <% 59 } 60 } 61 %> 62 <!-- 商品循環結束 --> 63 </td> 64 </tr> 65 </table> 66 </center> 67 </body> 68 </html>
顯示商品詳細信息的details.jsp

1 <%@page import="entity.Items"%> 2 <%@page import="dao.ItemsDAO"%> 3 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 4 <!-- 顯示商品詳情,並在右側顯示商品的瀏覽記錄(最近5條記錄) --> 5 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 6 <html> 7 <head> 8 <title>歡迎光臨網上商城</title> 9 <style type="text/css"> 10 div{ 11 float:left; 12 margin-left: 30px; 13 margin-right:30px; 14 margin-top: 5px; 15 margin-bottom: 5px; 16 } 17 div dd{ 18 margin:0px; 19 font-size:10pt; 20 } 21 div dd.dd_name 22 { 23 color:blue; 24 } 25 div dd.dd_city 26 { 27 color:#000; 28 } 29 </style> 30 </head> 31 32 <body> 33 <h1>商品詳情</h1><hr> 34 <center> 35 <table width="750" height="60" cellpadding="0" cellspacing="0" border="0"> 36 <tr> 37 <!-- 商品詳細信息 --> 38 <% 39 Items item = new ItemsDAO().getItemsById(Integer.parseInt(request.getParameter("id"))); 40 if(item!=null){ 41 %> 42 <td width="70%" valign="top"> 43 <table> 44 <tr> 45 <td rowspan="4"><img src="images/<%=item.getPicture()%>" width="200" height="160"/></td> 46 </tr> 47 <tr> 48 <td><b><%=item.getName() %></b></td> 49 </tr> 50 <tr> 51 <td>產地:<%=item.getCity() %></td> 52 </tr> 53 <tr> 54 <td>價格:¥<font color="red"><b><%=item.getPrice() %></b></font></td> 55 </tr> 56 </table> 57 </td> 58 <% 59 } 60 %> 61 <!-- 取得Cookie --> 62 <% 63 String list = ""; 64 // 從客戶端獲得Cookie集合 65 Cookie[]cookies = request.getCookies(); 66 if(cookies!=null&&cookies.length>0){ 67 for(Cookie c:cookies){ 68 if(c.getName().equals("ListViewCookie")){ 69 list = c.getValue(); 70 } 71 72 String[] arr = list.split(","); 73 // 相同商品只在瀏覽記錄中存放一次 74 if(Arrays.binarySearch(arr, request.getParameter("id"))<0){ 75 list += request.getParameter("id") + ","; 76 } 77 // 如果瀏覽記錄超過1000條,則清空Cookie 78 if(arr!=null&&arr.length>1000){ 79 list = "";// 清零-置空串 80 } 81 Cookie cookie = new Cookie("ListViewCookie",list); 82 response.addCookie(cookie); 83 } 84 } 85 %> 86 87 <!-- 瀏覽過的商品 --> 88 <td width="30%" bgcolor="#EEE" align="center"> 89 <br /><b>您瀏覽過的商品</b><br /> 90 <!-- 循環開始 --> 91 <% 92 ArrayList<Items>itemsList = new ItemsDAO().getViewList(list); 93 if(itemsList!=null&&itemsList.size()>0){ 94 for(Items i:itemsList){ 95 %> 96 <div> 97 <dl> 98 <dt><img src="images/<%=i.getPicture() %>" width="120" height="90" border="1" /></dt> 99 <dd class="dd_name"><%=i.getName() %></dd> 100 <dd class="dd_city">產地:<%=i.getCity() %> 價格:¥<%=i.getPrice() %></dd> 101 </dl> 102 </div> 103 <% 104 } 105 } 106 %> 107 <!-- 循環結束 --> 108 </td> 109 </tr> 110 </table> 111 </center> 112 </body> 113 </html>
主業務邏輯類ItemsDAO

1 package dao; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.util.ArrayList; 8 import java.util.Arrays; 9 10 import util.DBHelper; 11 12 import entity.Items; 13 14 /** 15 * 商品的業務邏輯類 16 */ 17 public class ItemsDAO { 18 /** 獲得所有的商品信息 */ 19 public ArrayList<Items> getAllItems() { 20 ArrayList<Items> itemsList = new ArrayList<Items>();// 商品集合 21 22 Connection coon = null; 23 PreparedStatement pstmt = null; 24 ResultSet rs = null; 25 26 try { 27 coon = DBHelper.getConnection(); 28 String sql = "select * from items;";// sql語句 29 pstmt = coon.prepareStatement(sql); 30 rs = pstmt.executeQuery(); 31 32 while (rs.next()) { 33 Items items = new Items(); 34 setItemsAttributes(rs, items);//為實體類【商品】設置屬性【根據DB中的相關字段】 35 itemsList.add(items);// 把1個商品加入集合 36 } 37 return itemsList; 38 } catch (Exception e) { 39 e.printStackTrace(); 40 return null; 41 } finally { 42 DBHelper.relsaseResource(rs, pstmt); 43 } 44 } 45 46 /** 根據數據庫的結果集設置實體類的屬性 */ 47 private void setItemsAttributes(ResultSet rs, Items items) 48 throws SQLException { 49 items.setId(rs.getInt("id")); 50 items.setName(rs.getString("name")); 51 items.setCity(rs.getString("city")); 52 items.setPrice(rs.getInt("price")); 53 items.setNumber(rs.getInt("number")); 54 items.setPicture(rs.getString("picture")); 55 } 56 57 /** 根據商品的id獲得商品資料 */ 58 public Items getItemsById(int id) { 59 Connection coon = null; 60 PreparedStatement pstmt = null; 61 ResultSet rs = null; 62 63 try { 64 coon = DBHelper.getConnection(); 65 String sql = "select * from items where id=?;"; 66 pstmt = coon.prepareStatement(sql); 67 pstmt.setInt(1, id); 68 rs = pstmt.executeQuery(); 69 70 if (rs.next()) { 71 Items items = new Items(); 72 setItemsAttributes(rs, items); 73 return items; 74 } else { 75 return null; 76 } 77 } catch (Exception e) { 78 e.printStackTrace(); 79 return null; 80 } finally { 81 DBHelper.relsaseResource(rs, pstmt); 82 } 83 } 84 85 /**獲取最近瀏覽的前5條商品信息*/ 86 public ArrayList<Items>getViewList(String list){ 87 ArrayList<Items>itemsList = new ArrayList<Items>(); 88 int iCount = 5;//每次返回5條 89 if (list!=null&&list.length()>0) { 90 String[]temp=list.split(","); 91 //顯示最近瀏覽過的商品——倒序得到Cookie中保存的ID 92 if (temp.length>=iCount) { 93 System.out.println("瀏覽記錄大於等於5條"); 94 System.out.println(Arrays.toString(temp)); 95 for(int i = temp.length-1;i>=temp.length-iCount;i--){ 96 itemsList.add(getItemsById(Integer.parseInt(temp[i]))); 97 } 98 }else { 99 System.out.println("瀏覽記錄小於5條"); 100 System.out.println(Arrays.toString(temp)); 101 for(int i = temp.length-1;i>=0;i--){ 102 itemsList.add(getItemsById(Integer.parseInt(temp[i]))); 103 } 104 } 105 return itemsList; 106 }else { 107 return null; 108 } 109 } 110 }
項目展示:(項目地址:https://git.oschina.net/gaopengfei/JSPLogin.git)
Tips:
解決中文亂碼:
1)在執行獲取請求參數前設置編碼:
request.setCharacterEncoding(“漢字編碼”);
2)轉換字符編碼:
1 //獲取原始的請求參數值 2 String rawName = request.getParameter("name"); 3 //將請求參數值使用ISO-8859-1字符串分解成字節數組 4 byte[] rawBytes = rawName.getBytes("ISO-8859-1"); 5 //將字節數組重新編碼成字符串 6 String name = new String(rawBytes , "gb2312");
3)獲取請求參數同時轉換編碼:
request.getParameter(“name”).getBytes ("ISO-8859-1");