JSP筆記javascript
Tomcatservercss
port:html
port就是指的某一個程序網絡入口,Tomcat的初始化port爲:8080;前端
port的個數:256*256=65536個;java
通常常見協議的缺省port爲:mysql
http 80web
smtp 25sql
pop3 110數據庫
ftp 23apache
https 443
port佔用查看命令:dos中執行netstat –ano命令
conf目錄下的server.xml配置文件裏的<Connectorport="8080"protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/> 標籤用於配置Tomcatserver的port
環境變量配置:
新增一個JAVA_HOME環境變量配置爲JDK的根文件夾。因爲Tomcatserver是java寫的所有也需要JVM來執行
文件共享:<Context />標籤中的reloadable=」true」屬性,設置爲true 表示僅僅要文件被改動。就又一次公佈並載入(不建議使用)(context.xml配置文件裏)
第一種:
tomcatserver會本身主動掃描webapps這個文件夾。因此咱們要共享的web應用文件夾。就可以放在此文件夾下,也就是說Tomcatserverwebapp文件夾中的web應用,外界可以直接訪問。不需要配置
另一種:
也可以改動conf文件夾下的server.xml配置文件。在Host標籤中加入<Contextpath="/hello" docBase="E:/Demo/Test" />標籤。hello爲E:/Demo/Test映射;也就是說hello是一個虛擬的web應用文件夾地址,而E:/Demo/Test是咱們的實際web應用文件夾地址,假設path=」」;就表示是缺省的;
第三種:
也可以在\conf\Catalina\localhost\文件夾如下 建立一個隨意文件名稱的.xml文件,在裏面配置<ContextdocBase="E:/Demo/Test" />標籤。那麼這個web的虛擬文件夾就是這個文件的名稱。實際的文件夾地址就是docBase所配置的地址。但實際的文件夾地址不能是\webapps這個文件夾中的,此方法的優勢是配置好了不需要從新啓動;假設這個.xml文件名稱爲ROOT.xml就表示缺省默認的;這種關係稱爲映射關係
Tomcat的文件夾層次結構:
bin文件夾 存放的是啓動和關閉Tomcat的腳步文件
conf 存放Tomcatserver的各類配置文件
lib 存放Tomcatserver的支持jar包
logs 存放Tomcatserver的日誌文件
temp 存放Tomcat執行時產生的暫時文件
webapps web應用所在文件夾,即可以供外界訪問的web資源的存放文件夾
work Tomcat的工做文件夾
Tomcatserver的應用管理:(適用於Tomcat7.0,Tomcat6.0角色名用的是manager)
改動\conf文件裏的tomcat-users.xml位置文件。 在<tomcat-users> </tomcat-users>標籤中加上<rolerolename="manager-gui"/><user username="admin"password="admin" roles="manager-gui"/>
manager-gui是角色 而後在設置帳號和password
而後在Tomcat首頁打開ManagerApp輸入帳號password進入應用管理頁面。Start 開始。Stop 中止;Reload 重裝;Undeploy 卸載
當咱們打開www.mybaidu.com時,執行E:\practice\JSP\practice1\Test\Demo\1.html文件
第一步:
設置Demoproject下WEB-INF中的web.xml配置文件;將1.html設置爲缺省頁。<welcome-file-list> <welcome-file>1.html</welcome-file> </welcome-file-list>
第二步:
配置\conf中server.xml文件;在後面加入<Contextpath="" docBase="E:\practice\JSP\practice1\Test\Demo" />;將path設置爲」」表示缺省
第三步:
設置port爲80port(僅僅限定HTTP協議);配置\conf中server.xml文件;<Connectorport="8080" protocol="HTTP/1.1"connectionTimeout="20000" redirectPort="8443" />; port=」80」
新建一個主機
在conf目錄下的server.xml配置文件裏。加入一個<Hostname=」主機名」 appBase=」webproject位置」> <Contextpath=」映射路徑」 docBase=」訪問路徑」 /> </Host>
Tomcat體系結構
Tomcatserver啓動時會啓動一個Server服務,Server服務啓動時會啓動多個鏈接器(Connector);
瀏覽器發送一個HTTP協議而後找到Server服務中與HTTP協議相應的鏈接器(Connector)。而後經過鏈接器(Connector)找到引擎(Engine)。而後再找主機。主機再找WEB應用。最後找到WEB資源
配置https鏈接器
webproject(Project)
注意:每次建立一個新的project都需公佈到Tomcatserver。改動代碼後需又一次部署(Redeploy)一下
war包
jar –vcf 新的文件名稱.war 要打包的目錄;用此命令將webproject打包爲war包
當war包的文件。放入Tomcat的webapps目錄中時,會本身主動解壓
文件夾層次結構
Myeclipse 2013 project文件夾結構
project文件夾 |
存放java文件的文件夾 |
存放於java文件相應的class文件 |
存放Web應用文件夾 |
存放jar包 |
Web應用的配置文件 |
索引頁 |
Tomcatproject物理結構
web.xml 配置文件
web.xml僅僅能放在WEB-INF這個目錄中;
設置項目的缺省首頁(不能直接將servlet映射爲首頁,假設首頁必須要通過serlvet轉發,那麼可以在index.jsp文件裏轉發至serlvet,再經過此servlet轉發至首頁)
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
在web應用中註冊com.scxh.Test這個serlvet。並取名爲Test
<servlet>
<servlet-name>Test</servlet-name>
<servlet-class>com.scxh.Test</servlet-class>
</servlet>
當出現此連接到此project後,出現.com的後綴就交給Test這個類處理。
<servlet-mapping>
<servlet-name>Test</servlet-name>
<url-pattern>*.com</url-pattern>//不能在前面加字符了,如:<url-pattern>aa/*.com</url-pattern>;這樣也是不一樣意的
</servlet-mapping>
這個Test可以映射成多個URL(僞靜態)這就是servlet的映射,如:
<servlet-mapping>
<servlet-name>Test</servlet-name>
<url-pattern>/*</url-pattern>//表示‘/‘後面不管跟什麼都訪問這個類(aa/*;這樣的方式也可以)
</servlet-mapping>
通常Servlet在配置映射時,不要將url-pattern標籤配置爲」/」;因爲’/’通配符表示所有缺省的(找不到的資源)都訪問此Servlet;在Conf/web.xml文件裏。系統向所有的Servlet都配置了此’/’。當咱們訪問所有靜態資源(如直接訪問webproject中的1.html)都會被系統配的’/’ 所捕獲到,都是訪問的系統自帶的Servlet對象;而後再經過這個對象去找你web應用中是否有這個靜態資源。有就直接返回,沒有就拋404異常(假設咱們再設置url-pattern標籤配置爲’/’就會覆蓋系統的設置,當咱們再訪問有些靜態資源時就訪問不到)
修飾符的優先級(誰最符合就匹配誰。’*’號越在前面,優先級越低)
HTTP協議
請求頭(client與server交互)
client連上server後,向server請求某個web資源,稱之爲client向server發生了一個HTTP請求,一個完整的HTTP請求包含:一個請求行、若干請求頭、及實體內容
演示樣例:
GET/books/java.html HTTP/1.1 請求行(請求行用於描寫敘述client的請求方式、請求的資源名稱、及使用的HTTP協議版本號)
請求方式:GET(缺省,特色:顯示提交,在URL地址後附帶的參數是有限的,其數據容量一般不能超過1K; 提交數據顯示在url欄中」?」後面);
POST(通常用於表單的提交,則可以再請求的實體內容中向發武器發送數據,傳送的數據量無限制。隱式提交);
Accept:*/*
Accept-Language:en-ue
Connection:Keep-Alive 多個請求頭(用於描寫敘述client請求的主機
Host:localhost ,及client的一些環境信息等)
Referer:thp://localhost/links.asp
User-Agent:Mozilla/4.0
Accept-Encoding:gzip,deflate
Hello world! 實體內容(一般是表單所提交的內容)
請求頭的描寫敘述:
Accept: 告訴server,客戶機所支持的數據類型,如:text/html,image/*; 就是說支持text的html,支持所有的image; 如爲:*/*;表示什麼都支持
Accept-Charset:ISO-8859-1 告訴server,客戶機所採用的編碼格式
Accept-Encoding:gzip,compress 告訴server,客戶機所支持的壓縮格式
Accept-Language: en-us,zh-cn 告訴server,客戶機的語言環境
Host:localhost:8080 客戶機要訪問的主機
If-Modified-Since:Tue,11 jul 2000 18:23:51 GMT 告訴server,資源的緩存時間; 咱們上一次瀏覽此網頁的時間,發送給server,server用於比對原站點的更新時間,假設原站點在此時間內更新過數據,就又一次返回數據,如沒有更新就直接用客戶機中緩存內的所緩存的網頁
Referer:www.baidu.com 告訴server,他是從哪一個資源來訪問server的; 這裏表示這是從百度訪問的該資源(可以用於防盜鏈)
User-Agent:Mozilla/4.0(compatible;MSIE 5.5;Windows NT 5.0) 告訴server,客戶機的軟件環境(系統,及瀏覽器版本號等)
Cookie: 客戶機經過這個可以向server帶數據
Connection:close/Keep-Alive 告訴server,當這個請求完成後,是保持鏈接仍是關閉鏈接; close是關閉鏈接, Keep-Alive是保持鏈接
Date:Tue,11 jul 2000 18:23:51 GMT 告訴server,客戶機當前的時間
UA-CPU:X86 告訴server。windows的執行平臺,如64位,32位等
If-None-Match:W/* 182-1303717494234
響應頭(server與client交互)
一個http對應表明server向client回送的數據它包含:一個狀態行、若干消息頭、以及實體內容
演示樣例:
HTTP/1.1 200 OK 狀態行(狀態行用於描寫敘述server對請求的處理結果)
Server:Microsoft-IIS/5.0
Date:Tue,11 jul 2000 18:23:51 GMT 多個消息頭(消息頭用於描寫敘述server的基本信息,
Content-Length:2291 以及數據的描寫敘述,server經過這寫數據的描寫敘述信息,
Content-Type:text/html 可以通知client怎樣處理等一會它(server)回送的數據。)
Cache-control:private
<html>
<body></body> 實體內容(一般是網頁代碼)
</html>
響應頭的描寫敘述
HTTP/1.1 200 OK 描寫敘述返回數據的協議版本、狀態碼、緣由敘述
狀態碼用於表示server對請求的處理結果,它是一個三位的十進制數.對應狀態碼分爲5類,如:
100~199 表示成功接收請求,要求client繼續提交下一次請求才幹完畢整個處理過程
200~299 表示成功接收請求並已完畢整個處理過程, 常用200
300~399 爲完畢請求,客戶需進一步細化請求.好比,請求的資源已經移動到一個新的地址,常用30二、30七、304(307和304表示server的資源位作改動。可以用客戶機上的緩存,302表示去訪問Location: 這個頭所返回的地址)
400~499 client的請求有誤,常用404(404表示server沒有這個資源;403表示server拒絕你訪問這個資源,請檢查是否有權限訪問)
500~599 server端出現錯誤, 常用500,(如同一個response對象同一時候使用字符流和字節流時server就會返回此異常,因爲它們是相互排斥的)
Location:www.baidu.com (請求重定向)這個頭配合302狀態碼使用,用於告訴client應該轉到的地址
Server:Apache-Coyote/1.1 server經過這個頭,告訴clientserver的類型
Content-Encoding:gzip,compress server經過這個頭,告訴client數據的壓縮格式
Content-Length: server經過這個頭,告訴client壓縮後數據的大小
Content-Type:text/html; charset=UTF-8 server經過這個頭。告訴client數據的類型(如要查詢要返回的文件類型的具體請查詢conf/web.xml)
Last-Modified:Tue,11 jul 2000 18:23:51 GMT 告訴client,當前資源最後公佈時間
Refresh:1;[url=’http://www.baidu.com’] 告訴瀏覽器隔多長時間刷新一次[假設在分號後面加上一個地址,表示隔多久時間跳轉到這個站點]
Content-Disposition:attachment;filename=文件名稱 告訴瀏覽器經過這個頭,告訴瀏覽器下面載方式打開
Transfer-Encoding:chunked 告訴瀏覽器文件的傳送格式
Set-Cookie:ss=Q0=5Lb_nQ;path=/search
Etag:W/」7777-1242234904000」 緩存相關的頭
Expires:-1 告訴瀏覽器,這個資源的緩存時間。-1或0表示不緩存; 假設要緩存,設置爲要緩存到的時間
也是控制瀏覽器要不要緩存數據(瀏覽器的內核不一樣。因此響應頭比較多)假設要緩存, 設置爲要緩存到的時間 |
Cache-Control:no-cache
Pragma:no-cache
Connection:close/Keep-Alive 告訴瀏覽器請求完成後是否斷開鏈接
Date:Tue,11 jul 2000 18:23:51 GMT 告訴瀏覽器。server當前的時間
斷點下載
請求頭
Range頭指示server僅僅傳輸一部分Web資源.這個頭可以用來實現斷點續傳功能,Range字段可以經過三種格式設置要傳輸的字節範圍:
Range: bytes=1000-2000
表示請求server發送這個資源中1000字節到2000字節之間的內容
Range: bytes=1000-
表示請求server發送這個資源中1000字節之後的所有內容
Range: bytes=1000
表示請求server發送這個資源中最後1000字節的內容
響應頭
Accept-Ranges: 這個頭告訴瀏覽器這個資源是否支持Ranges(斷點下載) 支持返回:bytes 不支持返回:none
Content-Ranges:1000-3000/5000指定了返回的Web資源的字節範圍。
這裏表示返回的數據是1000-3000字節之間的內容。這個資源總共同擁有5000個字節
JSP中的路徑(java中的路徑相對於src文件夾)
訪問資源:
訪問時,假設從client訪問server的資源: /project名/要訪問的資源路徑; 通常在前端超連接時,後臺從定向時使用
訪問時,假設直接在server端直接訪問資源: /要訪問的資源路徑; 通常在server端轉發時使用;
server訪問文件:
在web開發中假設要獲取到用到一個文件的位置。僅僅實用絕對路徑,比方建立文件流、文件對象、等。
經過 類載入器的 getClassLoader().getResource("相對路徑").getPath();返回此文件的絕對路徑;或者用getClassLoader().getResourceAsStream("相對路徑」) 直接將文件載入到內存中。並返回一個字節輸入流對象。
這裏的相對路徑,相對的是WEB-INF/classes 文件夾。
假設一個要在一個jar包中訪問這個jar包中的文件,那麼僅僅能將此文件載入到內存中,經過字節輸入流對象來獲取此文件的數據。因爲文件在jar包中,不能獲取到絕對路徑。
Servlet開發
Servlet生命週期:
l Servlet通常僅僅會在第一次訪問時建立,而後一直停留在內存中,直到server中止纔會被釋放(或者這個web應用被刪除時)。每產生一次請求都會建立一個request和response對象但它們的生命週期很是短,當請求和響應完畢後就銷燬。但Servlet對象僅僅會建立一個
l server啓動時建立servlet,需加上<load-on-startup>標籤(通常不會這樣用的。載入框架文件時就是這樣用的)
l servlet中儘可能使用局部變量。假設要用static全局變量。並要對static變量進行改動的話。就要考慮線程安全問題了,解決線程安全需用線程同步代碼塊,同步代碼塊中的代碼不能太多,否則會影響性能
<servlet>
<servlet-name>ServletDemo1</servlet-name>
<servlet-class>cn.webapp.ServletDemo1</servlet-class>
<!--增長了下面的標記,此servlet就會在server啓動時建立-->
<load-on-startup>1</load-on-startup>//假設在web.xml配置文件裏在當前Servlet註冊標籤中加上了當前標籤。就會在server啓動時建立當前的Servlet對象,並調用Servlet對象的init方法;中間這個1表示假設有多個Servlet對象要在server啓動時載入時,這個值將控制Servlet的載入順序;越小優先級越高
</servlet>
l Servlet建立的時候會調用init方法結束時會調destroy方法
新建一個Servlet類它必須繼承HttpServlet類或GenericServlet類
繼承GenericServlet類需重寫service(ServletRequestarg0, ServletResponse arg1)這種方法
繼承HttpServlet類需重寫doGet或doPost方法是(改動模板路徑:MyEclipse\plugins\com.genuitec.eclipse.wizards_11.0.0.me201303311935.jar中templates\Servlet.java文件裏改動doGet和doPost)
地址的使用方法(最好都在前面加上/)
當給瀏覽器用時,是相對於當前的主機(要在最前面加上項目名稱)
當給server用時, 是相對於當前的web應用
線程安全
//線程安全
/*SingleThreadModel接口是一個空的接口;假設實現了此接口就表示此對象時一個線程安全的對象;
當一個用戶訪問當前的Servlet後,下一個用戶訪問當前的Servlet時發現Servlet實用戶,
就會建立出一個新的Servlet對象,這也是在一個server中建立兩個Servlet的方法
(此方法不推薦使用;太消耗資源,因爲Servlet建立後僅僅有關閉server纔會銷燬)
*/
public class ThreadSafe extends HttpServlet implements SingleThreadModel{
public int i = 0;
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
i++;
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
System.out.println(i);
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
Servlet中的六大對象
ServletConfig(servlet配置對象及servlet對象域)
用於封裝Servlet的配置信息
可以在project下的web.xml配置文件裏,註冊Servlet標籤中加上:<init-param>標籤;
<servlet>
<servlet-name>ConfigDemo</servlet-name>
<servlet-class>cn.java.ConfigDemo</servlet-class>
<init-param><!—此標籤的做用域僅僅能在cn.java.ConfigDemo這個servlet中-->
<param-name>name1</param-name> <!-- 這是至關於經過"name1"可以映射到"張三" -->
<param-value>張三</param-value>
</init-param>
<init-param>
<param-name>name2</param-name> <!-- 這是至關於經過"name2"可以映射到"李四" -->
<param-value>李四</param-value>
</init-param>
</servlet>
獲取方法
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//獲取ServletConfig對象中的值(此值需要在web.xml中註冊此servlet標籤中加)
public class Test extends HttpServlet {
//privateServletConfig config;//方式一所需定義的全局變量
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//第一種方式獲取值
//輸出config對象中name1和name2中所映射的值
// System.out.println(config.getInitParameter("name1"));
// System.out.println(config.getInitParameter("name2"));
/*
//另一種方式獲取(用另一種方式時不能重寫init(ServletConfig config)方法)
//先經過this.getServletConfig()獲取到config對象,再經過getInitParameter("name1")獲取到name1和name2中所映射的值
System.out.println(this.getServletConfig().getInitParameter("name1"));
System.out.println(this.getServletConfig().getInitParameter("name2"));
*/
/*
//第三種方式,使用迭代(獲取全部的config值)
ServletConfigconfig1 = this.getServletConfig();//獲取config對象
Enumeration en =config1.getInitParameterNames();//獲取config1對象中所有的name。並返回一個列表
while(en.hasMoreElements()){//用這個列表的迭代器進行遍歷
String key = (String) en.nextElement();
String value =this.getServletConfig().getInitParameter(key);
System.out.println(value);
}
*/
//第四種直接獲取
System.out.println(this.getInitParameter("name1"));
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
/*
//第一種方式:重寫HttpServet父類GenericServlet中的init(ServletConfig config)方法
//此方法會在server啓動時調用,並將config對象傳入進來
@Override
public void init(ServletConfig config)throws ServletException {//獲取config對象
// TODO Auto-generated method stub
this.config=config;
}
*/
}
servletContext(表明一個web應用(域))此對象的生命週期爲:當web應用公佈時建立,卸載web應用時銷燬。假設在servlet中要對servletContext域對象中的key值進行更改的話,需考慮線程安全問題
ServletContext.removeAttribute(Stringkey); 刪除servletContext對象域中鍵值的映射關係,否則此鍵值會一直存活到server關閉。會浪費資源
WEB容器在啓動時,它會爲每個WEB應用程序都建立一個相應的ServletContext對象。它表明」當前web應用」。
SerletConfig對象中維護了ServletContext對象的引用,開發者在編寫servlet時,可以經過servletConfig.getServletContext方法得到ServletContext對象
由於一個WEB應用中的所有Servlet共享同一個ServletContext對象,因此多個Servlet可以經過servletContext對象實現數據共享(ServletContext對象一般也被稱之爲context域(域就是一個範圍,Context域是一個應用範圍的域)對象)
n 獲取web應用的參數(配置數據庫)
<context-param><!—這是配置整個web應用初始化參數的標籤;一個web應用中可以有多個初始化參數的標籤-->
<param-name>name</param-name>
<param-value>haoren</param-value>
</context-param>
Stringsex = this.getServletContext().getInitParameter("name");//取出context-param標籤中的值。也可以用this.getServletContext().getInitParameterNames();方法獲取全部的key;而後再迭代取出value(在ServletConfig對象中有講過取出value的方式)
System.out.print(sex);
n 數據共享
ServeltDemo1:
this.getServletContext().setAttribute("address", "chengdu");//存入servletContext對象中
ServeltDemo2:
String address =(String) this.getServletContext().getAttribute("address");//取出servletContext對象中的值
n 利用ServletContext對象讀取源文件
讀取properties文件
//第一種方式
ServletContext servletContext = this.getServletContext();//獲取到servletContext對象
InputStream inStream = servletContext.getResourceAsStream("/config.properties");//把/config.properties資源做爲一個輸入流返回(這裏"/" 路徑指的是webproject的根文件夾)
//假設此處的路徑寫的是相對路徑,相對的是Tomcat的bin文件夾,因爲Tomcat的是在此文件夾中啓動的
Properties properties = new Properties();//建立一個properties對象(properties對象中底層是用map集合維護的)
properties.load(inStream);//properties對象中提供了load方法,從流中獲取properties文件的值
String name = properties.getProperty("name");//獲取properties對象中key是name的value
String url = properties.getProperty("url");//獲取properties對象中key是url的value
System.out.println(name+" "+url);
//另一種方式(經過硬盤上的絕對路徑訪問config.properties文件),此方法可以獲取到文件的名稱
ServletContext servletContext = this.getServletContext();//獲取到servletContext對象
String path = servletContext.getRealPath("/config.properties");//會返回這個路徑在硬盤上的絕對路徑;這裏會返回
//E:\practice\JSP\practice2\Tomcat7.0\webapps\servletContext\config.properties這個路徑
String fileName = path.substring(path.lastIndexOf("\\")+1);//這樣可以獲取到文件的名稱;在下載時需要用到
System.out.println("文件名爲:"+fileName);//打印這個文件名
FileInputStream in = new FileInputStream(path);//有了絕對路徑後就可以建立 文件字節流了
Properties properties = new Properties();//建立一個properties對象(properties對象中底層是用map集合維護的)
properties.load(in);//properties對象中提供了load方法,從流中獲取properties文件的值
in.close();//關閉流
String name = properties.getProperty("name");//獲取properties對象中key是name的value
String url = properties.getProperty("url");//獲取properties對象中key是url的value
System.out.println(name+" "+url);
//第三種方式(經過一個普通類載入config.properties文件的方式)
//假設在一個普通類中用ServletContext對象來獲取;就是前臺應用耦合了後臺應用;因此咱們應該避免這個使用方法
//在一個普通類中讀取config.properties文件;
public class Test4 {
public static void print() throws IOException {
/*
//此方法獲取的輸入流(in)不能實時更新(因爲是類載入器載入器僅僅載入一次到內存中)
InputStream in = Test4.class.getClassLoader().getResourceAsStream("../../config.properties");
//這裏相對的是Tomcat中webapps\servletContext\WEB-INF\classes這個目錄(假設用類載入器載入文件,這個文件不能太大)
*/
//此方法獲取的輸入流(in)可以實現實時更新(此方法是獲得絕對路徑後在建立輸出流)
URL url1 = Test4.class.getClassLoader().getResource("../../config.properties");//獲取到這個文件的URL
String path = url1.getPath();//經過url獲取到這個config.properties文件的絕對路徑
InputStream in = new FileInputStream(path);//經過這個絕對路徑來建立輸入流
Properties properties = new Properties();//建立一個Properties對象
properties.load(in);//properties對象中提供了load方法,從流中獲取properties文件的值
in.close();//關閉流
String name = properties.getProperty("name");//獲取properties對象中key是name的value
String url = properties.getProperty("url");//獲取properties對象中key是url的value
System.out.println("Test4:"+name+" "+url);
}
public static void main(String[] args) {
try {
Test4.print();
} catch (IOException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
}
request(請求頭對象)用於獲取client傳入的數據
獲取表單中的值:
//獲取表單提交的數據
public class Test extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)//request:請求;response:響應
throws ServletException, IOException{
response.setContentType("text/html; charser=utf-8");//設置瀏覽器的編碼格式
response.setCharacterEncoding("utf-8");//設置響應回傳數據的編碼格式
request.setCharacterEncoding("utf-8");//設置請求數據的編碼格式
//獲取表單的參數,除多選框外,其餘表單的取值方式都同樣
String username = request.getParameter("username");
String password = request.getParameter("password");
String sex = request.getParameter("sex");
String country = request.getParameter("country");
String [] enjoy = request.getParameterValues("enjoy");//多選框用getParameterValues(String arg0)這種方法,並會返回一個String []的數組
String remark = request.getParameter("remark");
PrintWriter out = response.getWriter();//獲取到響應對象的輸出流
out.print("你的用戶名爲:"+username+";你的密碼爲:"+password+";你的性別爲:"+sex+";你的國籍爲:"+country+";備註爲:"+remark);
out.println(";你的愛好爲:");
for(int i=0; i<enjoy.length; i++){
out.print(enjoy[i]+" ");
}
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
//解決提交表單方式爲get時出現的亂碼問題
public class getMessyCodeextends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException{
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
String text = request.getParameter("text");//獲取提交表單的參數
String temp = new String(text.getBytes("ISO8859-1"),"UTF-8");//將ISO8859-1的參數,轉換爲字節數組後,再傳入一個新的字符串,並又一次指定編碼格式
response.getWriter().print("你提交的爲:"+temp);//將數據傳送給響應對象的輸出流
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException{
doGet(request, response);
}
}
經過request對象實現轉發:
/*轉發
請求重定向與轉發的差異
請求重定向: 是向client發回一個網址,讓瀏覽器又一次去訪問(向server發出了兩次請求;並且網址會變。
重定向完畢後。再刷新,刷新的是重定向後的網頁)
轉發: 是經過server直接轉發到某一個網址(向server僅僅發出一次請求。網址不會變。
當轉發完畢後,再刷新,由於網址沒變,刷新的仍是沒轉發前的資源,並會再次轉發(提交數據時要注意));
總結:因此通常不用請求重定向,通常用轉發完畢,因爲請求重定向會向server發出兩次請求。轉發時要避免因刷新而致使數據反覆提交的問題;
*/
//經過request對象實現轉發,
public class Test1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException,IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//獲取表單中的值
String text = request.getParameter("text");
//向request對象域中存入值
request.setAttribute("text", text);
//假設用轉發時不能關閉response對象的流,否則調用forward方法時會拋出異常(但可以設置response響應對象的頭,並且轉發後仍是有效的)
// PrintWriter out = response.getWriter();//Error
//out.print(「asdf」); //Error
//out.close();//Error
//轉發到Test12.jsp,並將request, response對象提交過去(最好在跳轉完畢以後return)
request.getRequestDispatcher("/Test12.jsp").forward(request, response);
return;
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
經過request對象獲取請求頭的請求資源和所有請求頭的值
public class Test2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//獲取請求方式(結果爲:GET或POST等)
System.out.println(request.getMethod());
//當後綴名爲/com/*時,都會訪問到此servlet(我輸入的是:http://localhost:8080/request/com/1.html )
//獲取請求資源的URI(結果爲:/request/com/1.html )
System.out.println(request.getRequestURI());
//獲取請求資源的URL(結果爲:http://localhost:8080/request/com/1.html )
System.out.println(request.getRequestURL());
//URL表明的是互聯網上面的資源地址
//URI表明的是隨意一個資源的地址(可以理解爲某個server上的地址)
//經過request請求頭對象,獲取一個頭的值(這裏獲取的是client所支持的壓縮格式)
System.out.println(request.getHeader("Accept-Encoding"));
System.out.println("獲取所有的頭");
//經過request請求對象獲得所有頭的名稱
Enumeration<String> headerNames =request.getHeaderNames();
while(headerNames.hasMoreElements()){//推斷此枚舉是否還有下一個值
String headerName = headerNames.nextElement();//返回它的下一個值
System.out.println(headerName+":"+request.getHeader(headerName));
}
//request.getHeaders("");//當一個頭設置了兩個值,就用此方法獲取
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
經過request對象防止盜鏈
//防止盜鏈
public class Test5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//防止反覆提交,此處是驗證提交的次數
System.out.println("提交的次數");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
//獲取來訪者的url
String path = request.getHeader("referer");
//獲取本server的主機名
String server = "http://"+request.getServerName();
//推斷path的前端是不是server(也就是推斷主機名是否一樣)
if(path != null && path.startsWith(server)){
//將path和server轉入request對象域
request.setAttribute("path", path);
request.setAttribute("server", server);
//轉發至Test52.jsp
request.getRequestDispatcher("/Test52.jsp").forward(request, response);
}else{
//不轉發
response.getWriter().print("不是本網頁的鏈接");
}
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
比較常用的方法:
request.getRequestURL(); 獲取完整的URL
request.getRequestURI(); 僅僅獲取請求資源的地址
request.getQueryString(); 獲取在地址欄中’?
’號後面的所有字符串(因此它僅僅針對get的提交方式有效)
request.getRemoteAddr(); 獲取客戶機的IP地址
request.getRemoteHost(); 獲取客戶機的完整主機名(但是客戶機的IP要在DNS上註冊後才幹顯示主機名,否則仍是顯示IP地址)
request.getRemotePort(); 獲取瀏覽器所使用的port號(當瀏覽器關閉後再又一次打開時port號會隨機變化)
request.getLocalAddr(); 獲取WEBserver的IP地址
request.getLocalName(); 獲取WEB服務的主機名
request.getServerName(); 獲取WEBserver的主機名
request.getServerPort(); 貨物WEBserver的port
request.getMethod(); 獲取瀏覽器的請求方式
request.getHeader(headerName); 依據對應的響應頭名字來獲取響應的值
request.getHeaders(headerName); 假設同一個響應頭有多個值,就用此方法獲取,並返回一個Enumeration
request.getContextPath(); 獲得當前的project名:如:/dy19
request.getServletContext().getContextPath(); 獲得當前的project名:如:/dy19
request.getServletPath(); 獲得web配置文件<url-pattern>/servlet/UploadServlet</url-pattern>此標籤中的值
URL與URI的差異
www.sina.com/news/1.html 這就是一個URL
news/1.html 這就是一個URI
URL表明的是互聯網上面的資源地址
URI表明的是隨意一個資源的地址(可以理解爲某個server上的地址)
經過request對象獲取client所提交的數據(經過get或post等,提交的數據)(在上面request對象的第一個知識點中已作過筆記)
//經過request對象獲取client所提交的數據(經過get或post等,提交的數據)(先要檢查用戶提交的數據中是否有str這個key)
public class Test3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
System.out.println("-------------------直接經過key獲取提交的value--------------------------------");
/*
//client用get或post方式提交的數據,都可以用下面方式獲取
//如咱們在訪問時在後面加上數據如:http://localhost:8080/request/servlet/Test3?
name=abc&password=123
//或者用表單提交都能獲取到
String value = request.getParameter("name");//獲取指定名稱的值
if(value!=null && !value.trim().equals("")){//推斷是不是沒有輸入或輸入的全部爲空格(檢查提交的數據合格再使用)
System.out.println("name="+value);//value.trim()方法會刪除字符串兩邊的空格,假設字符串全部都是空格,那麼返回的字符串相等於new Stirng("");
}
System.out.println("-------------------先獲取到所有請求數據key。再經過迭代取出請求的值--------------------------------");
//獲取所有的數據的key,再經過key遍歷所有的值
Enumeration<String> names =request.getParameterNames();
while(names.hasMoreElements()){//推斷此枚舉是否還有下一個key
String name = names.nextElement();//獲取下一個key
String value1 = request.getParameter(name);//經過key遍歷所有的value
System.out.println(name+"="+value1);
}
System.out.println("--------------------獲取同一個key有兩個value的方法-------------------------------");
//假設提交的數據key有多個一樣如:http://localhost:8080/request/servlet/Test3?str=abc&str=123
//這裏的str有兩個值,就用request.getParameterValues("str");來獲取
String[] values = request.getParameterValues("str");//返回str中的多個值
for(int i=0; values!=null && i<values.length; i++){//遍歷這些值(先要檢查用戶提交的數據中是否有str這個key)
System.out.println(values[i]);
}
*/
System.out.println("----------------------將請求的數據以一個map集合返回-----------------------------");
//將提交的數據返回到一個Map集合中提交方式爲:http://localhost:8080/request/servlet/Test3?
name=abc&name=111&password=123
Map<String,String[]> map =request.getParameterMap();
//遍歷輸出這個map集合
//獲取map中所有的key,以Set集合的方式返回
Set<String> set = map.keySet();
//獲取set集合的迭代器
Iterator<String> it = set.iterator();
//遍歷這個迭代器
while(it.hasNext()){//推斷迭代器是否還有下一個key值
String key = it.next();//獲取下一個key
//輸出key
System.out.print(key);
//經過key返回所相應的value;返回一個數組,因爲同一個key可能有兩個以上value
String [] values = map.get(key);
//遍歷輸入這個values
for(String s:values){
System.out.print(":"+s);
}
//換行
System.out.println();
}
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
經過request.getRequestDispatcher("").include(request,response);方法實現多個頁面動態包括(也就是將多個頁面的數據同一時候傳給前臺)
public class Test6 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//在response對象的返回數據的尾部加上了/Test61.jsp中的內容
request.getRequestDispatcher("/Test61.jsp").include(request, response);
//在response對象的返回數據的尾部加入了我是servlet<br/>
response.getWriter().print("我是servlet<br/>");
//在response對象的返回數據的尾部加入了/Test62.jsp中的內容
request.getRequestDispatcher("/Test62.jsp").include(request, response);
/*
因此輸出的結果爲:
This is my Test61.JSP page.
我是servlet
This is my Test62.JSP page.
*/
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
response(響應頭對象)用於向client返回數據
依據response對象向瀏覽器發送數據
//經過response對象的字節流返回數據
response.setHeader("Content-type","text/thml;charset=UTF-8"); //設置頭的值,這是是設置Content-type告訴瀏覽器回送的數據。爲html格式,它編碼格式爲UTF-8
response.setContentType("text/html;charser=utf-8");//設置ContentType(返回數據類型)響應頭的數據類型爲html格式。編碼格式爲utf-8
//也至關因而告訴瀏覽器以什麼樣的編碼格式打開這段數據
response.setCharacterEncoding("utf-8");//設置response對象的編碼格式(response對象裏面也有對數據進行轉碼,因此也需要編碼格式)
request.setCharacterEncoding("utf-8");//設置request對象的編碼格式(request對象裏面也有對數據進行轉碼。因此也需要編碼格式)
PrintWriter out = response.getWriter();//獲取到字符輸出流
out.write("中國");//向字符流中寫入數據
out.flush();//移除流中的緩存
out.close();//關閉流
//經過response對象的字符流返回數據
public class Test2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");//設置ContentType(返回數據類型)響應頭的數據類型爲html格式,編碼格式爲utf-8
//也至關因而告訴瀏覽器以什麼樣的編碼格式打開這段數據
response.setCharacterEncoding("utf-8");//設置response對象的編碼格式(response對象裏面也有對數據進行轉碼,因此也需要編碼格式)
request.setCharacterEncoding("utf-8");//設置request對象的編碼格式(request對象裏面也有對數據進行轉碼,因此也需要編碼格式)
String data = "中國";
PrintWriter out = response.getWriter();//獲取到字符輸出流
out.write(data);//向字符流中寫入數據
out.flush();//移除流中的緩存
out.close();//關閉流
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
提示: 字符流和字節流是相互排斥的,假設同一個response對象,用了字符流就不能用字節流了,最好都用字節流(從response或request對象中獲取的流不需要關閉。因爲當servlet對象在銷燬時會本身主動檢測這些流是否調用了close方法,而後關閉,但是假設是咱們本身new的流必須關閉它,否則會浪費資源)
從瀏覽器中下載web應用中的資源
String path = this.getServletContext().getRealPath("/image/美女.zip");//獲取這個文件的絕對路徑
String fileName = path.substring(path.lastIndexOf(File.separator)+1);//獲取到這個文件的名字
fileName = URLEncoder.encode(fileName, "UTF-8");//假設爲中文名字需要進行轉碼
response.setHeader("Content-Disposition", "attachment;filename="+fileName);//設置響應頭Content-Disposition的值爲attachment表示下面載方式打開,後面跟文件名稱字
FileInputStream in = new FileInputStream(path);//建立一個字節輸入流,並指向這個圖片
byte[] buffer = new byte[1024];//建立一個緩衝字節數組
int len=0;//定義一個緩衝大小的變量
OutputStream out = response.getOutputStream();//獲取response的字節輸出流
while((len=in.read(buffer)) > 0){//推斷從輸入流中獲取的字節數,假設小於或等於0表示沒有讀取到字節
out.write(buffer,0,len);//將buffer中的緩存寫入到 response的字節輸出流中
}
//關閉流
in.close();
out.flush();
out.close();
請求重定向
/*請求重定向
請求重定向與轉發的差異
請求重定向: 是向client發回一個網址,讓瀏覽器又一次去訪問(向server發出了兩次請求,並且網址會變)
轉發: 是經過server直接轉發到某一個網址(向server僅僅發出一次請求,網址不會變)
總結:因此通常不用請求重定向,通常用轉發完畢,因爲請求重定向會向server發出兩次請求。
*/
public class Test7 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
/*
response.setStatus(302);//設置response對象中狀態行的狀態碼爲302。表示請求重定向
response.setHeader("Location","/response/welcome.jsp");//Location此頭爲請求重定向頭,重定向到welcomem.jsp文件
*/
//此方法也可以直接重定向到welcomem.jsp文件
response.sendRedirect("/response/welcome.jsp");
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
設置瀏覽器定時重複刷新頁面或定時重定向
public class Test5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
/*
//不停的刷新
response.setHeader("refresh","3");//表示每隔3秒鐘就訪問一次此servlet
//產生一個隨機數並經過字符流返回
PrintWriter out = response.getWriter();
out.write(new Random().nextInt()+"");
*/
/*
//3秒鐘之後可以重定向到其它的網頁
response.setHeader("refresh", "3;url='http://www.baidu.com'");//設置refresh(刷新頭,設置其值,表示3秒鐘後跳轉至百度)
PrintWriter out = response.getWriter();
out.write("本網頁將在3秒鐘後重定向到百度;假設未跳轉,情點擊<a href='http://www.baidu.com'>百度</a>");
*/
//最有用的方式。用jsp文件控制頁面跳轉
//經過meta表示設置jsp文件response對象的響應頭,隔3秒跳轉至/response/welcome.jsp網頁
String str = "<meta http-equiv='refresh' content='3;url=/response/welcome.jsp'>" +
"本網頁將在3秒鐘後跳轉;假設未跳轉,情點擊<a href='/response/welcome.jsp'>超連接</a>";
//將數據存入ServletContext應用域對象中
this.getServletContext().setAttribute("str", str);
//跳轉至MyJsp網頁;但先要在webproject下建一個MyJsp.jsp文件,並在body標籤中用java代碼獲取ServletContext應用域對象str中的value如:
//<%//獲取servletContext應用域對象中的值String str =(String)application.getAttribute("str"); //經過流向當前的位置輸出數據 out.write(str);%>
this.getServletContext().getRequestDispatcher("/MyJsp.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
請求重定向時,經過url方式將數據提交給Test41.jsp
Servlet中的代碼
//請求重定向時,經過url方式將數據提交給Test41.jsp
public class Test4 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
/*
//第一種方式:
//數據
String str = new String("中國");
str = new String(str.getBytes("utf-8"),"ISO-8859-1");
//請求重定向,並將數據傳過去
response.sendRedirect("/request/Test41.jsp?str="+str);
*/
/*
//另一種方式:
String value = new String("四川");//數據
String value1 = URLEncoder.encode(value, "UTF-8");//加碼
response.sendRedirect("/request/Test41.jsp?value="+value1); //假設直接在url後面跟中文數據,需要對中文進行轉碼
*/
//加碼與解碼
String temp = new String("中文數據");
//加碼(就是將temp這個UTF-8編碼的字符串轉換爲ISO-8859-1;當某些時候進行中文傳輸數據時,需要進行加碼與解碼)
String temp1 = URLEncoder.encode(temp, "UTF-8");
//也就是說加碼事後,將temp的值的存儲格式變爲了默認的ISO-8859-1編碼格式
System.out.println(temp1);//打印爲:%E4%B8%AD%E6%96%87%E6%95%B0%E6%8D%AE
//解碼(將加碼過的字符串(ISO-8859-1),轉換爲相應的編碼格式)
String temp2 = URLDecoder.decode(temp1, "UTF-8");
System.out.println(temp2);//打印爲:中文數據
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
Jsp中的代碼
<body>
<!--第一種方式 :< %=new String(request.getParameter("str").getBytes("ISO-8859-1"),"UTF-8") %> -->
<!-- 另一種方式的解碼與第一種同樣(僅僅限於servlet傳值給jsp時) --><%=new String(request.getParameter("value").getBytes("ISO-8859-1"), "UTF-8") %>
</body>
經過改動server配置文件。來設置server默認的編碼格式(但此方法通常不用)
在apache-tomcat-7.0.6\conf\servlet.xml文件裏的<Connector port="8080"protocol="HTTP/1.1" connectionTimeout="20000"redirectPort="8443" />標籤末尾加入一個屬性: URIEncoding=」UTF-8」;
或者在末尾加入一個useBodyEncodingForURI=」true」。這個屬性是設置URL地址的默認編碼格式
控制瀏覽器對數據的緩存
public class Test6 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
/*
//設置瀏覽器不要緩存(爲了使不少其它的瀏覽器兼容,因此設置的頭比較多)
response.setHeader("expires","-1");
response.setHeader("cache-Control","no-cache");
response.setHeader("pragma","no-cache");
*/
//設置瀏覽器緩存數據
//設置數據緩存的時間爲當前時間加上1小時
response.setDateHeader("expires", System.currentTimeMillis()+(1000*3600));//1000毫秒*3600 ==一小時
String data = new String("aaaaaaaaa");//數據
response.getWriter().write(data);//data的數據會被保存1小時
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
將數據壓縮後才傳給client
public class Test8 extends HttpServlet{
public void doGet(HttpServletRequest request, HttpServletResponseresponse)//request爲請求;response爲響應頭
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
String str = new String("要壓縮的數據");
//建立一個字節緩存輸出流
ByteArrayOutputStream bout = newByteArrayOutputStream();
//把輸出流做爲參數,建立一個gzip壓縮對象,將壓縮後的數據放到緩存流中
GZIPOutputStream gout = new GZIPOutputStream(bout);
//將要壓縮數據的字節數組傳入壓縮對象的write方法中進行壓縮
gout.write(str.getBytes());
//關閉壓縮
gout.close();
//從緩存輸出流中獲取壓縮後的byte數組數據
byte[] gzip = bout.toByteArray();
//關閉緩存輸出流
bout.close();
//設置Content-Encoding(server返回數據的壓縮格式)響應頭的返回值
response.setHeader("Content-Encoding", "gzip");
//設置Content-Length(server返回數據壓縮後的長度)響應頭的返回值
response.setHeader("Content-Length", String.valueOf(gzip.length));
//設置response的傳出數據
response.getOutputStream().write(gzip);
//傳送過去後瀏覽器會本身主動解壓顯示
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
cookie(緩存數據)
把數據緩存在client的硬盤上,一個Cookie僅僅能表示一種信息,它至少含有一個鍵值
一個WEB網站可以給一個WEB瀏覽器發送多個Cookie,一個瀏覽器也可以存儲多個WEB網站提供的Cookie
可以調用Cookie對象的setMaxAge()方法設置此Cookie的存儲時間即生命週期(單位秒),設置爲0表示刪除該Cookie;假設不設置保存時間。此Cookie僅僅會保存在用戶的內存中,當瀏覽器關閉釋放內存,此Cookie會被刪除,刪除cookie時,path必須一致,不然不會被刪除
瀏覽器通常僅僅贊成存放300個Cookie,每個網站最多存放20個Cookie,每個Cookie的限制大小爲4KB
輸出用戶訪問此servlet的次數
public class Test1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//得到本web應用(/cookie)存儲在client的cookie
Cookie [] cookies = request.getCookies();
//標記訪問的次數
int time = 1;
//推斷本web應用是否在client存有cookie
if(cookies!=null && cookies.length>0){
//遍歷這些cookie
for(int i=0; i<cookies.length; i++){
//推斷是不是numberOfTimes(次數)這個key
if("numberOfTimes".equals(cookies[i].getName())){
//得到numberOfTimes這個key的值(上次訪問的次數)
String value = cookies[i].getValue();
//並刪除當前的Cookie
cookies[i].setMaxAge(0);//將存儲時間設置爲0表示刪除此cookie
//將獲取的值轉換爲int類型
int temp = Integer.valueOf(value);
//上次訪問的次數加上1,並賦值給time標記
time = ++temp;
}
}
}
//建立一個新的cookie並把numberOfTimes的值設爲本次的次數
Cookie cookie = new Cookie("numberOfTimes",time+"");
//設置cookie的保留時間,單位爲秒
cookie.setMaxAge(3600);
//設置標識(表示當前cookie是/cookieWEBproject的)
cookie.setPath("/cookie");
//向瀏覽器返回此cookie(保存在客戶機的硬盤上)
response.addCookie(cookie);
//打印用戶訪問的次數
response.getWriter().print("你是第"+time+"次訪問本servlet");
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
session(會話對象)
把數據緩存在server端
在WEB開發中,server可以爲每個用戶瀏覽器建立一個會話對象(session對象),也就是說一個瀏覽器獨佔一個session對象(默認狀況下).所以。在需要保存用戶數據時,server可以把用戶數據寫到用戶瀏覽器獨佔的session對象中,當用戶用瀏覽器訪問其它程序時,其它程序可以從用戶的session中取出該用戶的數據,爲用戶服務
Session對象是由server建立,咱們可以調用request對象的getSession方法獲得用戶的session對象
Session與cookie的差異:
Cookie是把用戶的數據寫在用戶本地硬盤上
Session是把用戶的數據寫到server爲每個用戶單獨分配的session對象中
當session對象超過30分鐘(默認)無訪問,就銷燬此session對象;調用session對象的getLastAccessedTime()方法返回此session對象最後的訪問時間(時間戳)
Session對象的生命週期設置
Session也是依附於cookie的,當server新建了一個session對象,就會生成一個id,而後經過cookie將此id返回到client上id的key爲」JSESSIONID」,而後當用戶下次來訪問此web應用時是帶着session對象的id來的,經過此id咱們就可以找到與之相應的session對象 ; 但此cookie對象沒有設置保存時間。因此並無寫到客戶機的硬盤上,而是在客戶機的內存中,當用戶關閉瀏覽器時,此cookie會被本身主動釋放,再打開瀏覽器就訪問不到原有的session對象了; 爲了解決此問題咱們需要重寫一個key爲」JSESSIONID」。並設置了保存時間(通常與在web.xml配置文件裏配置了的時間一致)的cookie 覆蓋掉原有的cookie。session的id可以經過session對象的getId()方法得到; 做用域:此session對象僅僅在本project中有效
在WEBproject的配置文件web.xml文件里加入一個標籤: <session-config>
<session-timeout>10</session-timeout>
</session-config>
表示session對象在10分鐘無人使用的狀況下,將被本身主動銷燬
也可以直接調用session對象的invalidate();方法,立刻銷燬此用戶的session對象
經過一個servlet向session對象中存值,一個servlet輸出session對象中的值的例題:
Jsp中的代碼:
<body>
<a href="servlet/Test1">存</a><br/>
<a href="servlet/Test2">取</a>
</body>
存值的servlet的代碼:
//用戶訪問此Test1 servlet時。向此用戶的session對象中存入一個值,當用戶訪問Test2 servlet時取出用戶的session對象所存入的值
//也就是說。當咱們第一此獲取用戶的session對象時,server假設沒有給此用戶建立session對象,那麼就給用戶新建一個
//session對象的生命週期是:server第一次獲取用戶的session對象 到 此session對象30分鐘(默認)不用時就本身主動釋放
public class Test1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//獲取在server中獲取用戶的session對象,假設有就返回,沒有就建立一個新的session對象再返回
HttpSession session = request.getSession();
//向此用戶的session對象總存入值
String str = "hello";
session.setAttribute("data", str);
//打印此值
response.getWriter().print("存入了:"+str);
/*
Session也是依附於cookie的。當server新建了一個session對象,就會生成一個id,
而後經過cookie將此id返回到client上id的key爲」JSESSIONID」,而後當用戶下次來
訪問此web應用時是帶着session對象的id來的,經過此id咱們就可以找到與之相應的session對象 ;
但此cookie對象沒有設置保存時間。因此並無寫到客戶機的硬盤上,而是在客戶機的內存中,
當用戶關閉瀏覽器時,此cookie會被本身主動釋放,再打開瀏覽器就訪問不到原有的session對象了;
爲了解決此問題咱們需要重寫一個key爲」JSESSIONID」,並設置了保存時間(通常與在web.xml配置文件裏配置了的時間一致)
的cookie 覆蓋掉原有的cookie;session的id可以經過session對象的getId()方法得到;
*/
//如下就是覆蓋原有cookie的代碼
//獲取到session對象的id
String sessionId = session.getId();
//建立一個新的cookie對象(並設置一個鍵值。key必須爲JSESSIONID才幹覆蓋原有的cookie。value爲當前session對象的id)
Cookie cookie = new Cookie("JSESSIONID",sessionId);
//設置cookie的存活時間(通常和web.xml配置的session對象的存活時間一致,缺省爲30分鐘)
cookie.setMaxAge(1800);//存活時間爲30分鐘。不調用此方法設置值,此cookie將不會被寫入客戶機的硬盤上
//設置此cookie的網站
cookie.setPath("/session");
//返回給客戶機
response.addCookie(cookie);
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
取值的servlet的代碼:
//用戶訪問取出Test1 servlet存在session對象中的值
public class Test2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
response.setContentType("text/html; charser=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
//取出此用戶的session對象
HttpSession session = request.getSession(false);//傳入一個false,表示此方法僅僅獲取session對象,並不建立session對象(當沒有session對象時)
//HttpSessionsession = request.getSession();//此方法儘管也可以,但假設此用戶沒有session對象時。此處並不需要建立一個session對象,因此最好用上面這樣的方法,(可以添加效率)
//再取出此session對象中的data的值
String str = "no";
//推斷是否獲取到了session對象
if(session != null){
str = (String)session.getAttribute("data");
}
//打印此值
response.getWriter().print("取出了:"+str);
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
}
當用戶禁用cookie後怎麼解決傳入session對象的id問題(經過url想servlet帶入session對象的id,但用戶關閉瀏覽器後將失去session對象。沒法避免(上面用cookie可以避免))
上面的servlet中的代碼不變 jsp中代碼爲:
<body>
<%
//當訪問首頁時就建立此session對象
request.getSession();
//encodeURL()是本應用級別的,encodeRedirectURL()是跨應用的
//此方法會在servlet/Test1後面本身主動加上session對象的id(重要:假設在servlet重定向跳轉時,這裏重寫url的方法是:response.encodeRedirectURL("servlet/Test1")
Stringurl1 = response.encodeURL("servlet/Test1"); //這裏是重寫在jsp中跳轉頁面的url 因此用response.encodeURL("servlet/Test1"))
//此方法會在servlet/Test2後面本身主動加上session對象的id
Stringurl2 = response.encodeURL("servlet/Test2");
%>
<a href="<%=url1 %>">存</a><br/>
<a href="<%=url2 %>">取</a>
</body>
還有在作登陸時需要用到session對象,當用戶登陸成功後就把user對象存入session中,當註銷時就需要調用session對象的invalidate();方法,立刻銷燬此session對象。也可用session.removeAttribute("user");值刪除指定的映射關係(推薦)
base64編碼
假設一個字符串用dase64編碼, 會將這個字符串的二進制代碼的3個字節轉換爲4個字節,在最高位補0的形式;
如 :
10100110 11110010 00010100
dase64編碼後:
00101001 00101111 00001000 00010100
這樣每個字節的第值就在0-63之間了,再通過dase64的碼錶轉換過來後就是僅僅有包含了鍵盤上的所有字符
在java中得到dase64編碼對象
sun.misc.BASE64Encoder base64Encoder = new sun.misc.BASE64Encoder();//得到dase64編碼對象
String str = base64Encoder.encode(byte[] arg0);//傳入一個byte[]數組,將將這個數組用dase64編碼,並返回一個新的字符串
在java 中得到dase64解碼對象
sun.misc.BASE64Decoderbase64Decoder = new BASE64Decoder();//建立解碼對象
byte[] buff =base64Decoder.decodeBuffer(str);//將要解碼字符串傳入,返回一個byte數組
String token = new String(buff);//經過這個byte數組建立一個字符串
通常在MyEclipse不能用,需用下面方法進行設置
僅僅需要在projectbuild path中的JRE System Library中的Accessible,再又一次加入庫JRE System Library 的Accessible,Rule Pattarn爲**。又一次編譯後就一切正常了(例如如下圖)
JSP開發
jsp是SUN公司定義的一種用於開發動態web頁面的計算。和html不一樣的是。jsp贊成在頁面中編寫java代碼及在頁面中獲取request、response等對象實現與瀏覽器交互,因此jsp也是一種web資源開發技術
jsp文件在訪問時server會將其轉換爲servlet的java文件(轉換後文件的位置Tomcat7.0\work\Catalina\localhost\project名\org\apache\jsp;
1、jsp中的代碼轉換後,會被放到此java文件裏的_jspService( )方法中
2、因爲第一次訪問一個jsp文件時,會將此jsp翻譯成servlet,因此 jsp文件在第一次訪問時會很是慢。第二次訪問時引擎(就是將jsp轉換爲servlet的程序)發現jsp文件沒有改變就不在翻譯,直接訪問此servlet因此速度快
3、並且JSP引擎在調用_jspService( )方法時,會傳入9個隱式對象(如下JSP隱式對象中講)
JSP模版元素
JSP中的模板元素定義了網頁的基本骨架,即定義了頁面的結構和外觀
JSP表達式
JSP表達式用於將程序數據輸出到client 語法<%=變量或表達式 %> 也就是直接在此位置輸出數據
server會將此語法直接轉換爲 out.print(變量或表達式);
JSP腳本片段
就是在jsp文件裏嵌套<% java代碼 %>這就是腳本片段, 可以出現在jsp中的任何位置,腳本片段中僅僅能出現java代碼;
Jsp中可以出現多個腳本片段,在兩個腳本片段之間可以嵌套文本、HTML標籤及其它jsp元素
多個腳本片段中的代碼可以相互訪問。單個腳本片段中的java語句可以是不完整的,但是多個腳本片段組合後的結果必須是完整的java語句,好比:
<%
for(inti=0; i<5; i++){
%>
<p>hello world!</p>
<%
}
%>
這表示把<p>hello world!</p>輸出5遍
JSP聲明
假設在用下面方式定義腳本片段,表示把此腳本片段中的代碼放到_jspService( )方法的外面去。好比:
<%!
Publicstatic void fun(){
System.out.println(「helloworld!」);
}
%>
,假設不將此java代碼放到_jspService( )方法的外面去,至關於在_jspService()方法的內部定義了一個fun()方法,這樣java語法是不一樣意的;這樣咱們就也可以在JSP中定義一個成員變量或靜態域等功能了
JSP凝視
在JSP中的凝視方法是<%--被凝視的內容 --%>
此方法凝視是。當server將jsp文件轉換爲servlet時,會丟棄此凝視,並不會向用戶返回此凝視的代碼;假設用<!- - 凝視的內容- -> 此方法凝視,server會將此代碼發送給客戶,會添加網絡數據;用此<!---->種凝視,被凝視的javaBean標籤也會被servlet翻譯,因此在jsp中儘可能注意
JSP模板更改
改動模板路徑:MyEclipse\plugins\com.genuitec.eclipse.wizards_11.0.0.me201303311935.jar中templates\jsp\Jsp.vtl文件裏改動
JSP指令
Jsp指令是爲了JSP引擎(就是將jsp轉換爲servlet的程序)而設計的,它們並不是直接生產不論什麼可見輸出,而僅僅告訴引擎怎樣將jsp頁面翻譯成servlet,指令僅僅是用於傳給引擎,並不會發送給客戶機,在jsp2.0中共定義了三個指令:
page指令
語法<%@ 指令 屬性名=」值」 %>
演示樣例:
<%@ page contentType=」text/html;charset=gb2312」 %>
表示告訴引擎 此文件的格式及編碼
多個屬性可以寫在一個指令中(用空格分隔),也可以寫在多個指令中
演示樣例:
<%@page contentType=」text/html; charset=gb2312」 %>
<%@page import=」java.Util.Date」 %>
和
<%@ pagecontentType=」text/html; charset=gb2312」 import=」java.Util.Date」 %>
是同樣的效果
page指令和存放在jsp中的任何位置,但最好放在JSP頁面的起始位置
page指令的屬性
language=」java」 表示在JSP腳本片段中的代碼是java代碼
extends=」package.class」 表示此jsp翻譯成servlet後繼承誰(通常不改)
import=」java.util.Date,java.sql.* 」 表示在此jsp中的腳本片段中的java代碼需要導入的包,多個包可以用」,」隔開,也可以寫多個page指令導入
jsp中下面包會本身主動導入
java.lang.*;
javax.servlet.*;
javax.servlet.jsp.*;
javax.servlet.http.*;
session=」true| false」 是否獲取此用戶的session對象(默認值爲true, 獲取)。假設設爲不本身主動獲取, 咱們也可以手動經過request對象來獲取session對象
buffer=」none| 20kb」 設置out隱式對象的緩存。缺省默以爲8KB的緩存,none爲不緩存
autoFlush=」true| false」 設置out隱式對象的緩存滿後是否本身主動刷新,通常不改(默以爲true, 本身主動刷新)
isThreadSafe=」true| false」 設置此jsp的線程是不是安全的(默以爲true, 是線程安全的),假設設置爲false 那麼此jsp翻譯成servlet後會實現SingleThreadModel接口以確保線程安全(SingleThreadModel接口上面已講過);
info=」text」 可以經過此屬性帶信息
errorPage=」relative_url」 指定當此jsp頁面出現異常後。轉向哪一個頁面,此路徑必須使用相對路徑,假設以」/」開頭表示相對於當前應用的程序的根文件夾, 不然相對於當前的頁面位置
此屬性僅僅是設置此jsp異常時跳轉的頁面,也可以再web.xml文件裏配置全局的異常跳轉頁面,如:
<error-page>
<exception-type>java.lang.ArithmeticException</exception-type>
<location>/error.jsp</location>
</error-page>
表示當前web應用中所有的serlvet及jsp文件拋出java.lang.ArithmeticException異常後將跳轉至/error.jsp這個jsp文件
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
表示當前web應用拋出404(找不到資源)異常後,就跳轉至/error.jsp這個jsp文件
假設在一個jsp文件裏設置了errorPage的屬性,那麼在web.xml文件裏設置的異常跳轉。將不正確此jsp頁面起做用
isErrorPage=」true | false」 設置當前頁面是否爲錯誤處理頁面(默認值爲false,不是錯誤處理頁面)。假設將此屬性設爲true,那麼此jsp會接收一個異常對象(exception)
contentType=」text/html;charset=ISO-8859-1」 告訴告訴瀏覽器打開此文件的格式及編碼 (也就是設置response的Content-Type頭屬性的值)
pageEncoding=」characterSet |ISO-8859-1」 也是設置編碼格式的
isELIgnored="true | false" 是否忽略EL表達式,默以爲false(不忽略);
include指令
語法<%@ includefile=」 /Test1/head.jsp」 %>
用此指令包括 屬於靜態包括
靜態包括,在將jsp轉換爲servlet時就將要包括的jsp文件整合成一個servlet。在返回給客戶機。因此靜態包括僅僅有一個serlvet,效率高
用request.getRequestDispatcher("/Test1/head.jsp").include(request,response);方法包括就是動態包括
動態包括,就是包括者需要訪問被包括者時,再去訪問被包括者的servlet,因此包括了多少個jsp文件就會多出多少個servlet,效率低
注意事項: 被包括者不能有外部的框架(框架代碼) ,因爲包括時會將被包括者文件裏的所有字符都包括到當中
taglib指令
taglib指令用於在JSP頁面中導入標籤庫,語法:<%@ taglib url=」 http://java.sun.com/jsp/jstl/core」 prifix=」c」%>
JSP隱式對象
JSP引擎在調用_jspService()方法時,會傳入9個隱式對象(注意cookie不是一個隱式對象)
request 請求對象(已講)
response 響應對象(已講)
session 回話對象(已講)
application servletContext對象(已講)
config servletConfig對象(已講)
page 當前的servlet(this)對象,因接收時轉換成了Object對象,因此用時要強轉爲org.apache.jasper.runtime.HttpJspBase(已講)
exception 錯誤對象。當僅僅有page指令的isErrorPage屬性設置爲」true」(表示此頁面是錯誤處理頁面)時纔會傳入此對象(此對象繼承了Exception對象, 已講)
out
out 隱式對象用於向客戶發送字符數據
out對象經過pageContext對象的getOut方法得到,其做用和使用方法與response.getWriter()方法很類似。
此out隱式對象的類型爲JspWriter。JspWriter至關於一種帶緩存功能的PringtWriter,設置JSP頁面的page指令的buffer屬性可以調整此out對象的緩存大小,也可以關閉緩存
僅僅有向此out對象中寫入了內容。且知足下面不論什麼一個條件, out對象纔去調用response.getWriter()方法,並經過該方法返回的PrintWriter輸出流對象將out對象的緩衝區的內容正真寫入到Servlet引擎提供的緩衝區域中。
一、設置page指令的buffer屬性的值爲:none,關閉out對象的緩存
二、out對象的緩存區已滿
三、jsp頁面結束
注意事項: 此out對象不要和response.getWriter流對象一塊兒使用 ,否則會出現輸出順序不一致的異常
pageContext
一、 pageContext對象是JSP技術中最中意的一個對象,它表明JSP頁面的執行環境
二、 pageContext對象封裝了其它8大隱式對象的引用
三、 pageContext對象它自身就是一個域對象,可以用來存儲數據
四、 pageContext對象還封裝了web開發中常常涉及到的一些常用的操做, 如包括和轉發到其它資源, 檢索其它域對象中的屬性等
五、 生命週期: 當jsp文件運行完畢後,此域就被銷燬了
獲取其餘隱式對象的方法
pageContext.getEcception(); 獲取exception隱式對象
pageContext.getPage(); 獲取page隱式對象(this)
pageContext.getRequest(); 獲取request(請求)隱式對象
pageContext.getResponse(); 獲取response(響應)隱式對象
pageContext.getServletConfig(); 獲取servletConfig隱式對象
pageContext.getServletContext(); 獲取servletContext隱式對象
pageContext.getSession(); 獲取session隱式對象
pageContext.getOut(); 獲取out隱式對象
pageContext對象中域方法
pageContext.setAttribute(Stringkey,String value); 向pageContext域中存入值,注意pageContext對象的生命週期是:當前的jsp文件運行完畢後就消失了,因此要注意pageContext的使用範圍
pageContext.getAttribute(Stringkey); 獲取pageContext對象域中的映射值
pageContext.removeAttribute(Stringkey); 刪除pageContext對象中的映射關係
pageContext對象中訪問其餘三個域的方法
pageContext對象中有表明各個域的常量(int 類型)
pageContext.APPLICATION_SCOPE 表示application (servletContext)對象
pageContext.SESSION_SCOPE 表示session對象
pageContext.REQUEST_SCOPE 表示request對象
pageContext.PAGE_SCOPE 表示當前的pageContext對象
pageContext對象中有獲取其它域中鍵值的方法
pageContext.getAttribute(Stringkey, pageContext.SESSION_SCOPE); 表示獲取session對象中的映射關係pageContext.SESSION_SCOPE這個常量表明session對象
pageContext.setAttribute(Stringkey, String value, pageContext.SESSION_SCOPE); 表示設置session對象中的映射關係
pageContext.removeAttribute(Stringkey, pageContext.SESSION_SCOPE); 表示刪除session對象中的映射關係
pageContext.findAttribute方法
pageContext.findAttribute(String key); 此方法是遍歷獲取所有域中的鍵值關係(順序: pageContext-> request -> session -> application(servletContext))假設在request對象中找到了此映射關係的值,那麼將不會在向下繼續尋找,如四個域中都沒找到此鍵值關係,就返回一個「」字符串,並不是「null」
pageContext對象中定義了forward(轉發)方法和include(動態包括)方法分別用來簡化和取代request.getRequestDispatcher(「url」).forward(request, response)方法;參數是要轉發的url(加」/」表示當前的web應用根文件夾)。但這兩個方法。會將除了pageContext這個域對象之外的所有對象轉發或包括過去
servlet中的四大域對象有:
pageContext 當jsp文件運行完畢後,此域就被銷燬了
request 當request對象銷燬是,此域就被銷燬了
session session對象域的存活時間是可以調整的。默認狀況下30分鐘無操做本身主動銷燬
servletContext 當前web應用中的所有資源都可以訪問此域,此對象的存活時間爲, 當server啓動就建立, 當server關閉時銷燬(通常存儲在此域中的鍵值在不用時都要用.removeAttribute(String key)方法來刪除此鍵值,否則會浪費資源)
JSP標籤
JSP標籤頁稱爲JSP Action(JSP動做)元素,它用於在jsp頁面中提供業務邏輯功能,避免在JSP頁面中直接編寫java代碼形成jsp頁面難以維護
jsp中有例如如下三個常用的標籤:
<jsp:include>標籤
語法:<jsp:include page=」/url」><jsp:include>(動態包括和pageContext.include(「/url」)是同樣的)會將除了pageContext這個域對象之外的所有對象轉發或包括過去
<jsp:forward>標籤
語法:<jsp:forwardpage=」/url」></jsp:forward>(轉發和pageContext.forward(「url」)是同樣的)會將除了pageContext這個域對象之外的所有對象轉發或包括過去
<jsp:param>標籤(配合前面兩個標籤一塊兒使用)
語法:
<jsp:paramname=」key」 value=」value」>
使用方法:
<jsp:forwardpage=」/servlet」>
<jsp:param name=」key」 value=」value」/>
<jsp:paramname=」key1」 value=」value1」 />//可傳入多個鍵值
</jsp:forward>
這樣咱們就可以在/servlet中用request. getParameter("key");方法來獲取key的值, 也就是說可以經過<jsp:param>標籤傳值給轉發或包括的jsp或serlvet
JSP映射與serlvet的映射
servlet的映射(前面已講過)
在web應用中註冊com.scxh.Test這個serlvet,並取名爲Test
<servlet>
<servlet-name>Test</servlet-name>
<servlet-class>com.scxh.Test</servlet-class>//不加「/」相對於classes文件夾,加上相對於當前的web文件夾,此處不用加
<!--增長了下面的標記。此servlet就會在server啓動時建立-->
<load-on-startup>1</load-on-startup>//假設在web.xml配置文件裏在當前Servlet註冊標籤中加上了當前標籤,就會在server啓動時建立當前的Servlet對象,並調用Servlet對象的init方法;
</servlet>
serlvet的映射
<servlet-mapping>
<servlet-name>Test</servlet-name>
<url-pattern>*.com</url-pattern>//不能在前面加字符了。如:<url-pattern>aa/*.com</url-pattern>;這樣也是不一樣意的
</servlet-mapping>
JSP的映射
在web應用中註冊這個head.jsp文件並取名爲head
<servlet>
<servlet-name>head</servlet-name>
<jsp-file>/Test1/head.jsp</jsp-file>//不加「/」相對於classes文件夾,加上相對於當前的web文件夾,此處需加上
<!--增長了下面的標記,此servlet就會在server啓動時建立-->
<load-on-startup>1</load-on-startup>//假設在web.xml配置文件裏在當前JSP註冊標籤中加上了當前標籤,就會在server啓動時建立當前的JSP所相應的Servlet對象,並調用Servlet對象的init方法;
</servlet>
映射這個jsp
<servlet-mapping>
<servlet-name>head</servlet-name>
<url-pattern>/head.htlm</url-pattern>//這樣咱們就可以再瀏覽器值直接project名/head.htlm 訪問head.jsp文件了
</servlet-mapping>
JavaBean
JavaBean通常用於封裝數據的實體。JavaBean是一個遵循特定寫法的java類, 它一般具備例如如下特色:
1. 這個java類必須具備一個無參的構造函數
2. 屬性必須私有化
3. 私有化的屬性必須有public類型的set和get方法(set方法稱爲對屬性的改動器,get方法稱爲屬性的訪問)
4. 必須放在一個java文件裏並且此類必須爲public類型的
JSP中提供了三個標籤用於操做javaBean
<jsp:useBean>
演示樣例:
JSP中的代碼:
<jsp:useBean id="ren" class="cn.Demo1" scope="page"></jsp:useBean> <%--假設這個scope屬性不缺省。默認值爲「page「--%>
<%=ren.getName() %>
轉換爲servlet後的代碼
cn.Demo1ren= null; //建立一個cn.Demo1這個類的引用變量,取名爲
//到pageContext域對象中去取ren這個映射關係
ren =(cn.Demo1)_jspx_page_context.getAttribute("ren", PageContext.PAGE_SCOPE);
//推斷是否取到。沒有取到就在內存中建立個新的對象
if (ren == null){
//建立一個新的對象
ren = new cn.Demo1();
//並把此對象存入pageContext域中,key值爲引用的變量名
_jspx_page_context.setAttribute("ren",ren, PageContext.PAGE_SCOPE);
}
也就是說當咱們在<jsp:useBean>標籤中把id設置」ren」 並把class設置爲一個類(帶有包名的完整名稱)時,那麼系統會本身主動建立這個類名爲ren的引用變量, 假設scope屬性的值爲page,表示到pageContext域中去獲取key爲ren的Bean對象,假設沒有獲取到就建立一個這個類的新對象,並存入scope域對象中key的值就是id的值(「ren」);scope的值可以使四大域中的不論什麼一個;
注意事項:
<jsp:useBean id="ren"class="cn.Demo1" scope="session">
嵌套的代碼
</jsp:useBean>
在<jsp:useBean > 標籤中嵌套的代碼僅僅有當這個標籤建立一個新對象時,此代碼纔會運行;假設在域中獲取到了此對象(此標籤就不建立新對象),中間嵌套的代碼將不會運行
<jsp:setProperty>
經過Bean對象的屬性名來給此屬性賦值(配合<jsp:useBean>標籤來用)
<%--<jsp:setProperty>標籤的使用方法(配合<jsp:useBean>標籤來用) --%>
<%-- 經過Bean爲"ren"對象中的"gender"屬性賦值爲」女「 --%>
<jsp:setProperty name="ren" property="gender"value="女"/>
<%=ren.getGender() %><%-- 打印的值爲:」女「 --%>
<%="<br/>1-----------------------------------------------------------------<br/>" %>
<%-- 可以用字符串爲8大基本類型賦值(會本身主動將字符串轉換爲向相應的類) --%>
<jsp:setProperty name="ren" property="id"value="13"/><%--這裏的id屬性爲int類型。賦值字符串會本身主動轉換 --%>
<%=ren.getId() %><%-- 打印的值爲:」13「 --%>
<%="<br/>2-----------------------------------------------------------------<br/>" %>
<%-- 經過請求參數爲ren對象的password賦值 --%>
<%-- 提交的方式爲:http://localhost:8080/javaBean/Test1/Demo1.jsp?
password=abc123 --%>
<jsp:setProperty name="ren" property="password"param="password"/>
<%=ren.getPassword() %><%-- 打印的值爲:」abc123「 --%>
<%--param="password" 這句話會被翻譯成 request.getParameter("password");
也就是所從咱們提交的數據中去找password這可以key的值,找到了就賦值,沒有這個key就不賦值--%>
<%="<br/>3-----------------------------------------------------------------<br/>" %>
<%-- 經過請求參數爲ren對象的date賦值(date爲Date日期對象) --%>
<%-- 提交的方式爲:http://localhost:8080/javaBean/Test1/Demo1.jsp?date=2012-5-19 --%>
<%-- Date date = newSimpleDateFormat("yyyy-MM-dd").parse(request.getParameter("date"));--%>
<%-- <jsp:setPropertyname="ren" property="date" value="<%=date%>"/>--%>
<%=ren.getDate() %><%--打印的值爲:Sat May 19 00:00:00 CST 2012 --%>
<%--從以上value="<%=date %>代碼出可以看出,value的值可以引用java代碼所返回的值 --%>
<%="<br/>4-----------------------------------------------------------------<br/>" %>
<%-- 經過請求參數本身主動爲ren對象相應的屬性賦值 --%>
<%-- 提交的方式爲:http://localhost:8080/javaBean/Test1/Demo1.jsp?name=lishi&gender=nan
注意此處用中文會出現get方式提交亂碼問題(前面已講過怎麼解決)--%>
<jsp:setProperty name="ren"property="*" /><%--還可以寫爲<jsp:setProperty name="ren"property="name" />表示從請求中找到name這個key,並賦值給ren這個對象-->
<%=ren.getName() %><%--打印的值爲:lishi --%>
<%=ren.getGender() %><%--打印的值爲:nan --%>
<%-- 假設property="*"的話,那麼表示依據名稱本身主動匹配請求參數的key給ren對象中和此key同樣的屬性賦值--%>
<jsp:getProperty>
此標籤用於讀取JavaBean對象的屬性,也就是調用屬性的get方法,而後將讀取屬性的值轉換成字符串後插入響應的正文中,假設某個屬性的值爲null,那麼輸出的內容爲字符串」null」
語法:
<jsp:getProperty name="ren" property="name"/>
<%--表示直接輸出ren這個Bean對象的name屬性,假設此屬性的值爲null,那麼將輸出"null"字符串 --%>
JSP設計模式
JSP+JavaBean模式
此模式適合開發邏輯不太複雜的web應用程序,這樣的模式下,JavaBean用於封裝業務數據,JSP即負責處理用戶請求,又顯示數據
Servlet(controller)+JSP(view)+JavaBean(model)稱爲MVC模式
此模式適合開發複雜的web應用,在這樣的模式下,serlvet複雜處理用戶請求,JSP負責顯示數據,JavaBean負責封裝數據,採用此MVC模式各個模塊之間層次清晰,web開發推薦採用此模式
此模式分爲三層:web層、業務邏輯層(service)、數據訪問層(dao)
Web層分
處理用戶請求
Service(業務邏輯層)
處理dao層返回的數據,及封裝這些數據
Dao(數據訪問層)
訪問數據庫
包名規範
cn.itcast.domain 存放javaBean的類
cn.itcast.dao 存放Dao層的類
cn.itcast.dao.impl 存放Dao層的接口
cn.itcast.servce 存放Service層的類
cn.itcast.servce.impl 存放servlce層的接口
cn.itcast.web.serlvet名 存放處理用戶請求的servlet+JSP
cn.itcast.web.listener
cn.itcast.web.filter
cn.itcast.utils 存放工具類的包
Junit.test 存放測試的程序
在MVC模式下的jsp文件必須放在WEB-INF/jsp文件夾中防止client直接訪問
MVC模式開發的流程圖:
EL表達式
EL表達式語法:${date }假設在jsp中用此語句,那麼表示到每個域中去找date的映射關係,找到了就返回此date的value,假設沒有找到就返回一個「」爲空的字符串。
此表達式會翻譯成servlet的代碼:pageContext.findAttribute(date); 此方法是遍歷獲取所有域中的鍵值關係(順序: pageContext-> request -> session -> application(servletContext))假設在request對象中找到了此映射關係的值,那麼將不會在向下繼續尋找。如四個域中都沒找到此鍵值關係,就返回一個「」字符串,並不是「null」(上面已講過)(可以從指定域中獲取指定的映射關係)
假設存入的是一個key鍵所相應的是一個Bean對象,EL表達式語法爲:${date.name}; 那麼當取出date對象後會去調用name屬性的get方法,並返回其值
在WEB開發中,假設JS中要用到EL表達式。在JSP引入JS文件時,可以把js文件命名爲.jsp文件就可以了。這樣裏面el就能執行,也就是server可以執行這個文件了。
無非頁面引用的時候引用jsp就可以了。
如:<script src="myjs.jsp"type="text/javascript></script>;但取值範圍僅僅能取到session和application域中的值
經過EL表達式從指定域中獲取數據
<%="<br/>-------------------從指定域中取出數據---------------------<br/>"%>
<%
pageContext.setAttribute("name", "page");
request.setAttribute("name", "request");
session.setAttribute("name", "session");
application.setAttribute("name", "application");
%>
${pageScope.name }
${requestScope.name }
${sessionScope.name }
${applicationScope.name}
經過EL表達式獲取請求的數據
<%-- 經過EL表達式,獲取請求的數據 --%>
<body>
<%="<br/>-------------------獲取請求的數據---------------------<br/>"%>
<%-- 如訪問的url爲:http://localhost:8080/javaBean/Test1/Demo4.jsp?name=zhangshan--%>
${param.name }
<%--以上代碼就至關於:request.getParameter("name")--%>
<%="<br/>-------------------獲取複選框中請求的數據---------------------<br/>"%>
${paramValues.name[0] }
<%--以上代碼就至關於:
String[] str = request.getParameterValues("name");
System.out.println(str[0]);
獲取的是複選框中第下標爲0的值
--%>
經過EL表達式獲取集合中的數據
list集合
<%-- 用EL表達式取出list集合中的數據 --%>
<%
//向list集合中存入Demo1的對象
List<Demo1> list = new ArrayList<Demo1>();
list.add(new Demo1("aaa")); //構造方法會爲此對象的name屬性賦值
list.add(new Demo1("bbb"));
list.add(new Demo1("ccc"));
request.setAttribute("list", list);
%>
${list[0].name}<%--表示取出域中list的集合對象後。在取出這個集合的第0個對象再調用這個對象的getName方法 --%>
map集合
<%-- 用EL表達式取出map集合中的數據 --%>
<%
//向map集合中以鍵值對的方式存入Demo1對象
Map<String, Demo1> map = new HashMap<String, Demo1>();
map.put("d1", new Demo1("d111111")); //構造方法會爲此對象的name屬性賦值
map.put("d2", new Demo1("d222222"));
map.put("d3", new Demo1("d333333"));
map.put("d4", new Demo1("d444444"));
request.setAttribute("map", map);
%>
${map.d2.name}<%--表示取出域中取出map的集合對象後再經過d2這個key找出其value(Demo1對象),再調用name屬性的get方法 --%>
輸出當前工程的名稱,如:/project
<%--輸出當前所在的project名稱 --%>
${pageContext.request.contextPath}<%--獲得pageContext對象後再經過request對象的contextPath屬性獲取本project的名稱 --%>
<%--在跳轉頁面時需要用到:如<a href="${pageContext.request.contextPath }/Test1/Demo1.jsp">跳轉</a> 這樣咱們就可以直接跳轉至本project中的其它頁面了--%>
JSTL標籤
EL表達式可以經過JSTL標籤迭代集合等功能
JSTL是SUN公司開發的一套標籤庫,使用JSTL可以在頁面中實現一些簡單的邏輯,從而替換頁面中的腳本代碼
在JSP中使用JSTL標籤需完畢下面兩個步驟
一、 導入jstl.jar和standerd.jar這兩個JSTL的jar包
二、 在JSP頁面使用<%@ tagliburl=」 http://java.sun.com/jsp/jstl/core」 prifix=」c」 %> 元素導入標籤庫
url的地址是standerd.jar包中的/META-INF/c.tld文件裏的<uri>http://java.sun.com/jsp/jstl/core</uri>標籤中的地址
常用的JSTL標籤
<c:foreach var=」」 items=」」>(迭代標籤)
<%="<br/>-----------------------經過EL表達式配合JSTL來迭代list集合-------------------------------<br/>" %>
<%
//向list集合中存入Demo1的對象
List<Demo1> list = newArrayList<Demo1>();
list.add(new Demo1("aaa"));//構造方法會爲此對象的name屬性賦值
list.add(new Demo1("bbb"));
list.add(new Demo1("ccc"));
request.setAttribute("list", list);
%>
<c:forEach var="demo1"items="${list }">
${demo1.name }
</c:forEach>
<%--items="${list }" 經過EL表達式中取出這個集合,並將遍歷的出的對象放入demo1變量中,
而後在經過EL表達式調用li這個對象的getName方法
--%>
<%="<br/>-----------------------經過EL表達式配合JSTL來迭代map集合-------------------------------<br/>" %>
<%
//向map集合中以鍵值對的方式存入Demo1對象
Map<String, Demo1> map = new HashMap<String,Demo1>();
map.put("d1", new Demo1("d111111"));//構造方法會爲此對象的name屬性賦值
map.put("d2", new Demo1("d222222"));
map.put("d3", new Demo1("d333333"));
map.put("d4", new Demo1("d444444"));
request.setAttribute("map", map);
%>
<c:forEach var="entry"items="${map }">
${entry.key } : ${entry.value.name }
</c:forEach>
<%--
//上面entry變量獲得的就至關於如下it獲得的
Set<Map.Entry<String,Demo1>> set = map.entrySet();
Iterator<Map.Entry<String,Demo1>> it = set.iterator();
//上面EL表達式所輸出的就至關於如下out對象所輸出的
while(it.hasNext()){
Map.Entry<String, Demo1>entry = it.next();
out.print(entry.getKey()+":"+entry.getValue().getName());
}
也就是說當map集合對象被遍歷出來的對象就是一個Map.Entry對象
${entry.key} : ${entry.value.name }就是在在調用Map.Entry的getKey方法
及調用 Map.Entry的getValue方法再經過其返回對象,調用其對象的getName方法
--%>
<c:if test=」」>(測試標籤,推斷)
<%="<br />-----------------------測試(推斷)標籤的使用-------------------------------<br />" %>
<%
//pageContext.setAttribute("user", "張三");
%>
<c:if test="${user!=null }">
pageContext域中的user值爲:${user }
</c:if>
<c:if test="${user==null }"><!—EL表達式也可以用${empty user};表示假設user爲null的話就返回ture,emptykeyword還可以檢測集合如:${empty map},意思是當map集合等於null,或者map的isEmpty()方法返回爲true(也就是map中沒有映射關係時) ,那麼此EL表達式就返回false -->
pageContext域中沒有值
</c:if>
<%--當在四個域中取到user的值(映射關係)後就輸出第一句話,不然輸出第二句話。也就是說當test的值爲true時此標籤中的內容纔會被運行 --%>
本身定義標籤
傳統標籤
本身定義標籤主要用於移除JSP頁面中的java代碼
生命週期:當jsp運行到此標籤時,建立此標籤類的對象,而後此標籤類對象會在關閉server時銷燬
要使用本身定義標籤移除jsp頁面中的java代碼,僅僅需要完畢下面兩個步驟:
一、編寫一個實現Tag接口的java類(或者繼承Tag的實現類TagSupport,把頁面java代碼移到這個java類中(標籤處理器);
二、編寫標籤庫描寫敘述符(tld)文件,在tld文件裏把標籤處理器類描寫敘述成一個標籤
Tag接口中的方法
doEndTag();
當讀取到標籤結束符時,會調用此方法
doStartTag();
當讀取到標籤開始符時,會調用此方法
getParent();
獲得此標籤的父節點
release();
釋放執行當前標籤所佔的資源
setPageContext(
PageContext pc);
設置當前標籤的pageConotext對象(此標籤會由運行引擎調用,並傳入當前jsp標籤中的pageContext對象)
演示樣例:(用標籤在jsp頁面獲取IP地址)
標籤類
//定義一個標籤類,必須實現Tag接口,或者繼承Tag接口的TagSupport實現類
/*
//第一種方法:實現Tag接口(介紹了此接口中方法的調用順序, 也可以查看與調用此標籤的JSP文件所相應的servlet中的代碼)
public class Test1 implements Tag{
private PageContext pageContext = null;
private Tag tag = null;
//當讀取完當前標籤開始符時,會調用此方法
@Override
public int doStartTag() throws JspException {
// TODO Auto-generatedmethod stub
HttpServletRequest request = (HttpServletRequest)pageContext.getRequest();
String ip = request.getRemoteAddr();
JspWriter out = pageContext.getOut();
try {
out.write(ip);
} catch (IOException e) {
// TODO Auto-generatedcatch block
throw new RuntimeException(e);//此異常不會再調用時不會拋給調用者,會直接拋給JVM
}
return 0;
}
//當讀取完當前標籤結束符時會調用此方法
@Override
public int doEndTag() throws JspException {
// TODO Auto-generatedmethod stub
return 0;
}
//設置當前標籤的pageContext對象(系統調用,此方法會最早被調用)
@Override
public void setPageContext(PageContext pageContext) {
// TODO Auto-generatedmethod stub
this.pageContext = pageContext;
}
//設置當前標籤的父節點(系統調用,當調用完setPageContext方法後就會調用此方法,假設沒有父節點會傳入一個null)
@Override
public void setParent(Tag tag) {
// TODO Auto-generatedmethod stub
this.tag = tag;
}
//獲得此標籤的父節點
@Override
public Tag getParent() {
// TODO Auto-generatedmethod stub
return this.tag;
}
//關閉標籤所佔用的資源(系統調用,此方法通常用於釋放標籤工做時所生成的資源,此方法會時最後被調用,比doEndTag()方法還要後調用)
@Override
public void release() {
// TODO Auto-generatedmethod stub
}
}
*/
//另一種方法:繼承Tag接口的TagSupport實現類(推薦,因爲繼承此方法不需要重寫其它的方法)
public class Test1 extends TagSupport{
//當讀取到標籤開始符時,會調用此方法
@Override
public int doStartTag() throws JspException {
// TODO Auto-generatedmethod stub
//經過pageContext對象來獲取request對象
HttpServletRequest request = (HttpServletRequest)this.pageContext.getRequest();
//經過request對象來獲取到客戶機的IP地址
String ip = request.getRemoteAddr();
//經過pageContext對象獲取到out緩存輸出對象
JspWriter out = this.pageContext.getOut();
try {
//向緩存對象中加入此ip
out.write(ip);
} catch (IOException e) {
// TODO Auto-generatedcatch block
throw new RuntimeException(e);
}
return super.doStartTag();
}
}
在tld文件裏註冊標籤類(通常放在WEB-INF文件夾下。因爲當jsp文件用tld文件的uri名導入標籤庫時,jsp會默認到WEB-INF文件夾下去找此文件)
<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/j2eehttp://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<!-- 標籤的描寫敘述 -->
<description>A tag libraryexercising SimpleTag handlers.</description>
<!-- 版本號 -->
<tlib-version>1.0</tlib-version>
<!-- 名稱(可以不改動) -->
<short-name>scxh</short-name>
<!-- 將此文件裏標籤綁定到一個uri上(映射名稱) -->
<uri>http://www.scxh.cn</uri>
<!-- 註冊標籤 -->
<tag>
<!-- 此標籤類的映射名稱 -->
<name>printIP</name>
<!-- 標籤類的完整名稱 -->
<tag-class>cn.scxh.Test1</tag-class>
<!-- 標籤內容爲空 -->
<body-content>empty</body-content>
</tag>
</taglib>
在JSP中調用此標籤
<%@ page language="java"import="java.util.*" pageEncoding="UTF-8"%>
<%--導入標籤,併爲此標籤取一個代號 --%>
<%--第一種方式:直接導入標籤uri --%>
<%--@taglib uri="http://www.scxh.cn"prefix="test1"--%>
<%--另一種方式:直接導入標籤文件的路徑 --%>
<%--@taglib uri="WEB-INF/test1.tld"prefix="test1"--%>
<%--第三種方式:導入在web.xml文件裏配置的變量名(推薦) --%>
<%@taglib uri="testtab" prefix="test1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'Test1.jsp'starting page</title>
</head>
<body>
你的IP地址爲:<test1:printIP/>
</body>
</html>
使用第三種方式導入標籤需在xml文件裏設置
<jsp-config>
<taglib>
//取一個映射名稱(uri)
<taglib-uri>testtab</taglib-uri>
//設置tld文件的路徑(必須是路徑,不能是tld文件的uri)
<taglib-location>/WEB-INF/test1.tld</taglib-location>
</taglib>
</jsp-config>
本身定義標籤的擴張功能
Tag接口中的常量
EVAL_BODY_INCLUDE 表示運行標籤體中的內容(doStartTag()方法返回值引用)
SKIP_BODY 表示不運行標籤體中內容(doStartTag()方法返回值引用)
EVAL_PAGE 表示繼續運行餘下的JSP內容(doEndTag()方法返回值引用)
SKIP_PAGE 表示不運行餘下的JSP內容(doEndTag()方法返回值引用)
控制Jsp頁面某一部份內容是否運行
調用doStartTag()(此方法會在讀取完標籤開始符時調用)方法.假設此方法的返回值爲Tag.SKIP_BODY表示不運行標籤中的內容;假設返回的是Tag. EVAL_BODY_INCLUDE表示運行此標籤中的內容
演示樣例:
標籤類
//控制標籤體的內容是否輸出
public class Test2 extends TagSupport{
@Override
public int doStartTag() throws JspException {
// TODO Auto-generatedmethod stub
return Tag.SKIP_BODY;//表示不輸出標籤中的內容
//return Tag.EVAL_BODY_INCLUDE;//表示輸出標籤中的內容
}
}
在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/j2eehttp://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<!-- 此文件通常放在WEB-INF文件夾下,因爲當jsp文件用tld文件的uri名導入標籤庫時,jsp會默認到WEB-INF文件夾下去找此文件 -->
<!-- 標籤的描寫敘述 -->
<description>A tag libraryexercising SimpleTag handlers.</description>
<!-- 版本號 -->
<tlib-version>1.0</tlib-version>
<!-- 名稱(可以不改動) -->
<short-name>scxh</short-name>
<!-- 將此文件裏標籤綁定到一個uri上(映射名稱) -->
<uri>http://www.scxh.cn</uri>
<!-- 註冊標籤 -->
<tag>
<!-- 此標籤類的映射名稱 -->
<name>print</name>
<!-- 標籤類的完整名稱 -->
<tag-class>cn.scxh.Test2</tag-class>
<!-- 標籤內容爲JSP。此值需大寫-->
<body-content>JSP</body-content>
</tag>
</taglib>
JSP中調用此標籤
<%@ page language="java"import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="labelTag"prefix="label" %>
<!DOCTYPE HTMLPUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'Test2.jsp'starting page</title>
</head>
<body>
<%-- 控制標籤中的內容是否被運行 --%>
<label:print>
<p>控制此內容是否被輸出</p>
</label:print>
</body>
</html>
控制整個jsp頁面是否運行
調用doEndTag()(此方法會在讀取完標籤結束符時調用)方法.假設此方法的返回值爲Tag.SKIP_PAGE表示不運行此標籤後面的JSP代碼;假設返回的是Tag. EVAL_PAGE表示運行此標籤後面的JSP代碼
演示樣例:
標籤類
//控制此標籤後的JSP是否還運行
public class Test3 extends TagSupport{
//當讀取完當前標籤結束符時會調用此方法
@Override
public int doEndTag()throws JspException {
//returnTag.SKIP_PAGE;//表示不運行此標籤後面的JSP代碼
return Tag. EVAL_PAGE;//表示運行此標籤後面的JSP代碼
}
}
在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/j2eehttp://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<!-- 此文件通常放在WEB-INF文件夾下。因爲當jsp文件用tld文件的uri名導入標籤庫時,jsp會默認到WEB-INF文件夾下去找此文件 -->
<!-- 標籤的描寫敘述 -->
<description>A tag libraryexercising SimpleTag handlers.</description>
<!-- 版本號 -->
<tlib-version>1.0</tlib-version>
<!-- 名稱(可以不改動) -->
<short-name>scxh</short-name>
<!-- 將此文件裏標籤綁定到一個uri上(映射名稱) -->
<uri>http://www.scxh.cn</uri>
<!-- 註冊標籤 -->
<tag>
<!-- 此標籤類的映射名稱 -->
<name>execution</name>
<!-- 標籤類的完整名稱 -->
<tag-class>cn.scxh.Test3</tag-class>
<!-- 標籤內容爲空 -->
<body-content>empty</body-content>
</tag>
</taglib>
JSP中調用此標籤
<%@ page language="java"import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="labelTag"prefix="label"%>
<!DOCTYPE HTMLPUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'Test3.jsp'starting page</title>
</head>
<body>
<label:execution/>
This ismy JSP page. <br>
<p>測試label:execution標籤後面的JSP是否運行</p>
</body>
</html>
控制標籤內容是否反覆運行
此方法需要用到TagSupport父類中的public int doAfterBody();方法,此方法會在讀取完當前內容後調用,在運行doEndTag()方法前被調用,假設doAfterBody();方法返回的是IterationTag. EVAL_BODY_AGAIN的話,表示此方法中的內容繼續被輸出。假設返回的是IterationTag.SKIP_BODY,表示此方法中的內容不被輸出;但必定要讓doStartTag()方法的返回值爲Tag.EVAL_BODY_INCLUDE;表示運行標籤中的內容
演示樣例:
標籤類
//控制標籤中內容反覆輸出5此
public class Test4 extends TagSupport{
private int i = 5;
//必定要讓此方法的返回值爲Tag.EVAL_BODY_INCLUDE;表示運行標籤中的內容
@Override
public int doStartTag() throws JspException {
// TODO Auto-generatedmethod stub
return Tag.EVAL_BODY_INCLUDE;
}
@Override
public int doAfterBody() throws JspException {
i--;
if(i>0){
return IterationTag.EVAL_BODY_AGAIN;//返回此常量表示繼續輸出標籤中的內容
}else{
return IterationTag.SKIP_BODY;//返回此常量表示不輸出標籤中的內容
}
}
}
在tld文件裏註冊標籤類
<!-- 註冊標籤 -->
<tag>
<!-- 此標籤類的映射名稱 -->
<name>print5</name>
<!-- 標籤類的完整名稱 -->
<tag-class>cn.scxh.Test4</tag-class>
<!-- 標籤內容爲空 -->
<body-content>JSP</body-content>
</tag>
JSP中調用此標籤
<%@ page language="java"import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="labelTag"prefix="label"%>
<!DOCTYPE HTMLPUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'Test4.jsp'starting page</title>
</head>
<%--讓標籤中的內容輸出5次 --%>
<body>
<label:print5>
<p>此處會被輸出5次</p>
</label:print5>
</body>
</html>
改動標籤內容後再輸出
標籤類需要繼承BodyTagSupport類,並重寫doStartTag();方法,讓其返回值爲BodyTag.EVAL_BODY_BUFFERED;讓此標籤的內容封裝成一個對象,系統再經過調用此標籤對象的setBodyContent(BodyContent b)方法將標籤內容對象傳入; 而後咱們再重寫doEndTag();方法。getBodyContent()方法經過獲取到內容對象,再對此對象改動後經過out緩存輸出到jsp
演示樣例:
標籤類
//將標籤中的字母轉換爲大寫
public class Test5 extends BodyTagSupport{
@Override
public int doStartTag() throws JspException {
// TODO Auto-generatedmethod stub
return BodyTag.EVAL_BODY_BUFFERED;//讓此標籤的內容封裝成一個對象,系統再經過調用此標籤對象的
//setBodyContent(BodyContent b)方法將標籤內容對象傳入;
}
@Override
public int doEndTag() throws JspException {
BodyContent content = this.getBodyContent();//經過此方法獲得內容對象
String str = content.getString();//將內容對象以字符串返回
str = str.toUpperCase();//將字符串中的所有字母都變爲大寫
try {
pageContext.getOut().write(str);//將轉換事後的字符串輸出到JSP
} catch (IOException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
return super.doEndTag();
}
}
在tld文件裏註冊標籤類
<!-- 註冊標籤 -->
<tag>
<!-- 此標籤類的映射名稱 -->
<name>uppercase</name>
<!-- 標籤類的完整名稱 -->
<tag-class>cn.scxh.Test5</tag-class>
<!-- 標籤內容爲空 -->
<body-content>JSP</body-content>
</tag>
JSP中調用此標籤
<%@ pagelanguage="java" import="java.util.*"pageEncoding="UTF-8"%>
<%@taglib uri="labelTag"prefix="label"%>
<!DOCTYPE HTMLPUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'Test5.jsp'starting page</title>
</head>
<%--將標籤中的字母轉換大寫 --%>
<body>
<label:uppercase>
<p>此處的字母會被轉換爲大寫:abcdef</p>
</label:uppercase>
</body>
</html>
簡單標籤
簡單標籤需要實現SimpleTag接口或繼承它的實現類SimpleTagSupport,經過這個接口或這個它的實現類就可以完畢上面複雜標籤的所有功能
生命週期:當jsp運行到此標籤時,建立此標籤類的對象,當整個jsp(servlet)運行完畢後這個標籤類對象就被釋放了
SimpleTagSupport類的方法(按運行順過排序);當讀到一個標籤後會調用標籤類的這些方法
setJspContext(
JspContext pc);
此方法由JSP的serlvet最早調用(可以看着是系統調用),將pageContext對象傳入;
setParent(JspTag parent); 系統調用,會將此標籤的父節點當作一個對象傳入,假設沒有父節點,就傳入null
setJspBody(
JspFragment jspBody);
此方法會由JSP的servlet調用,並將標籤的內容封裝成對象後傳入。
doTag();
此方法會在上面標籤運行完畢後才被運行(由程序猿寫操做語句)
getJspBody();
獲得標籤的內容對象(由程序猿調用)
getJspContext(); 獲得調用此標籤的pageContext對象(由程序猿調用)
getParent();
獲得當前標籤的父節點標籤(由程序猿調用)
案例:
控制標籤體中的內容是否被運行
java標籤類中的內容
//控制標籤體中的內容是否被運行
public class Test1 extends SimpleTagSupport{
//此方法會在系統調用完父類的所有set*方法後,才調用此方法
@Override
public void doTag()throws JspException, IOException {
//假設要輸出標籤中的內容就使用下面方法。假設不輸出標籤內容就什麼也不作
//獲得標籤中的內容對象
JspFragment body = this.getJspBody();
//獲得JSP的pageContext對象
JspContext pageContext = this.getJspContext();
//將內容對象輸入到JSP的out對象中
body.invoke(pageContext.getOut());//也可以寫爲body.invoke(null);此內容將默認輸出到pageContext.getOut()對象中
}
}
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/j2eehttp://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<!-- 此文件通常放在WEB-INF文件夾下,因爲當jsp文件用tld文件的uri名導入標籤庫時,jsp會默認到WEB-INF文件夾下去找此文件 -->
<!-- 標籤的描寫敘述 -->
<description>A tag libraryexercising SimpleTag handlers.</description>
<!-- 版本號 -->
<tlib-version>1.0</tlib-version>
<!-- 名稱(可以不改動) -->
<short-name>scxh</short-name>
<!-- 將此文件裏標籤綁定到一個uri上(映射名稱) -->
<uri>http://www.scxh.cn</uri>
<!-- 註冊標籤 -->
<tag>
<!-- 此標籤類的映射名稱 -->
<name>print</name>
<!-- 標籤類的完整名稱 -->
<tag-class>com.scxh.Test1</tag-class>
<!-- 表示標籤內容不能爲腳本代碼(java代碼)。還可以有JSP表示可以java代碼。empty表示此標籤沒有標籤內容 -->
<body-content>scriptless</body-content>
</tag>
</taglib>
JSP文件裏的內容
<%@ pagelanguage="java" import="java.util.*"pageEncoding="UTF-8"%>
<%@taglib uri="labelSimpleTag"prefix="label" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTMLPUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp'starting page</title>
<meta http-equiv="pragma"content="no-cache">
<meta http-equiv="cache-control"content="no-cache">
<meta http-equiv="expires"content="0">
<meta http-equiv="keywords"content="keyword1,keyword2,keyword3">
<meta http-equiv="description"content="This is my page">
<!--
<link rel="stylesheet"type="text/css" href="styles.css">
-->
</head>
<%--控制標籤體中的內容是否被運行 --%>
<body>
<label:print>
<p>控制此內容是否被運行</p>
</label:print>
</body>
</html>
控制標籤體中的內容反覆運行5次
僅僅需將上面java標籤類中
//將內容對象輸入到JSP的out對象中
body.invoke(pageContext.getOut());
的此代碼用for循環運行5次就能夠
將標籤體中的字母變爲大寫(改動標籤體的內容)
僅僅需要將上面java標籤類中doTag()方法中的代碼改爲
//將標籤體內容中的字母變爲大寫
@Override
public void doTag() throws JspException, IOException {
//獲得標籤中的內容對象
JspFragment body = this.getJspBody();
//建一個緩存流對象
StringWriter buffer = new StringWriter();
//將內容對象當作一個字符串輸出到一個緩衝對象中
body.invoke(buffer);
//取出緩存流對象中的內容
String content = buffer.toString();
//關閉緩衝流
buf.flush();
buf.close();
//再將內容中的小寫轉爲大寫
String content1 = content.toUpperCase();
//再將此內容放入到out對象中
this.getJspContext().getOut().write(content1);
}
控制此標籤後的JSP是否被運行
僅僅需要將上面java標籤類中doTag()方法中的代碼改成
//控制標籤後的JSP是否繼續被運行
@Override
public void doTag() throws JspException, IOException {
//僅僅需要在此方法中拋出此異常,那麼此標籤後面的JSP將不會被運行
throw new SkipPageException();
}
標籤的屬性
假設想要本身定義標籤具備屬性,需要在標籤處理器中編寫每個屬性相應成員變量及它的的set方法和在tld文件裏描寫敘述標籤的屬性;系統當讀取到標籤屬性時會本身主動調用此標籤類與之相應的成員變量名的set方法將屬性的值傳入;
演示樣例:
java標籤類中的代碼
//讓標籤中的內容輸出屬性count值所有指定的次數
public class Test2 extends SimpleTagSupport{
private int count = 0;
//當讀取到與標籤中count對象時會調用此方法(按名稱相應,經過javaBean實現)
public void setCount(int count) {
this.count = count;
}
@Override
public void doTag() throws JspException, IOException {
// TODO Auto-generatedmethod stub
//將內容輸出conut這麼屢次
for(int i=0; i<count; i++){
this.getJspBody().invoke(null);
}
}
}
tld文件裏的內容
<!-- 註冊標籤 -->
<tag>
<!-- 此標籤類的映射名稱 -->
<name>printCount</name>
<!-- 標籤類的完整名稱 -->
<tag-class>com.scxh.Test2</tag-class>
<!-- 表示標籤內容不能爲腳本代碼(java代碼),還可以有JSP表示可以java代碼,empty表示此標籤沒有標籤內容 -->
<body-content>scriptless</body-content>
<!-- 表示爲此標籤聲明一個屬性 -->
<attribute>
<!-- 指定屬性的名稱 -->
<name>count</name>
<!-- 表示此屬性是不是必須的 -->
<required>true</required>
<!-- 表示此屬性的值可否夠是一個表達式(可否夠是LE表達式等) -->
<rtexprvalue>true</rtexprvalue>
<!-- 還可以指定屬性值的類型(必須是java的完整類名)。不寫此標籤表示接收一個Object類型 -->
<!-- <type>java.lang.Integer</type> -->
</attribute>
</tag>
JSP文件裏的內容
<%@ pagelanguage="java" import="java.util.*"pageEncoding="UTF-8"%>
<%@taglib uri="labelSimpleTag"prefix="label"%>
<!DOCTYPE HTMLPUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'Test2.jsp'starting page</title>
</head>
<%--讓標籤中的內容輸出屬性count值所有指定的次數 --%>
<body>
<label:printCount count="5">
<p>標籤中的內容</p>
</label:printCount>
</body>
</html>
用本身定義標籤遍歷所有的集合及所有的數組
java標籤類中的代碼
public class ForEach extends SimpleTagSupport{
//所有單列集合的父接口
private Collection items = null;
//用於存儲在域對象中的key
private String var = null;
//將傳入的對象都轉換爲一個單列集合
public void setItems(Object items) throws Exception{
if(items==null){//假設傳入的是null
return;
}else if(items instanceof Collection){//假設傳入的對象時一個單例集合
this.items = (Collection)items;//就將這個對象強轉換Collection(所有單列集合的父接口)對象
}else if(items instanceof Map){//假設傳入的是一個map集合
Map map = (Map)items;//就將其強轉換Map(所有雙列集合的父接口)對象
this.items = map.entrySet();//將其轉換爲一個entrySet的單例集合中
}else if(items.getClass().isArray()){//假設傳入的是一個數組
List list = new LinkedList();//就將其裝入一個list集合中
int len = Array.getLength(items);//經過Array類反射出此數組對象的長度
for(int i=0; i<len; i++){//遍歷數組,將值存入list集中
list.add(Array.get(items,i));//經過Array類反射出items數組對象下標爲i的值
}
this.items = list;//將list集合賦給成員變量
}else{
throw new Exception("你傳入的不是一個集合也不是一個數組");
}
}
public void setVar(String var) {//接收用於存儲在域中的key
this.var = var;
}
@Override
public void doTag() throws JspException, IOException {
if(this.items==null){
return;
}
//獲取單列集合的迭代器
Iterator it = items.iterator();
//迭代這個集合
while(it.hasNext()){
Objectvalue = it.next();
this.getJspContext().setAttribute(var, value);//迭代出來的值向pageContext域中存
this.getJspBody().invoke(null);//運行此標籤的內容,(讓EL表達式從域中去取key爲「var」的值)
}
}
}
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/j2eehttp://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<!-- 此文件通常放在WEB-INF文件夾下。因爲當jsp文件用tld文件的uri名導入標籤庫時,jsp會默認到WEB-INF文件夾下去找此文件 -->
<!-- 標籤的描寫敘述 -->
<description>A tag libraryexercising SimpleTag handlers.</description>
<!-- 版本號 -->
<tlib-version>1.0</tlib-version>
<!-- 名稱(可以不改動) -->
<short-name>scxh</short-name>
<!-- 將此文件裏標籤綁定到一個uri上(映射名稱) -->
<uri>http://www.scxh.com.cn</uri>
<!-- 註冊標籤 -->
<tag>
<!-- 此標籤類的映射名稱 -->
<name>forEach</name>
<!-- 標籤類的完整名稱 -->
<tag-class>com.foreach.ForEach</tag-class>
<!-- 表示標籤內容不能爲腳本代碼(java代碼)。還可以有JSP表示可以java代碼,empty表示此標籤沒有標籤內容 -->
<body-content>scriptless</body-content>
<!-- 表示爲此標籤聲明一個屬性 -->
<attribute>
<!-- 指定屬性的名稱 -->
<name>var</name>
<!-- 表示此屬性是不是必須的 -->
<required>true</required>
<!-- 表示此屬性的值可否夠是一個表達式(可否夠是LE表達式等) -->
<rtexprvalue>true</rtexprvalue>
<!-- 表示此屬性值得類型 -->
<type>java.lang.String</type>
</attribute>
<!-- 表示爲此標籤聲明一個屬性 -->
<attribute>
<!-- 指定屬性的名稱 -->
<name>items</name>
<!-- 表示此屬性是不是必須的 -->
<required>true</required>
<!-- 表示此屬性的值可否夠是一個表達式(可否夠是LE表達式等) -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
JSP文件裏的內容
<%@ page language="java"import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://www.scxh.com.cn"prefix="c"%>
<!DOCTYPE HTMLPUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'Test1.jsp'starting page</title>
</head>
<!-- 重寫JSTL標籤中的forEach標籤。(遍歷數組、集合) -->
<body>
<%
List list = new ArrayList();
list.add("list1");
list.add("list2");
list.add("list2");
list.add("list4");
list.add("list5");
pageContext.setAttribute("list", list);
%>
<%
Map map = new HashMap();
map.put("1", "map1");
map.put("2", "map2");
map.put("3", "map3");
map.put("4", "map4");
map.put("5", "map5");
pageContext.setAttribute("map", map);
%>
<%
int[] nums = new int[]{1,2,3,4,5,6};
pageContext.setAttribute("nums", nums);
%>
<%
boolean[] bools = new boolean[]{true,false,true};
pageContext.setAttribute("bools", bools);
%>
<br/>------------------------遍歷list集合---------------------------------<br/>
<c:forEach var="str"items="${list }" >
${str }
</c:forEach>
<br/>------------------------遍歷map集合---------------------------------<br/>
<c:forEach var="entry"items="${map }">
key: ${entry.key } ,value: ${entry.value }
</c:forEach>
<br/>------------------------遍歷int數組---------------------------------<br/>
<c:forEach var="i"items="${nums }">
${i }
</c:forEach>
<br/>------------------------遍歷boolean數組---------------------------------<br/>
<c:forEach var="bool"items="${bools }">
${bool }
</c:forEach>
</body>
</html>
屬性值的類型說明(屬性的值必須用」」引發來,EL表達式和<%= %>也同樣)
假設在標籤屬性中傳入一個字符串」5.5」,而在標籤類中與此屬性名相應成員變量是一個float類型的話,系統會本身主動將字符串轉換爲Float類型,但僅僅會本身主動轉換八大基本類型;
假設標籤類中的成員變量是一個對象,那麼標籤屬性在傳入值時必須要是一個對象,如:標籤類中的屬性是一個Date對象,引用變量名爲date;那麼標籤屬性的值必須是date=」<%=new Date()%>」;或者用EL表達式傳入一個Date對象,否則系統不能本身主動轉換
JSTL標籤
EL表達式可以經過JSTL標籤。迭代集合等功能
JSTL是SUN公司開發的一套標籤庫,使用JSTL可以在頁面中實現一些簡單的邏輯,從而替換頁面中的腳本代碼
在JSP中使用JSTL標籤需完畢下面兩個步驟
一、 導入jstl.jar和standerd.jar這兩個JSTL的jar包
二、 在JSP頁面使用<%@taglib url=」 http://java.sun.com/jsp/jstl/core」 prifix=」c」 %> 元素導入標籤庫
url的地址是standerd.jar包中的/META-INF/c.tld文件裏的<uri>http://java.sun.com/jsp/jstl/core </uri>標籤中的地址
核心標籤
<%@page import="java.net.URLEncoder"%>
<%@page import="cn.scxh.Person"%>
<%@ page language="java"import="java.util.*" pageEncoding="UTF-8"%>
<%--導入JSTL包--%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core"prefix="c"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTMLPUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp'starting page</title>
<meta http-equiv="pragma"content="no-cache">
<meta http-equiv="cache-control"content="no-cache">
<meta http-equiv="expires"content="0">
<meta http-equiv="keywords"content="keyword1,keyword2,keyword3">
<meta http-equiv="description"content="This is my page">
<!--
<link rel="stylesheet"type="text/css" href="styles.css">
-->
</head>
<body>
<br/>----------------------------out標籤的使用--------------------------------<br/>
<%-- out標籤用於向瀏覽器輸出內容 --%>
<%-- value的值爲null時。輸出default的值 --%>
<c:out value="${aaaaa }" default="aaa"></c:out>
<%-- escapeXml="true"表示將輸出的內容轉義後輸出 --%>
<c:out value="此標籤會原樣輸出<a></a>" escapeXml="true"></c:out>
<br/>----------------------------set標籤的使用--------------------------------<br/>
<%--set標籤用於把某一個對象存在指定的域範圍,
或者設置Web域中的Map類型的屬性對象或者javaBean類型的的屬性對象的屬性 --%>
<%-- 給data這個key賦值爲:「xxx」。並存入pageContext對象中--%>
<c:set var="data" value="xxx"scope="page"></c:set>
${data }<%--輸出此date,查看data的值是不是xxx --%>
<%--將值存入map集合中 --%>
<%
Map map = new HashMap();
pageContext.setAttribute("map", map);
%>
<%-- 設置key 設置value 設置要存入的map集合 --%>
<c:set property="m1" value="map1"target="${map }"></c:set>
${map.m1 }<%--輸出map中m1中的值測試是否存入 --%>
<%--將值賦值給相應的javaBean對象 --%>
<%
Person person = new Person();
pageContext.setAttribute("person", person);
%>
<%--設置javaBean的屬性 設置要此屬性賦的值 設置要賦值的javaBean對象 --%>
<c:set property="name" value="張三" target="${person }"></c:set>
${person.name }<%--輸出此對象的name,測試是否被賦值 --%>
<br/>----------------------------catch標籤的使用--------------------------------<br/>
<%--用於捕獲異常對象,並存入pageContext對象中 --%>
<c:catch var="exception"><%--var是設置此異常對象存入pageContext中的key --%>
<%
int i = 1/0;
%>
</c:catch>
${exception.message }<%--輸出此錯誤對象的異常描寫敘述,測試pageContext對象中是否有此對象 --%>
<br/>----------------------------if標籤的使用--------------------------------<br/>
<%-- 設置存儲在域中的key 推斷的表達式 設置此表達式的值的存儲域--%>
<c:if var="aaa" test="${user==null }"scope="page">
你還沒登錄
</c:if>
${aaa }<%--輸出表達式的結果 --%>
<br/>----------------------------choose標籤的使用--------------------------------<br/>
<%--和if else同樣 --%>
<c:choose>
<c:when test="${1+1==2 }">
你算對了
</c:when>
<c:otherwise>
你算錯了
</c:otherwise>
</c:choose>
<br/>----------------------------foreach標籤的使用--------------------------------<br/>
<%--遍歷數組或集合 --%>
<%
List list = new ArrayList();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
pageContext.setAttribute("list", list);
%>
<%--設置存儲在域中的key 設置要遍歷的集合或數組--%>
<c:forEach var="str" items="${list }">
${str }
</c:forEach><br/>
<%--還可以當作for循環使用 --%>
<%--設置存儲在域中的key 設置開始的數 設置結束的數 設置循環的步長--%>
<c:forEach var="num" begin="1" end="9" step="1">
${num }
</c:forEach>
<br/>
<%-- 用forEach實現表格間色顯示 --%>
<%
List list1 = new ArrayList();
list1.add("aaa");
list1.add("bbb");
list1.add("ccc");
list1.add("ddd");
list1.add("ddd");
list1.add("ddd");
pageContext.setAttribute("list1", list1);
%>
<style type="text/css">
.odd{ background-color: #E6B489}
.even{background-color: #EF6756}
tr:hover{background-color: #D7DBE5}
</style>
<table border="1" width="20%"><%--varStatus="n"這個"n"用於記住當前遍歷的次數(n.count) --%>
<c:forEach var="str"items="${list1 }" varStatus="status">
<tr class="${status.count%2==0?
'even' : 'odd' }">
<td>${str }</td>
</tr>
</c:forEach>
</table>
<br/>----------------------------url標籤的使用--------------------------------<br/>
<%--又一次構建URL的地址,在URL後面加上session的id。並且此url前面沒有加project名,重構事後會本身主動加上 --%>
<c:url var="ur" value="/Test1.jsp"><%--重構事後的超連接:/jstl/Test1.jsp;jsessionid=CC2C99E7E3C1B3255B647C67502096EA?name=%e4%b8%ad%e5%9b%bd--%>
<%--假設在url標籤內嵌套此標籤,表示在url後面加入傳遞參數:?name=zhangsan --%>
<c:param name="name"value="中國"></c:param><%--假設value的值是中文。此標籤會本身主動調用
URLEncoder.encode(temp,"UTF-8");進行加碼--%>
</c:url>
<a href="${ur }">此超連接的url後面跟有session對象的id</a>
<br/>----------------------------forTokens標籤的使用--------------------------------<br/>
<%-- 用於切割字符串 --%>
<%
String str = "aaa,bbb,cccc,ddd,eeee";
pageContext.setAttribute("str", str);
%>
<%--存儲每次切割字符到域的key 要被切割的字符串 以什麼切割--%>
<c:forTokens var="ss" items="${str }" delims=",">
${ss }<br/>
</c:forTokens>
<br/>----------------------------remove標籤的使用--------------------------------<br/>
<%
pageContext.setAttribute("page1", "page1");
%>
${page1 }
<c:remove var="page1" scope="page"/><%--移除page域中的映射關係 --%>
${page1 }
</body>
</html>
<br/>--------------------import標籤和jsp:include標籤同樣使用(相同是動態包括)--- ----------------<br/>
<br/>--------------------redirect標籤是請求重定向--------------------------<br/>
軟件國際化(i18n:internationalization)
軟件開發時。要使它能同一時候因對世界不一樣地區和國家的訪問,並針對不一樣地區和國家的訪問,提供對應的、符合來訪者閱讀習慣的頁面或數據,
此運行文件JDK_1.7_X64\jdk\ben\native2ascii.exe用於將中文轉換成unicode編碼
國際化所具有的特徵:
對程序中國固定的文本元素或錯誤提示信息。狀態信息等需要依據來訪者的地區和國家選擇不一樣語言的文本爲之服務
對程序動態產生的數據,如(日期,貨幣等)軟件應用能依據當前所在的國家或地址的文化習慣進行顯示
資源包(功能名稱國際化)
對於軟件中的菜單條、導航條、錯誤提示信息,狀態信息等這些固定的文本信息,可以把它們寫在一個properties文件裏,並依據不一樣的國家編寫不一樣的properties文件,這一組properties文件稱之爲一個資源包
資源文件的名稱規範
基名_語言_國家 如:mag_zh_CN mag就表示:基名 , zh表示:漢語。CN表示:中國; i18n_en_US i18n表示:基名。en表示:英語。US表示:美國
Locale類是一個區域信息類,裏面有很是多表明國家和語言的常量
假設一個文件名稱就爲mag,那麼這個文件就是一個默認的文件。當沒有找到語言包時就找此文件
在javaAPI中提供了一個ResourceBundle類用於描寫敘述一個資源包,並且ResourceBundle類提供了相應的方法getBundle,這種方法可以依據來訪者的國家地區本身主動獲取與之相應的資源文件予以顯示
演示樣例:(當瀏覽器請求的是zh_CN。就將i18n_zh_CN.properties文件返回,假設瀏覽器請求的是en_US就將i18n_en_US.properties文件返回)
<%@ page language="java"import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTMLPUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN">
<html>
<head>
<title>登陸</title>
</head>
<%
Locale locale = request.getLocale();//獲取瀏覽器的語言(此類中有很是多表明國家和語言的常量)
ResourceBundle rb = ResourceBundle.getBundle("lang.i18n",locale);//經過語言來獲取相應的基名爲i18n的文件
%>
<body>
<p><%=rb.getString("i18n.Test1.title") %></p><%--獲取此文件裏「i18n.Test1.title」這個key 的值,如下其它的都同樣 --%>
<form action="#">
<%=rb.getString("i18n.Test1.username") %><input type="text"/><br/>
<%=rb.getString("i18n.Test1.password") %><input type="text"/><br/>
<input type="submit"value="<%=rb.getString("i18n.Test1.submit") %>"/>
</form>
</body>
</html>
數字國際化
int i = 1000000;
NumberFormat number = NumberFormat.getCurrencyInstance();
String str = number.format(i);
System.out.println(str);//打印爲:¥ 1,000,000.00
number = NumberFormat.getCurrencyInstance(Locale.US);
str = number.format(i);
System.out.println(str);//打印爲:$1,000,000.00
float f = 0.5f;
number = NumberFormat.getPercentInstance();
str = number.format(f);
System.out.println(str);//打印爲:50%
過濾器(Filter)
WEB開發者經過Filter(過濾器)技術,對webserver管理的所有WEB資源,如:JSP,Servlet。靜態圖片文件或靜態html文件等進行攔截,從而實現一些特殊的功能。
好比實現URL主要的權限訪問控制、過濾敏感詞彙、壓縮響應信息等一些高級功能。假設一個資源被兩個過濾器同一時候過濾,前後順序看在web.xml配置文件裏<filter-mapping>標籤的前後順序
ServletAPI中提供了一個Filter接口,假設一個類實現了Filter接口,那麼這個類就是一個過濾器類。經過這個Filter。開發者可以實現用戶在訪問某個目標資源以前,對訪問的請求和響應進行攔截
過濾器的聲明週期:在servlet建立時建立,並永久駐留在內存中,在servlet銷燬時銷燬。當過濾器建立時會調用init(FilterConfig arg0);方法。銷燬時會調用destroy();方法
演示樣例:
經過過濾器讓用戶訪問的所有資源的編碼格式爲UTF-8
過濾器中的代碼
public class FilterDemo1 implements Filter{
private String code = null;
//當實用於訪問/*(此web下資源時)就會訪問此過濾器
@Override
public void doFilter(ServletRequest request, ServletResponseresponse,
FilterChain arg2) throws IOException,ServletException {
System.out.println("過濾器被運行了");
//將code設置到到request和response及瀏覽器的打開模式中
request.setCharacterEncoding(code);
response.setCharacterEncoding(code);
response.setContentType("text/html;charset="+code);
//表示轉發到用戶所訪問的資源上面去
arg2.doFilter(request,response);
}
//此方法會在過濾器建立時調用
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generatedmethod stub
//獲取xml文件<init-param>標籤中code的value
String code = arg0.getInitParameter("code");
if(code==null)//假設沒有配置,就使用UTF-8默認編碼
code="UTF-8";
this.code = code;
}
//此方法在過濾器銷燬時調用
@Override
public void destroy() {
// TODO Auto-generatedmethod stub
}
}
servlet中代碼
public void doGet(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
//接收JSP傳入的值
String username = request.getParameter("username");
//打印這個值,查看是不是亂碼
response.getWriter().write(username);
}
public void doPost(HttpServletRequest request, HttpServletResponseresponse)
throws ServletException, IOException {
doGet(request, response);
}
web.xml文件裏註冊過濾器
<!-- 註冊過濾器 -->
<filter>
<!—給過濾器取一個名字-->
<filter-name>FilterDemo1</filter-name>
<!—過濾器類的完整名稱-->
<filter-class>cn.scxh.FilterDemo1</filter-class>
<!-- 設置init方法接收的參數 -->
<init-param>
<param-name>code</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<!-- 當訪問此web應用中所有的資源時,都用過濾器攔截 -->
<filter-mapping>
<!—當訪問」/*」如下的資源時。都用FilterDemo1這個過濾器攔截-->
<filter-name>FilterDemo1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
JSP中代碼
<body>
<!—將text中的中文字符傳入Test1這個servlet-->
<form action="${pageContext.request.contextPath }/servlet/Test1" method="post">
<input type="text"name="username"/>
<input type="submit"/>
</form>
</body>
過濾器默認僅僅攔截用戶提交的請求。假設爲server轉發,那麼默認將不會攔截(但可以手動設置如下的標籤進行攔截)
<filter-mapping>
<!—當訪問」/*」如下的資源時。都用FilterDemo1這個過濾器攔截-->
<filter-name>FilterDemo1</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher><!—缺省值是request,表示僅僅對用戶提交的請求攔截,假設寫了其它值。此缺省值將不在生效。但可以手動像這樣再定義一次就也可了-->
<dispatcher>FORWARD</dispatcher><!—表示可以攔截轉發的請求-->
<dispatcher>INCLUDE</dispatcher><!—表示可以攔截動態包括的請求-->
<dispatcher>ERROR</dispatcher><!—表示可以攔截錯誤時跳轉頁面時攔截(在web.xml文件裏配置錯誤頁面這樣的)-->
</filter-mapping>
監聽器(8個監聽4個事件)
在serlvet中定義了多種類型的監聽器,它們用於監聽的事件源分別爲serlvetContext,HttpSession和ServletRequest這三個對象
servlet規範針對這三個域對象(ServletContext。session,request)上的操做,又把這多種類型的監聽器劃分爲三種類型:
監聽三個域對象建立和銷燬的事件監聽器
監聽域對象中的屬性的添加和刪除的事件監聽器
監聽綁定到HttpSession域中的某個對象的狀態的時間監聽器
每個域對象的監聽器中傳入的ServletContextEvent類型的參數都可以獲得當前的域對象。比方session的監聽器可以經過傳入的參數獲取到當前的session域對象。
監聽域對象屬性(映射關係)的事件監聽器還可以經過傳入參數的getName和getValue方法獲取當前操做屬性(映射關係)的key和value
servletContext監聽器
servletContext對象的建立,當web應用被公佈時建立。當卸載web應用時銷燬。並會被實現了ServletContextListener接口的監聽器所監聽到
//監聽servletContext域對象建立和銷燬的監聽器
public class MyServletContextListener implements ServletContextListener{
//當servletContext域對象銷燬時此方法會被運行
@Override
public void contextDestroyed(ServletContextEvent event) {
// TODO Auto-generated method stub
System.out.println("servletContext域對象被銷燬了");
}
//當servletContext域對象建立時此方法會被運行
@Override
public void contextInitialized(ServletContextEvent arg0) {
// TODO Auto-generatedmethod stub
System.out.println("servletContext域對象被建立了");
}
}
//監聽servletContext域對象的屬性的監聽器(當對sevletContext對象域中的映射關係進行增,刪,改時。都會被實現了ServletContextAttributeListener接口的監聽器所監聽到)
public class MyServletContextAttributeListener implementsServletContextAttributeListener{
//當servletContext域對象中加入了新的映射關係就調用此方法
@Override
public void attributeAdded(ServletContextAttributeEvent event) {
// TODO Auto-generatedmethod stub
System.out.println("servletContext域中添加了此映射關係:"+event.getName()+"="+event.getValue());
}
//當servletContext域對象中刪除了映射關係就調用此方法
@Override
public void attributeRemoved(ServletContextAttributeEvent event) {
// TODO Auto-generatedmethod stub
System.out.println("servletContext域中刪除了此映射關係:"+event.getName()+"="+event.getValue());
}
//當servletContext域對象中改動了映射關係的值。就調用此方法
@Override
public void attributeReplaced(ServletContextAttributeEvent event) {
// TODO Auto-generatedmethod stub
System.out.println("servletContext域中改動了此映射關係:"+event.getName()+"="+event.getValue());
}
}
<!-- 註冊監聽器 -->
<listener>
<listener-class>cn.listener.MyServletContextListener</listener-class>
</listener>
<listener>
<listener-class>cn.listener.MyServletContextAttributeListener</listener-class>
</listener>
session域對象和erquest對象的監聽器和上面的方法都同樣。只是需要實現的接口不一樣
監聽session對象的建立和銷燬需要實現HttpSessionListener接口,監聽此域中屬性的監聽器需要實現HttpSessionAttribteListener接口
session對象的建立,當第一次調用request.getSession()方法時建立session對象;
session對象的銷燬,手動調用session對象的invalidate()方法和超時(session對象默認不操做狀況下存活30分鐘)session對象會被銷燬,並會被實現了HttpSessionListener接口的監聽器所監聽到。
當對session對象域中的映射關係進行 增。刪。改時,都會被實現了HttpSessionAttribteListener接口的監聽器所監聽到
監聽request對象的建立和銷燬需要實現ServletRequestListener接口,監聽此域中屬性的監聽器需要實現ServletRequestAttributeListener接口
request對象的建立和銷燬,當用戶每發送一次請求時,request對象就被建立一次,當server返回了response對象後此request對象將被銷燬,並會被實現了ServletRequestListener接口的監聽器所監聽到;
當對request對象域中的映射關係進行 增,刪。改 時,都會被實現了ServletRequestAttributeListener接口的監聽器所監聽到
監聽綁定到HttpSession域中的某個對象的狀態的時間監聽器
感知型監聽器,誰實現了這個些接口,就可以獲取在session域對象中的狀態,這兩種監聽器不需要註冊
HttpSessionActivationListener實現了此接口就可以感知本身什麼時候隨着HttpSession對象鈍化和活化(鈍化和活化的意思是當在server中暫停了當前的web應用。那麼此web應用中的所有域和域中的對象就鈍化了,繼續當前web應用,那麼此web應用中的所有域和域中的對象就活化了)
sessionDidActivate(HttpSessionEvent event);當此對象和session域對象一塊兒活化了時就會調用此方法
sessionWillPassivate(HttpSessionEvent event) ;當此對象和session域對象一塊兒鈍化了時就會調用此方法
HttpSessionBindingListener實現了此接口就可以感知本身什麼時候被加入到了session對象,和被session對象刪除了
valueBound(HttpSessionBindingEventevent);當本身被加入到了session域中時就會調用此方法
valueUnbound(HttpSessionBindingEventevent);當本身被session域對象移除時就會調用此方法
JDBC大數據(MySQL)
大數據分頁
就是指定每次查詢的條數
select* from emp limit m,n;
limitkeyword寫在查詢語句的最後面
m表示 從第幾行開始顯示(0開始算)
n表示 一次顯示多少行
大數據存儲
在實際開發中。通常不需要把大文本或二進制數據保存到數據庫中(會減小查詢效率)
大數據也稱爲LOB,LOB又分爲clob和blob
clob用於 存儲大文本(字符文本)
blob用於存儲二進制數據(圖片,聲音,二進制文件等)
在MySQL中的clob是Text;在MySQL中的Text和blob的類型又分爲:在MySQL中LOB的類型最大的存儲大小爲4G,因此通常要存儲的文件最大不能超過4G
Text:(存儲文本文件)
TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT
blob:(存儲二進制文件)
TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB
如下說明了每種類型的最大存儲大小
列類型 |
存儲需求 |
CHAR(M) |
M個字節,0 <= M <= 255 |
VARCHAR(M) |
L+1個字節,當中L <= M 且0 <= M <= 65535(參見如下的凝視) |
BINARY(M) |
M個字節。0 <= M <= 255 |
VARBINARY(M) |
L+1個字節,當中L <= M 且0 <= M <= 255 |
TINYBLOB, TINYTEXT |
L+1個字節。當中L < 28 爲256B |
BLOB, TEXT |
L+2個字節,當中L < 216 爲64KB |
MEDIUMBLOB, MEDIUMTEXT |
L+3個字節,當中L < 224 爲16M |
LONGBLOB, LONGTEXT |
L+4個字節,當中L < 232 爲4G |
ENUM('value1','value2',...) |
1或2個字節,取決於枚舉值的個數(最多65,535個值) |
SET('value1','value2',...) |
一、二、三、4或者8個字節。取決於set成員的數目(最多64個成員) |
演示樣例1:(向數據庫中存儲一個.txt的文本文件)
MySQL代碼
create table t_temp1(
idint primary key,
data TEXT
)
java代碼
//向數據庫中存取文本文件
public class Test1 {
//設置數據庫配置文件的位置
static{
JDBCUtil3.setPropertiesUrl("db.properties");
}
public static void main(String[] args) {
//把一個文本文件存儲數據庫中
fun1();
//把這個文本文件取出,並存放到指定的文件夾
fun2();
}
private static void fun1() {
//獲取數據庫鏈接
Connection cn = JDBCUtil3.getNewConnection();
//推斷鏈接是否爲null
if(cn == null)
return;
PreparedStatement ps = null;
//傳入要存入的文本文件
File file = new File("J:"+File.separator+"1.txt");
//推斷這個文件是否存儲在
if(!file.exists()){
throw new RuntimeException("沒有文件可以存入到數據庫中");
}
//建立一個字符流
Reader reader = null;
try {
//設置sql語句
ps = cn.prepareStatement("insert into t_temp1(id, data) values(?
,?)");
ps.setInt(1, 1);
//經過文件建立一個輸入文件字符流
reader = new FileReader(file);
//將這個流設置爲sql的第二個參數
ps.setCharacterStream(2, reader,file.length());
//運行這個sql語句
ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
//關閉數據庫
JDBCUtil3.close(null, ps, cn);
}
//取出數據中的這個文本文件
private static void fun2() {
//獲取數據庫鏈接
Connection cn = JDBCUtil3.getNewConnection();
//推斷鏈接是否爲null
if(cn == null)
return;
//建立一個數據庫對象
PreparedStatement ps = null;
//建立一個結果集
ResultSet rs = null;
//建立一個輸入字符流
Reader reader = null;
//建立一個輸出字符流
Writer writer = null;
try {
//或的數據庫對象,傳入一個sql語句
ps = cn.prepareStatement("select data from t_temp1");
//運行這個sql語句,得到一個結果集
rs = ps.executeQuery();
//遍歷這個結果集
while(rs.next()){
//以字符輸入流的方式取出data字段中的字符
reader = rs.getCharacterStream(1);
//建立一個輸出字符流,並指定要輸出到的文件
writer = new FileWriter("J:"+File.separator+"2.txt",true);
//把字符輸入流的字符,放入到字符輸出流中(就是從數據庫中取出數據,放入某個文件裏)
//建立一個字符緩存
char[] c = new char[1024];
int len = -1;
//把輸入流中取出字符放入字符緩存中,而後輸出流就從字符緩存中去取出字符
while((len = reader.read(c))>0){
writer.write(c, 0, len);
}
//刷新一下,好讓輸出流將字符全然輸出到文件裏
writer.flush();
}
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}finally{
try {
//關閉結果集、字符輸入流、字符輸出流
rs.close();
reader.close();
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
演示樣例2:(向數據庫中存儲一張.jpg圖片的二進制文件)
MySQL代碼
createtable t_temp2(
idint primary key,
dataMEDIUMBLOB
)
java代碼
//向數據庫中存取二進制文件(圖片)
public class Test2 {
//設置數據庫配置文件的位置
static{
JDBCUtil3.setPropertiesUrl("db.properties");
}
public static void main(String[] args) {
//把一個二進制文件存儲數據庫中
//fun1();
//把這個二進制文件取出,並存放到指定的文件夾
fun2();
}
//把一個二進制文件存儲數據庫中
private static void fun1() {
//獲取數據庫鏈接
Connection cn = JDBCUtil3.getNewConnection();
PreparedStatement ps = null;
//建立一個輸入字節流
InputStream in = null;
try {
//經過sql語句獲取到數據庫對象
ps = cn.prepareStatement("insert into t_temp2(id,data) values(?,?
)");
//設置id
ps.setInt(1, 1);
//建立一個文件輸入字節流
in = new FileInputStream("J:"+File.separator+"1.jpg");
//將這個流設置爲sql的第二個參數。in.available()獲取流中的字節大小
ps.setBinaryStream(2, in,in.available());
//運行這個sql語句
ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}finally{
try {
//關閉文件輸入字節流
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//取出數據中的這個二進制文件
private static void fun2() {
//獲取數據庫鏈接
Connection cn = JDBCUtil3.getNewConnection();
PreparedStatement ps = null;
InputStream in = null;
OutputStream out = null;
ResultSet rs = null;
try {
//經過sql語句獲取數據庫對象
ps = cn.prepareStatement("select data from t_temp2");
//運行sql語句。並返回一個結果集
rs = ps.executeQuery();
if(rs.next()){
//以字節輸入流的方式獲取結果集中數據
in = rs.getBinaryStream("data");
//建立一個文件字節輸出流。並指定要輸出的路徑
out = new FileOutputStream("J:"+File.separator+"2.jpg");
//建立一個字節緩存
byte[] b = new byte[1024];
int len = -1;
//讓字節輸入流的輸出緩存到字節緩存區。而後字節輸出流就從緩存中取出放入字節輸出流中
while((len = in.read(b))>0){
out.write(b,0,len);
}
}
//關閉流
in.close();
//刷新輸出流,好讓流中的數據全部寫入到文件裏
out.flush();
out.close();
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}finally{
//關閉數據庫
JDBCUtil3.close(rs, ps, cn);
}
}
}
批處理
當需要向數據庫發送一批SQL語句運行時,應避免向數據庫一條條的發送運行,而應採用JDBC的批處理機制,提高運行效率
第一種方式:(操做方式不一致,用此方式。
如:即有增也有刪的多條sql語句)
Statement類 此Statement對象中有一個list集合,將傳入的sql緩存起來(經過Connection數據庫鏈接對象的 createStatement()方法獲取此對象)
Statement.addBatch( sql ); 將sql語句緩存至Statement的list集合中
Statement.executeBatch(); 依次運行Statement類中list中緩存的所有sql語句
Statement.clearBathc(); 清除list集合中的所有sql語句
另一種方式:(操做方式一致,用此方式。
如:僅僅有向數據庫中添加的多條sql語句)
Statement的子類PreparedStatement類
可以依據?向sql設置值
演示樣例1:(操做方式不一致,用此方式。
如:即有增也有刪的多條sql語句)
MySQL代碼
createtable temp1(
id int primary key,
data varchar(100)
)
java代碼
//批處理(讓sql語句一次提交)
public class Test1 {
//設置數據庫配置文件的位置
static{
JDBCUtil3.setPropertiesUrl("db.properties");
}
public static void main(String[] args) {
//向temp1表中插入兩條數據,並刪除第一條
fun1();
}
//向temp1表中插入兩條數據,並刪除第一條
private static void fun1() {
//準備好三條sql語句
String sql1 = "insert into temp1(id, data) values(1, 'aa')";
String sql2 = "insert into temp1(id, data) values(2, 'bb')";
String sql3 = "delete from temp1 where id=1";
Connectioncn = JDBCUtil3.getNewConnection();
Statement s = null;
try {
//經過cn獲取到Statement對象
s = cn.createStatement();
//將sql緩存到Statement對象中的list緩存集合中
s.addBatch(sql1);
s.addBatch(sql2);
s.addBatch(sql3);
//按順序依次運行list緩存集合中的所有sql語句,並返回的是每條sql影響了的行數 int數組
int[] count = s.executeBatch();
//輸出每條sql影響了的行數
for(int i : count){
System.out.println(i);
}
//關閉Statement對象
s.close();
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}finally{
JDBCUtil3.close(null, null, cn);
}
}
}
演示樣例2:(操做方式一致,用此方式。如:僅僅有向數據庫中添加的多條sql語句)
MySQL代碼
createtable temp1(
idint primary key,
namevarchar(20)
)
java代碼
//批處理(讓sql語句一次提交)
//操做方式一致。用此方式。
如:僅僅有向數據庫中添加的多條sql語句
public class Test2 {
//設置數據庫配置文件的位置
static{
JDBCUtil3.setPropertiesUrl("db.properties");
}
public static void main(String[] args) {
//向數據庫中加入1000001條記錄
fun1();
}
//向數據庫中加入1000001條記錄
/*
Oracle僅僅需要8秒
MySQL需要4個小時左右
*/
private static void fun1() {
//記住當前的時間
long date = System.currentTimeMillis();
Connection cn = null;
PreparedStatement ps = null;
try {
//獲取鏈接
cn = JDBCUtil3.getNewConnection();
//獲取數據庫對象
ps = cn.prepareStatement("insert into temp1(id, name) values(?, ?
)");
//遍歷1000001
for(int i=1;i<=1000001; i++){
//以i變量設置id
ps.setInt(1, i);
//設置name
ps.setString(2, "aaaaa"+i);
//將sql語句存入ps中的list集合緩存中
ps.addBatch();
//假設緩存有2000條sql語句就運行(因爲內存不夠)
if(i%2000==0){
//運行list集合中的所有sql語句
ps.executeBatch();
//當運行完畢後清除list中的所有sql語句
ps.clearBatch();
}
}
//運行後面多出來的1條sql,並清除它
ps.executeBatch();
ps.clearBatch();
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}finally{
//關閉數據庫
JDBCUtil3.close(null, ps, cn);
//輸出這次執行共消耗了多少秒
System.out.println("共用:"+(System.currentTimeMillis()-date)/1000+"秒");
}
}
}
當insert插入數據時獲取此條記錄的主鍵的值
當此表中的id字段爲自增加時。咱們在插入一條數據時可以用下面方式獲取到插入數據的主鍵的值
ps = cn.prepareStatement("insert intotemp1(name) values( ?)");
ps.executeUpdate();
//獲取到此記錄的主鍵的值,並以結果集返回,僅僅指針對insert語句有效
ResultSetrs = ps.getGeneratedKeys();
System.out.println(rs.getInt(1));//輸出此條記錄的主鍵的值
JDBC調用存儲過程
接口CallableStatement; 它的父接口爲PreparedStatement
獲取此接口需調用Connection鏈接對象的prepareCall(String str);方法來獲取;
str參數的規範:「{call 存儲過程名(?
,?)}」;
用Connection對象的setString(1,」abc」);//來給佔位符」?」賦值,對於要輸出的參數用registerOutParameter(2,Types.VARCHAR2);來設置,第二個參數用於指定輸出參數的類型。Types類中有與數據庫數據類型匹配的常量
演示樣例:
存儲過程:
delimiter$$//分界的意思。$$符號是敲回車或遇到」;」號不運行,直到再讀取到兩個$$時運行
CREATEPROCEDURE dempSp(IN inputParam VARCHAR(100), INOUT inOutParam VARCHAR(1000))
begin
select concat(‘welcome-----’, inputParam) into inOutParam; //將「welcome-----」字符串,鏈接到傳入參數inputParam的前面,並賦值給inOutParam。返回
end$$
delimiter;
java代碼調用存儲過程
//獲取數據庫鏈接
cn= JDBCUtil3.getNewConnection();
//獲取存儲過程對象
CallableStatementcs = cn.prepareCall(「{call demoSp(?, ?)}」);
//給第一個參數設置。假設此參數不用返回的話。就直接傳入要傳入的參數就能夠
cs.setString(1,」abc」);
//因第二個參數要返回,因此要指定參數的類型,Types類中有與數據庫類型相應的常量
cs.registerOutParameter(2,Types.VARCHAR);
//運行存儲過程
cs.execute();
//獲取第二個有返回值的參數
Stringvalue = cs.getString(2);
事務
事務指邏輯上的一組操做,組成這組操做的各個單元,要麼全部成功,要麼全部不成功
在java中事務是默認本身主動提交的,當咱們僅僅想一條sql語句時,事務直接就提交了
事務的特性
原子性(Atomicity)
原子性是指事務是一個不可切割的工做單位,事務中的操做要麼都發生,要麼都不發生
一致性(Consistency)
事務必須使數據庫從一個一執性狀態變換到另一個一致性狀態 (比方轉帳。A轉帳給B,轉帳前和轉帳後A和B的錢的總和必須一致)
隔離性(Isolation)
事務的隔離性是多個用戶併發訪問數據庫時,數據庫爲每一個用於開啓的事務。不能被其它事務的操做數據所幹擾,多個併發事務之間要互相隔離
持久性(Durability)
持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即便數據庫發生問題也不該該對其有不論什麼影響
隔離性(必須用在事務之中)
多個線程開啓各自事務操做數據庫中數據時,數據庫系統要負責隔離操做,以保證各個線程在獲取數據時的準確性。否則會引起髒讀、不可反覆讀、幻讀
髒讀:
髒讀是指一個事務讀到了還有一個事務中未提交的數據
不可反覆讀:
針對一條記錄,每次讀取記錄先後不一致
虛讀:
同一張表,讀取記錄先後的記錄數不一致
隔離級別的分類(級別越高,消耗性能就越高)
READUNCOMMITTED: 此級別 髒讀、不可反覆讀、虛讀,都有可能發生(級別最低)
READCOMMITTED: 此級別 能避免發生髒讀,但不可反覆讀、虛讀。有可能發生
REPEATABLEREAD: 此級別 能避免發生髒讀、不可反覆讀,但虛讀,有可能發生(默認級別,通常也是用此級別,因此通常不用設置隔離級別)
SERIALIZABLE: 此級別 能避免髒讀、不可反覆讀、虛讀。但消耗性能最高
MySQL中控制事務隔離級別的語句:
select@@tx_isolation; //查看當前的事務隔離級別
settransaction isolation level 要設置的級別(四種之中的一個); //設置隔離級別,必須在開啓事務以前進行設置級別。不然無效
java中控制事務隔離級別的語句:
Connection鏈接對象的.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); 設置事務的隔離級別,但 必須在開開啓手動提交事務(如下這句)以前設置,不然無效。隔離的四大級別在Connection鏈接類中有與之相應的常量
Connection鏈接對象的.setAutoCommit(false); 設置數據庫不本身主動提交事務
總結:隔離性。就是事務沒提交前。所讀取到的數據不能有 髒讀、不可反覆讀、虛讀 等異常發生。也就是所當個人事務還沒提交前,查詢出別人對數據更新後的數據,那麼這是不正確的,因此就需要更改級別來控制。還沒提交事務前讀取的數據必須保持一致
數據庫中處理事務的keyword是:
start transaction 開啓手動提交事務
rollback 回滾事務
commit 提交事務
java中處理事務的方法是:
Connection鏈接對象的.setAutoCommit(false); 設置數據庫不本身主動提交事務
PreparedStatement數據庫對象的.commit(); 提交事務
PreparedStatement數據庫對象的.rollback(); 回滾事務
sp = Connection鏈接對象的.setSavepoint(); 設置回滾點
PreparedStatement數據庫對象的.rollback(sp ); 回滾事務到回滾點
演示樣例1:
//當id爲1的用戶給id爲2的用戶轉帳,設置統一提交事務
Connection cn = null;
PreparedStatement ps = null;
try{
//獲取鏈接
cn = JDBC.getConnection();
//設置事務不本身主動提交
cn.setAutoCommit(false);
//獲取數據庫操做對象
ps = cn.prepareStatement("update account set money=money-100 where id=1");
//運行sql語句
ps.executeUpdate();
//獲取數據庫操做對象
ps = cn.prepareStatement("update account set money=money+100 where id=2");
//運行sql語句
ps.executeUpdate();
}catch(Exception e){
e.printStackTrace();
try {
//當上面語句運行異常時回滾事務
cn.rollback();
} catch (SQLException e1) {
// TODO Auto-generatedcatch block
e1.printStackTrace();
}
}finally{
try {
//假設沒有異常就直接提交
cn.commit();
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}finally{
//關閉數據庫鏈接
JDBC.close(null, ps, cn);
}
}
演示樣例2:設置回滾點
//id1給id2轉帳100,id2又給id3轉帳100;當id2給id3轉帳時,發生異常,id1給id2轉帳照常運行
Connection cn = null;
PreparedStatement ps = null;
Savepoint sp = null;
try{
//獲取鏈接
cn = JDBC.getConnection();
//設置事務不本身主動提交
cn.setAutoCommit(false);
//獲取數據庫操做對象
ps = cn.prepareStatement("update account set money=money-100 where id=1");
//運行sql語句
ps.executeUpdate();
//獲取數據庫操做對象
ps = cn.prepareStatement("update account set money=money+100 where id=2");
//運行sql語句
ps.executeUpdate();
sp = cn.setSavepoint();//設置回滾點
//獲取數據庫操做對象
ps = cn.prepareStatement("update account set money=money-100 where id=2");
//運行sql語句
ps.executeUpdate();
//int i =1/0;//當此處出錯時,回滾點上面的sql照常運行
//獲取數據庫操做對象
ps = cn.prepareStatement("update account set money=money+100 where id=3");
//運行sql語句
ps.executeUpdate();
}catch(Exception e){
e.printStackTrace();
try {
//當上面語句運行異常時回滾事務
cn.rollback(sp);
} catch (SQLException e1) {
// TODO Auto-generatedcatch block
e1.printStackTrace();
}
}finally{
try {
//假設沒有異常就直接提交
cn.commit();
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}finally{
//關閉數據庫鏈接
JDBC.close(null, ps, cn);
}
}
鏈接池
就是先建立多個數據庫的鏈接存儲在一個容器中。當要用時直接取出。用完後不用關閉,直接再放回到容器中
Tomcat自帶的鏈接池
2.打開apache-tomcat-6.0.29\conf文件夾中的content.xml文件.
在此文件裏配置Resource
1 <?
xml version='1.0'encoding='utf-8'?>
2 <Context>
3 <!-- Default set of monitored resources-->
4 <WatchedResource>WEB-INF/web.xml</WatchedResource>
5
6 <!--數據源-->
7 <Resource
8 name="jdbc/DBSource" <!--數據源名稱,格式一般爲jdbc/xxx名稱-->
9 type="javax.sql.DataSource" <!--數據源類型-->
10 username="scott" <!--鏈接數據庫用戶名-->
11 password="tiger" <!--鏈接數據庫密碼-->
12 maxIdle="2" <!--最大空暇數,數據庫鏈接的最大空暇時間。超過空暇時間,數據庫鏈接將被標記爲不可用,而後被釋放。設爲0表示無限制。-->
13 maxWait="5000" <!--最大的等待時間,單位毫秒。
假設超過此時間將接到異常。設爲-1表示無限制-->
14 url="jdbc:oracle:thin:@localhost:1521:orcl" <!--數據庫的鏈接-->
15 -- driverClassName="oracle.jdbc.driver.OracleDriver" <!—驅動類-->
16 maxActive="10" <!--鏈接池的最大數據庫鏈接數。設爲0表示無限制-->
17 />
18 </Context>
3.在Web項目中的web.xml裏面需要引用數據源:
19 <!-- 引用數據源; -->
20 <resource-ref>
21 <description>Oracle dataSource</description>
22 <res-ref-name>jdbc/DBSource</res-ref-name> <!--數據源類型-->
23 <res-type>javax.sql.DataSource</res-type>
24 <res-auth>Container</res-auth>
25 <res-sharing-scope>Shareable</res-sharing-scope>
26 </resource-ref>
4.在java代碼中,寫一個方法調用一下.
比方:在一個DataSourceDemo
27 package pack.java.datasource.demo;
28
29 import java.sql.Connection;
30 import java.sql.SQLException;
31 import javax.naming.InitialContext;
32 import javax.naming.NamingException;
33 /**
34 * 數據源實例;
35 * @authorzhouhaitao
36 *
37 */
38 public classDataSourceDemo {
39 /**
40 * 依據datasourceName獲取數據源;
41 * @paramdsName
42 * @return
43 */
44 public Connection getConnection(){ // String dsName
45 Connectionconnection = null;
46 try {
47 //初始化,獲取上下文對象;
48 InitialContext context = new InitialContext();
49
50 //依據datasourceName獲取dataSource;
51 javax.sql.DataSource dataSource =(javax.sql.DataSource) context.lookup("java:comp/env"); //+dsName
52
53 try {
54 //從數據源中獲取鏈接;
55 connection =dataSource.getConnection();
56 } catch (SQLException e) {
57 //TODO Auto-generated catch block
58 e.printStackTrace();
59 }
60 } catch (NamingException e) {
61 // TODOAuto-generated catch block
62 e.printStackTrace();
63 }
64 return connection;
65 }
66 }
本身定義鏈接池
其它連接池到E:\practice\MySpace\javautil工做空間中去參考
/*
此類是一個數據庫鏈接池。初始化鏈接池數量可以再配置文件裏設置
此類是一個線程安全的,當線程池中沒有連接時,休眠該線程,當鏈接返回時再喚醒休眠的線程
*/
public class ConnectionPool {
//數據庫的username
private static String user = null;
//數據庫的password
private static String password = null;
//數據庫的鏈接地址
private static String url = null;
//數據的的驅動地址
private static String driverClassName = null;
//最大存活的鏈接數量
private static int maxActiveConnectionNumber = 0;
//存儲鏈接的List集合
private static List<Connection> pool = new LinkedList<Connection>();
//標識爲,標誌pool集合中是否還有鏈接
private static boolean bool = true;
//初始化數據庫鏈接,數量
static{
//獲取文件的輸入流
InputStream in = ConnectionPool.class.getClassLoader().getResourceAsStream("db.properties");
//建立一個Properties文件
Properties properties = new Properties();
try {
//從輸入流中獲取Properties文件的內容
properties.load(in);
//獲取Properties文件裏的各類信息
user = properties.getProperty("user");
password = properties.getProperty("password");
url = properties.getProperty("url");
maxActiveConnectionNumber = Integer.parseInt(properties.getProperty("maxActiveConnectionNumber"));
driverClassName = properties.getProperty("driverClassName");
//載入驅動
Class.forName(driverClassName);
//建立鏈接。並存儲到pool集合中
for(int i=0; i<maxActiveConnectionNumber; i++){
Connection cn = null;
cn = DriverManager.getConnection(url, user, password);
System.out.println(cn);
pool.add(cn);
}
}catch(IOException e){
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
//此方法由於獲取、pool集合中的鏈接
//此方法是一個線程安全的。當線程池中沒有連接時,休眠該線程,當鏈接返回時再喚醒休眠的線程
public static Connection getConnection(){
//鏈接
Connection cn = null;
//加鎖
ThreadLock.getLock().lock();
//獲取狀態對象
Condition c = ThreadLock.getCondition();
try{
//推斷pool集合中是否有鏈接
while(!bool){
//假設沒有就休眠當前的線程
c.await();//此休眠語句必須放在加了鎖的域中
}
//取出pool集合中的一個鏈接,並在pool集合中移除它
cn = pool.remove(0);
//推斷集合中是否還有鏈接
if(pool.size() <= 0){
//假設沒有就將標誌位設置爲false
bool = false;
}
} catch (InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}finally{
//解鎖
ThreadLock.getLock().unlock();
}
return cn;
}
//此方法用於返回鏈接,並存儲到pool集合中
public static void release(Connection cn){
//加鎖
ThreadLock.getLock().lock();
try{
//向pool集合中加入此鏈接
pool.add(cn);
//並把標識位設爲true,表示pool中已有鏈接
bool = true;
//喚醒狀態對象中的某一個線程
ThreadLock.getCondition().signal();//此喚醒語句必須放在加了鎖的域中
}finally{
//解鎖
ThreadLock.getLock().unlock();
}
}
}
//此類主要用於提供鎖和線程狀態對象
class ThreadLock{
private static Lock lock = new ReentrantLock();
private static Condition c = lock.newCondition();
//返回一個鎖對象
public static Lock getLock(){
return lock;
}
//返回一個線程狀態對象
public static Condition getCondition(){
return c;
}
}
DBCP連接池(推薦使用)
DBCP是Apache軟件基金組織下的開源連接池實現。用此鏈接池需導入Commons-dbcp.jar包(鏈接此的實現)和Commons-pool.jar包(鏈接池的依賴庫)
dbcpconfig.properties文件的配置
#鏈接設置
#驅動位置
driverClassName=com.mysql.jdbc.Driver
#鏈接
url=jdbc:mysql://localhost:3306/jdbc
#帳戶password
username=root
password=
#<!--初始化鏈接 -->
initialSize=10
#最大鏈接數量
maxActive=50
#<!--最大空暇鏈接 -->
maxIdle=20
#<!--最小空暇鏈接 -->
minIdle=5
#<!--超時等待時間以毫秒爲單位 6000毫秒/1000等於60秒 -->
maxWait=60000
#JDBC驅動創建鏈接時附帶的鏈接屬性屬性的格式必須爲這樣:[屬性名=property;]
#注意:"user"與 "password" 兩個屬性會被明白地傳遞,所以這裏不需要包括他們。
connectionProperties=useUnicode=true;characterEncoding=utf8
#指定由鏈接池所建立的鏈接的事務本身主動提交(auto-commit)狀態。
defaultAutoCommit=true
#driverdefault 指定由鏈接池所建立的鏈接的僅僅讀(read-only)狀態。
#假設沒有設置該值,則「setReadOnly」方法將不被調用。(某些驅動並不支持僅僅讀模式,如:Informix)。(通常不配)
defaultReadOnly=
#driverdefault 指定由鏈接池所建立的鏈接的事務級別(TransactionIsolation)。
#可用值爲下列之中的一個:(詳情可見javadoc。
)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
java代碼,用戶獲取鏈接和返回鏈接的工具類
/*
用DBCP鏈接池獲取鏈接的工具類
*/
public class DBCPUtils {
//定義一個數據源
private static DataSource ds = null;
static{
//將dbcpconfig.properties配置文件載入進來
InputStream in = DBCPUtils.class.getClassLoader().getResourceAsStream("DBCPConnectionPool/dbcpconfig.properties");
Properties pro = new Properties();
try {
pro.load(in);
//經過將配置文件傳入下面類中。從而得到數據源對象
ds = BasicDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
// TODO Auto-generatedcatch block
throw new RuntimeException(e);
}
}
//獲取鏈接
public static Connection getConnection(){
try {
//經過數據源將鏈接池中的鏈接取出
return ds.getConnection();
} catch (SQLException e) {
// TODO Auto-generatedcatch block
throw new RuntimeException(e);
}
}
//關閉鏈接。用DBCP鏈接池,Connection的方法已被改寫。因此調用Connection對象的close()方法時是將鏈接放回鏈接池中
public static void close(Connection conn,Statement ps,ResultSet rs){
try {
if(rs!=null){
rs.close();
}
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}finally{
try{
if(ps!=null){
ps.close();
}
} catch (SQLException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}finally{
try{
if(conn!=null){
conn.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
C3P0連接池(推薦使用)
用此鏈接池需導入c3p0-0.9.1.2.jar包c3p0-0.9.1.2-jdk1.3.jar及c3p0-oracle-thin-extras-0.9.1.2.jar包(此包是Orclase鏈接時需要的。但通常都導入)
此工具設置配置參數可有在對ComboPooledDataSource象中設置,也可以在當前src或web應用的WEB-INF/classes文件夾下創建一個c3p0-config.xml (推薦)配置文件進行配置,也可以創建一個c3p0.properties映射文件進行配置,
c3p0的配置文件說明:
演示樣例:
c3p0-config.xml文件的配置
<?xml version="1.0"encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">oracle.jdbc.OracleDriver</property>
<property name="jdbcUrl">jdbc:oracle:thin:@127.0.0.1:1521:orcl</property