Web應用程序
WEB,在英語中web即表示網(wǎng)頁的意思,它用于表示Internet主機上供外界訪問的資源。Internet上供外界訪問的Web資源分為:
1.靜態(tài)web資源(如html 頁面):指web頁面中供人們?yōu)g覽的數(shù)據(jù)始終是不變。
靜態(tài)web資源開發(fā)技術(shù):HTML+CSS+Javascript
2.動態(tài)web資源:指web頁面中供人們?yōu)g覽的數(shù)據(jù)是由程序產(chǎn)生的,不同時間點 訪問web頁面看到的內(nèi)容各不相同
動態(tài)web資源開發(fā)技術(shù):JSP/Servlet
在Java中,動態(tài)web資源開發(fā)技術(shù)統(tǒng)稱為Javaweb。
學習web開發(fā),需要先安裝一臺web服務器,然后再在web服務器中開發(fā)相應的web資源,供用戶使用瀏覽器訪問。
WEB應用程序指供瀏覽器訪問的程序,通常也簡稱為web應用。一個web應用由多個靜態(tài)web資源和動態(tài)web資源組成。Web應用開發(fā)好后,若想供外界訪問,需要把web應用所在目錄交給web服務器管理。
Web服務器是指駐留于因特網(wǎng)上某種類型計算機的程序,是可以向發(fā)出請求的瀏覽器提供文檔的程序。

BC/CS
CS:客戶機/服務器 結(jié)構(gòu) 網(wǎng)絡(luò)游戲客戶端,QQ等
BS:瀏覽器/服務器 結(jié)構(gòu) 百度,淘寶,新浪
Web應用:基于HTTP協(xié)議的應用程序
屬于 B/S架構(gòu)
瀏覽器客戶端:通過HTTP協(xié)議向服務器發(fā)出請求
服務器:通過HTTP協(xié)議向客戶端響應結(jié)果
HTTP協(xié)議:
是由W3C制定的一種網(wǎng)絡(luò)應用層協(xié)議,規(guī)定了瀏覽器和web服務器之間如何通信
以及通信的數(shù)據(jù)格式
特點:一次請求,一次連接
優(yōu)點:利用有限的連接,為近可能多的請求服務

Tomcat:開源的Java Web服務器
tomcat目錄結(jié)構(gòu)
bin:主要存放一些可執(zhí)行文件(比如啟動startup.bat以及關(guān)閉的shutdown.bat)
conf:配置文件;
lib:第三方依賴jar包;
logs:日志目錄;
temp:臨時文件目錄;
work:jsp經(jīng)過翻譯成Servlet再翻譯成.class的文件等;
webapps:真正的web應用可以部署的位置;
測試Tomcat服務器是否可以正常運行
配置環(huán)境變量
1.名稱:JAVA_HOME
變量值: jdk 的路徑(例:C:\Program Files (x86)\Java\jdk1.8.0_111)
2.名稱:CLASS_PATH
變量值:%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar
3.系統(tǒng)環(huán)境變量中有一個path選中后選擇編輯
;%JAVA_HOME%\bin;
進入 tomcat 的 bin 目錄,然后雙擊 startup.bat 。
Web項目的創(chuàng)建以及配置Tomcat

填寫項目名稱 - version 2.5 -Next

目錄結(jié)構(gòu)

配置Tomcat
Window - Preferences - Server - Runtime - Add
選擇需要配置Tomcat的版本 Tomcat 8.0
點擊 Next - Browser
選擇相應版本的Tomcat所在本地路徑
測試是否配置成果
在WebContent下 創(chuàng)建index.html
將項目部署到Tomcat內(nèi)
啟動Tomcat服務器
通過瀏覽器訪問 localhost:8080/項目名/index.html
Web server只能訪問靜態(tài)資源,為了提高是服務的擴張性,使用Servlet
什么是Servlet:
Java Servlet是和平臺無關(guān)的服務器端組件,它運行在Servlet容器中。Servlet容器負責Servlet和客戶的通信以及調(diào)用Servlet的方法,Servlet和客戶的通信采用“請求/響應”的模式。
Servlet本質(zhì)就是一個運行在Servlet容器中的Java類,Servlet容器就是Tomcat
Servlet的作用
創(chuàng)建并返回基于客戶請求的動態(tài)HTML頁面。
與其它服務器資源(如數(shù)據(jù)庫或基于Java的應用程序)進行通信
創(chuàng)建Servlet : 繼承HttpServlet,實現(xiàn)doGet( ),doPost( )方法
通過提交表單 訪問Servlet
設(shè)計表單:文本框,按鈕
<form>屬性method 表示提交表單的方法
Get: - -doGet( )
采用路徑傳參,參數(shù)在傳遞過程中可見(地址欄)
隱私性差
傳參能力有限,只能傳少量參數(shù)
所有的請求默認都是GET請求
Post:- - doPost( )
采用實體內(nèi)容傳參,參數(shù)在傳遞過程中不可見
隱私性好
實體內(nèi)容專門用來傳參,大小不受限制
在form上加method="post"
瀏覽器發(fā)送請求后,如何找到Servlet
配置web.xml
2.0 web項目會自動創(chuàng)建該文件
<servlet>
<servlet-name>Servlet1</servlet-name>//指定servlet類的唯一標識
<servlet-class>test.Servlet1</servlet-class>//servlet的全類名(包名.類名)
</servlet>
<servlet-mapping>//設(shè)定servlet與客戶端的映射路徑
<servlet-name>Servlet1</servlet-name>//與<servlet>中保持一致
<url-pattern>/Servlet1</url-pattern>//用于設(shè)定請求路徑
</servlet-mapping>
3>關(guān)于Servlet路徑配置問題詳解
<url-pattern>
路徑匹配:
/AServlet --http://localhost:8080/項目名/AServlet
/ABC/AServlet --http://localhost:8080/項目名/ABC/AServlet
/ABC/ABC/AServlet http://localhost:8080/項目名/ABC/ABC/AServlet
/ABC/ABC/* --http://localhost:8080/項目名/ABC/ABC/任意
/* -- http://localhost:8080/項目名/任意
/ 相當于 /*
后綴名匹配:
*.do ==> struts
*.action ==> struts2
*.html ==>
Servlet的生命周期
①服務器加載Servlet
②創(chuàng)建Servlet實例
--只有第一次請求Servlet時,創(chuàng)建Servlet實例,調(diào)用構(gòu)造器
③初始化init()
--只被調(diào)用一次,在創(chuàng)建好實例后立即被調(diào)用,用于初始化當前Servlet
④service()處理用戶請求
--可以被多次調(diào)用,每次請求都會調(diào)用service方法,實際用于響應請求的,根據(jù)用戶請求的類型(get或者post),調(diào)用doGet或者doPost方法。
⑤destory()銷毀
--只被調(diào)用一次,在當前Servlet所在的WEB應用被卸載前調(diào)用,用于釋放當前Servlet所占用的資源
//設(shè)置加載時機,默認訪問servlet時加載
//值為1時,啟動過程中便開始加載
//多個servlet之間值越小,越優(yōu)先
<load-on-startup></load-on-startup>
Servlet運行原理

request對象
1.提取客戶端提交表單的信息
2.提取HTTP請求報頭的信息
3.在服務器段保存數(shù)據(jù),進行數(shù)據(jù)傳遞
4.處理Web資源跳轉(zhuǎn)
HttpServletRequest常用的方法:
String getParameter(String name)
--根據(jù)請求參數(shù)的名字,返回參數(shù)值,特別常用
產(chǎn)生亂碼的原因:瀏覽器的編碼格式和服務器的解碼格式不同
解決亂碼:只要確保編碼和解碼一致,就絕對沒有問題
Get
修改Tomcat配置文件,Server.xml第65行加 URIEncoding="UTF-8"
<Connector port="8080" protocol="HTTP/1.1" URIEncoding="UTF-8"
connectionTimeout="20000" redirectPort="8443" />
POST
因為Post解碼是在第一次調(diào)用getParameter之前,那么解決亂碼只需要在調(diào)用該方法之前設(shè)置編碼:
request.setCharacterEncoding("UTF-8");
獲取HTTP請求頭信息
1.請求行
2.請求頭
3.請求空行
4.請求數(shù)據(jù)
request.getMethod(): 請求方式
request.getRequestURI(): /項目名/Servlet映射名
request.getServletPath(): /Servlet映射名
request.getContextPath(): /項目名
request.getScheme(): http
封裝好的方法.
request.getContentType(): null
request.getLocale(): zh_CN
request.getQueryString(): name=tom&age=18
request.getRequestURL(): http://localhost:8080/Day08-request/AServlet
request.getRemotePort(): 52074
request.getServerName(): localhost
request.getServerPort(): 8080
request.getRemoteAddr() :客戶端IP
設(shè)計用戶注冊功能
1.獲取表單注冊信息
2.添加到數(shù)據(jù)庫
設(shè)置響應信息 response對象
1.設(shè)置響應信息的字符集
2.向客戶端響應信息
3.Web資源跳轉(zhuǎn)
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");//設(shè)置響應內(nèi)容的類型
PrintWriter pw=response.getWriter();//獲取輸出流 ,向瀏覽器響應信息
String html="<!DOCTYPE html>"
+"<html>"
+"<meta charset='UTF-8'>"
+"<title>Insert title here</title>"
+"</head>"
+"<body>"
+"abc"
+"</body>"
+"</html>";
pw.write(html);//寫內(nèi)容
pw.close();//關(guān)閉流
設(shè)計程序
注冊成功后,在網(wǎng)頁上顯示 - - 注冊成功
完善用戶注冊
用戶信息符合規(guī)定條件 才允許注冊
如何注冊成功 顯示登陸頁面
12306項目驅(qū)動
軟件開發(fā)基本流程
需求分析
成果物:頁面原型 需求分析文檔
相關(guān)系統(tǒng)分析員向用戶初步了解需求,然后用相關(guān)的工具軟件列出要開發(fā)的系統(tǒng)的大功能模塊,每個大功能模塊有哪些小功能模塊,對于有些需求比較明確相關(guān)的界面時,在這一步里面可以初步定義好少量的界面。系統(tǒng)分析員深入了解和分析需求,根據(jù)自己的經(jīng)驗和需求用WORD或相關(guān)的工具再做出一份文檔系統(tǒng)的功能需求文檔。這次的文檔會清楚列出系統(tǒng)大致的大功能模塊,大功能模塊有哪些小功能模塊,并且還列出相關(guān)的界面和界面功能。系統(tǒng)分析員向用戶再次確認需求。
數(shù)據(jù)庫設(shè)計
基于需求分析的成果進行數(shù)據(jù)庫的設(shè)計,包含表,列以及關(guān)聯(lián)關(guān)系,初始數(shù)據(jù)。
概要設(shè)計(開發(fā)框架的搭建,核心技術(shù)的選擇)
首先,開發(fā)者需要對軟件系統(tǒng)進行概要設(shè)計,即系統(tǒng)設(shè)計。概要設(shè)計需要對軟件系統(tǒng)的設(shè)計進行考慮,包括系統(tǒng)的基本處理流程、系統(tǒng)的組織結(jié)構(gòu)、模塊劃分、功能分配、接口設(shè)計、運行設(shè)計、數(shù)據(jù)結(jié)構(gòu)設(shè)計和出錯處理設(shè)計等,為軟件的詳細設(shè)計提供基礎(chǔ)。
詳細設(shè)計
(通過UML建模實現(xiàn) 類圖 時序圖)
在概要設(shè)計的基礎(chǔ)上,開發(fā)者需要進行軟件系統(tǒng)的詳細設(shè)計。在詳細設(shè)計中,描述實現(xiàn)具體模塊所
涉及到的主要算法、數(shù)據(jù)結(jié)構(gòu)、類的層次結(jié)構(gòu)及調(diào)用關(guān)系,需要說明軟件系統(tǒng)各個層次中的每一個
程序(每個模塊或子程序)的設(shè)計考慮,以便進行編碼和測試。應當保證軟件的需求完全分配給整個
軟件。詳細設(shè)計應當足夠詳細,能夠根據(jù)詳細設(shè)計報告進行編碼。
編碼
在軟件編碼階段,開發(fā)者根據(jù)《軟件系統(tǒng)詳細設(shè)計報告》中對數(shù)據(jù)結(jié)構(gòu)、算法分析和模塊實現(xiàn)等方面的設(shè)計要求,開始具體的編寫程序工作,分別實現(xiàn)各模塊的功能,從而實現(xiàn)對目標系統(tǒng)的功能、
性能、接口、界面等方面的要求。在規(guī)范化的研發(fā)流程中,編碼工作在整個項目流程里最多不會
超過1/2,通常在1/3的時間,所謂磨刀不誤砍柴功,設(shè)計過程完成的好,編碼效率就會極大提高
,編碼時不同模塊之間的進度協(xié)調(diào)和協(xié)作是最需要小心的,也許一個小模塊的問題就可能影響了
整體進度,讓很多程序員因此被迫停下工作等待,這種問題在很多研發(fā)過程中都出現(xiàn)過。
測試
測試編寫好的系統(tǒng)。交給用戶使用,用戶使用后一個一個的確認每個功能。軟件測試有很多種:
按照測試執(zhí)行方,可以分為內(nèi)部測試和外部測試;按照測試范圍,可以分為模塊測試和整體聯(lián)調(diào);
按照測試條件,可以分為正常操作情況測試和異常情況測試;按照測試的輸入范圍,可以分為全
覆蓋測試和抽樣測試。以上都很好理解,不再解釋??傊?,測試同樣是項目研發(fā)中一個相當重要
的步驟,對于一個大型軟件,3個月到1年的外部測試都是正常的,因為永遠都會有不可預料的問
題存在。完成測試后,完成驗收并完成最后的一些幫助文檔,整體項目才算告一段落,當然日后
少不了升級,修補等等工作,只要不是想通過一錘子買賣騙錢,就要不停的跟蹤軟件的運營狀況
并持續(xù)修補升級,直到這個軟件被徹底淘汰為止。
數(shù)據(jù)庫的范式
消除重復數(shù)據(jù),減少冗余數(shù)據(jù),進行數(shù)據(jù)庫設(shè)計的方式
第一范式:數(shù)據(jù)表中每一個屬性都是不可分的基本數(shù)據(jù)項,同一個列中不能有多個值
第二范式 :要求數(shù)據(jù)表中的每個實例或行必須是唯一的,依賴于主鍵
所有列必須依賴主鍵(支持聯(lián)合主鍵)
第三范式;一個數(shù)據(jù)表不能包含其他表中非主鍵的列
MD5字符串加密處理
MD5是一種不可逆的加密算法
網(wǎng)站一般會保存用戶密碼:
為了不讓數(shù)據(jù)庫管理員看到用戶的密碼。
比如你輸入的密碼明明是這樣的:123456
網(wǎng)站加密后的密碼可能是這樣的:E10ADC3949BA59ABBE56E057F20F883E
public final static String md5(String s) {
char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };
try {
byte[] btInput = s.getBytes();
MessageDigest mdInst = MessageDigest.getInstance("MD5");
mdInst.update(btInput);
byte[] md = mdInst.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
常見錯誤:
404:服務器依據(jù)請求地址找不到相應的資源
1.沒有將項目部署到服務器 2.<servlet-name>不一致 3.瀏覽器中請求地址有誤
500:系統(tǒng)出錯,程序在運行過程中出現(xiàn)問題
405:方法聲明錯誤
2.request的請求轉(zhuǎn)發(fā)和包含功能.
轉(zhuǎn)發(fā):
服務器接到客戶端的請求后,將請求轉(zhuǎn)發(fā)給WEB應用內(nèi)的其他資源處理
轉(zhuǎn)發(fā):request.getRequestDispatcher(“url”).forward(req,res);
url中的/可以寫,也可以不寫,建議寫。默認相對于項目名進行跳轉(zhuǎn)
3.request域的應用.
原理:
在request對象中含有一個map.這個map就是request域.
作用:
在將來開發(fā)中. 使用請求轉(zhuǎn)發(fā)時,servlet處理完數(shù)據(jù), 處理結(jié)果要交給jsp顯示. 可以使用request域?qū)⑻幚斫Y(jié)果由servlet帶給jsp顯示.
操作:
1.setAttribute 存入一個鍵值對
2.getAttribute 通過鍵取出值
3.getAttributeNames 獲得域中所有鍵
4.removeAttribute 跟據(jù)鍵移除一個鍵值對
request的范圍:
一個request對象對應一個request域(map).
系統(tǒng)當前有多少個request就有多少request域.
重定向
服務器接收到客戶端的請求之后,返回給客戶端一個URL,客戶端根據(jù)URL
重新發(fā)出HTTP請求
重定向:response.sendRedirect(“url”);
url:如果不以/開頭,表示相對于當前路徑進行跳轉(zhuǎn)(localhost:port/項目名/)
response.sendRedirect(“index.html”)
url:如果以/開頭,表示相對于服務器域名進行跳轉(zhuǎn)(localhost:port/)
response.sendRedirect(request.getContextPath+“/index.html”)

共同點:都是用來解決web組件(Servlet/JSP) 之間的跳轉(zhuǎn)問題
兩種方式的區(qū)別:
1.重定向支持項目資源外的跳轉(zhuǎn)(站外跳轉(zhuǎn)),轉(zhuǎn)發(fā)只能站內(nèi)跳轉(zhuǎn)。
2.請求對象個數(shù):重定向2個 ,轉(zhuǎn)發(fā)1個。
3.重定向后瀏覽器地址欄發(fā)生改變,轉(zhuǎn)發(fā)不變。
4.請求轉(zhuǎn)發(fā)性能好于重定向
至于選用哪種方式取決于數(shù)據(jù)共享的方式。如果采
用請求對象做數(shù)據(jù)的共享,則必須選用請求轉(zhuǎn)發(fā)的方式進行資源的跳轉(zhuǎn)。如果不選用請求對象做數(shù)據(jù)的共享,都可以。
解決項目中不同的組件(Servlet)之間地跳轉(zhuǎn)(降低耦合度):
一個Servlet只去處理一個功能
使用規(guī)律:一般在增加,修改,刪除之后轉(zhuǎn)到查詢

設(shè)計程序
注冊成功- - 跳轉(zhuǎn)到登陸頁面
登陸成功- - 跳轉(zhuǎn)到系統(tǒng)主頁
登陸失敗- - 重新回到 登陸頁面
完善12306項目的注冊功能以及登陸功能
JSP
用戶輸入錯誤的信息時,做出相應的提示。登錄到主頁時,顯示當前用戶的信息
對于這些信息需要在什么時候設(shè)置,就是在對一次請求做出響應時,將相應的信息
傳遞到頁面當中
想要共享數(shù)據(jù),就需要在后臺進行數(shù)據(jù)的處理。需要將數(shù)據(jù)封裝起來,在網(wǎng)頁中來接受后臺封裝好的數(shù)據(jù)。對HTML來說,它是一種靜態(tài)頁面,用來制作網(wǎng)頁,顯示網(wǎng)頁內(nèi)容沒有問題,但是想要處理動態(tài)的數(shù)據(jù)時,用來訪問后臺傳遞的數(shù)據(jù)時,是沒有這個功能的,需要用JSP來解決這個問題
什么是JSP: JSP:動態(tài)網(wǎng)頁技術(shù)。
如何編寫JSP:在WebContent下創(chuàng)建JSP文件 修改字符集,
Eclipse-window - preferences - 搜索 file -JSP files - utf-8 - apply -OK
JSP本質(zhì)是Servlet,瀏覽器與服務器連接后,服務器的通信組件會先找到JSP,tomcat將它翻譯成servlet(jsp->.java->.class),初始化調(diào)用_jspInit(),_jspService(),_jspDestory()之后與servlet原理相同。
JSP的頁面元素

1.網(wǎng)頁內(nèi)容,HTML編寫
2.指令<%@ %> 用來設(shè)置JSP的數(shù)據(jù)項
Page:用于定義和頁面相關(guān)的屬性信息
Language=”java” JSP支持的腳本語言,目前僅支持Java
ContentType:告訴瀏覽器輸出文本的格式及編碼
PageEncoding:設(shè)置文件的編碼,定義輸出流的字符集編碼,默認iso-8859-1
Charset:設(shè)置文本內(nèi)容的字符集
Import=”java.util.*” 將指定的類引入到JSP上
JSP中page屬性可以寫多個,但建議每個page中的屬性只寫一次,import除外。
include指令:引入其他jsp
修改為了使項目默認部署到tomcat安裝目錄下的webapps中,show view—>servers—>找到需要修改的tomcat—>右擊
①停止eclipse內(nèi)的Tomcat服務器(stop)
②刪除該容器中部署的項目(add and remove)
③清除該容器相關(guān)數(shù)據(jù)(clean)
④打開tomcat的修改界面(open)
⑤找到servers location,選擇第二個(User tomcat Installation)
⑥修改deploy path為webapps
⑦保存關(guān)閉需要說明的是①②③必須操作,否則下面的步驟會被置灰無法操作。
3.嵌套java代碼,處理動態(tài)數(shù)據(jù)(腳本元素)
JSP表達式:<%= %>
內(nèi)容編譯后成為變量, 表達式 ,有返回值的方法,會顯示結(jié)果
需要導入對應的java包 import="java.util.Date"
<%= new Date() %>
JSP腳本: <% %>
內(nèi)容編譯后成為寫在方法里的java代碼片段
<%
for(int i=0;i<=5;i++){
}
%>
JSP聲明:<%! %>
內(nèi)容編譯后成為的成員變量(屬性)或成員方法
<%!
int a;
public void show(){
}
%>
腳本元素之間可以相互嵌套
<%!
public void show(){
%>
<%
for(int i=0;i<=5;i++){
%>
<%=i %>
<%
}
%>
<%!
}
%>
jsp和servlet的區(qū)別和聯(lián)系:
1.jsp經(jīng)編譯后就變成了Servlet.
(JSP的本質(zhì)就是Servlet,JVM只能識別java的類,不能識別JSP的代碼,Web容器將JSP的代碼編譯成JVM能夠識別的java類)
2.jsp更擅長表現(xiàn)于頁面顯示,servlet更擅長于邏輯控制.
3.Servlet中沒有內(nèi)置對象,Jsp中的內(nèi)置對象都是必須通過HttpServletRequest對象,HttpServletResponse對象以及HttpServlet對象得到.Jsp是Servlet的一種簡化,使用Jsp只需要完成程序員需要輸出到客戶端的內(nèi)容,Jsp中的Java腳本如何鑲嵌到一個類中,由Jsp容器完成。而Servlet則是個完整的Java類,這個類的Service方法用于生成對客戶端的響應。
JSP的9大內(nèi)置對象

JSP如何處理后臺封裝的參數(shù)
Web層共享數(shù)據(jù)的范圍:
應用對象:ServletContext 整個Web項目都可以使用
會話對象:HttpSession 瀏覽器從打開到關(guān)閉,就是一個會話。
請求對象:HttpServletRequest 在一次請求中公用一個對象
頁面對象:PageContext 在當前頁面中有效
原則:盡量使用范圍小的共享數(shù)據(jù)對象
利用request作數(shù)據(jù)共享:
request.setAttribute(數(shù)據(jù)名,數(shù)據(jù)值) / request.getAttribute(數(shù)據(jù)名)
session. setAttribute(數(shù)據(jù)名,數(shù)據(jù)值) / session. getAttribute(數(shù)據(jù)名)
在JSP頁面中獲取后臺傳遞的數(shù)據(jù),默認是Object,需要類型轉(zhuǎn)換
<%
String error=(String)request.getAttribute("error");
%>
<form action="Servlet1">
用戶名<input type="text" name="username">
<span>
<%
if(error!=null){
%>
<%=error %>
<%
}
%>
</span><br>
用戶名<input type="password" name="pwd">
<input type="submit">
</form>
設(shè)計程序
登陸失敗 重新回到登陸頁面 在登陸頁中顯示錯誤提示
完成12306項目 登陸頁錯誤提示
會話對象HttpSession
指的是一段時間內(nèi),單個客戶端與服務器之間多次的交互過程
作用范圍:瀏覽器從打開到關(guān)閉,都可以使用
會話對象的作用
保證同一個客戶端,多次請求之間的聯(lián)系
創(chuàng)建HttpSession
HttpSession session=request.getSession();
session.setAttribute(key, value);
JSP中獲取Session
HttpSession sessions=request.getSession();
sessions.getAttribute("")
設(shè)計程序
登陸成功后,在主要顯示當前用戶名
銷毀Session對象
session.invalidate();
設(shè)計程序
主頁中設(shè)計退出按鈕,完成退出功能
正常情況 退出之后 跳轉(zhuǎn)到登陸頁
這里為了驗證是否退出成功,可以重新跳轉(zhuǎn)到主頁 查看用戶名是否存在
如果不存在 表示session對象已經(jīng)被銷毀 退出成功
完成12306項目 主頁退出功能
可以設(shè)計退出后重定向到主頁,看是否存在用戶名
12306項目網(wǎng)頁用frame進行嵌套的,則無法使用轉(zhuǎn)發(fā)進行頁面跳轉(zhuǎn)
驗證碼
編寫驗證碼工具類
public final class ImageUtil {
// 驗證碼字符集
private static final char[] chars = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
// 字符數(shù)量
private static final int SIZE = 4;
// 干擾線數(shù)量
private static final int LINES = 5;
// 寬度
private static final int WIDTH = 80;
// 高度
private static final int HEIGHT = 40;
// 字體大小
private static final int FONT_SIZE = 30;
/**
* 生成隨機驗證碼及圖片
*/
public static Object[] createImage() {
StringBuffer sb = new StringBuffer();
// 1.創(chuàng)建空白圖片
BufferedImage image = new BufferedImage(
WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
// 2.獲取圖片畫筆
Graphics graphic = image.getGraphics();
// 3.設(shè)置畫筆顏色
graphic.setColor(Color.LIGHT_GRAY);
// 4.繪制矩形背景
graphic.fillRect(0, 0, WIDTH, HEIGHT);
// 5.畫隨機字符
Random ran = new Random();
for (int i = 0; i <SIZE; i++) {
// 取隨機字符索引
int n = ran.nextInt(chars.length);
// 設(shè)置隨機顏色
graphic.setColor(getRandomColor());
// 設(shè)置字體大小
graphic.setFont(new Font(
null, Font.BOLD + Font.ITALIC, FONT_SIZE));
// 畫字符
graphic.drawString(
chars[n] + "", i * WIDTH / SIZE, HEIGHT / 2);
// 記錄字符
sb.append(chars[n]);
}
// 6.畫干擾線
for (int i = 0; i < LINES; i++) {
// 設(shè)置隨機顏色
graphic.setColor(getRandomColor());
// 隨機畫線
graphic.drawLine(ran.nextInt(WIDTH), ran.nextInt(HEIGHT),
ran.nextInt(WIDTH), ran.nextInt(HEIGHT));
}
// 7.返回驗證碼和圖片
return new Object[]{sb.toString(), image};
}
/**
* 隨機取色
*/
public static Color getRandomColor() {
Random ran = new Random();
Color color = new Color(ran.nextInt(256),
ran.nextInt(256), ran.nextInt(256));
return color;
}
}
Servlet中獲取驗證碼
// 生成驗證碼圖片
Object[] objs = ImageUtil.createImage();
// 將驗證碼存入session
String imgcode = (String) objs[0];
request.getSession().setAttribute("imgcode", imgcode);
// 將圖片輸出給瀏覽器
BufferedImage img = (BufferedImage) objs[1];
response.setContentType("image/png");
// tomcat自動創(chuàng)建輸出流
// 目標就是本次訪問的瀏覽器
OutputStream os = response.getOutputStream();
ImageIO.write(img, "png", os);
os.close();
客戶端調(diào)用驗證碼
<img src=Servlet映射路徑" alt="驗證碼"
onclick="this.setAttribute('src','Servlet映射路徑?x='+Math.random())"/>
會話對象Cookie
HTTP是無狀態(tài)協(xié)議,服務器無法記住瀏覽器,cookie和session能夠?qū)顟B(tài)進行管理,讓服務器記住瀏覽器。
狀態(tài):用來證明瀏覽器來過服務器的表示數(shù)據(jù)
Cookie是在客戶端保存信息的技術(shù)
Cookie 是一小段文本信息,伴隨著用戶請求和頁面在 Web 服務器和瀏覽器之間傳遞。用戶每次訪問站點時,Web 應用程序都可以讀取 Cookie 包含的信息。
cookie原理.
讓瀏覽器記住鍵值對.是向響應頭中添加一下頭即可:
set-Cookie:name=tom;
瀏覽器記住之后,向服務器發(fā)送鍵值對,是在請求頭中添加下面的信息:
Cookie: name=tom;
創(chuàng)建 Cookie
創(chuàng)建Cookie對象 設(shè)置存儲的內(nèi)容
Cookie cookie=new Cookie("username","chen");
設(shè)定cookie的保存時長,單位 秒
cookie.setMaxAge(60*60*5);
將cookie添加到response對象中
response.addCookie(cookie);
cookie細節(jié)問題:
1.瀏覽器記多久?
默認是在會話期間有效.(關(guān)閉瀏覽器,cookie就被刪除).(有效時間-1)
2.有效時間如何設(shè)置?
//設(shè)置cookie的最大有效時間
1>設(shè)置一個正數(shù),標示最大有效時間.單位是秒
//cookie.setMaxAge(60*60);
2>設(shè)置為-1 , 就是相當于默認有效時間, 瀏覽器關(guān)閉就消失.
//cookie.setMaxAge(-1);
3> 標示cookie的有效時間為0.發(fā)送到瀏覽器就消失了.
JSP中獲取Cookie
<%
String name="";
Cookie[] cookies=request.getCookies();
/* 通過cookie中的key 獲取需要的cookie元素 */
for(Cookie cookie:cookies){
if(cookie.getValue().equals("chen")){
name=cookie.getValue();
}
}
%>
Cookie的原理

Cookie的特點:
存儲在瀏覽器端,隱私性差,安全性較低。
保存在本地磁盤中,臨時存儲。
用于數(shù)據(jù)的傳遞
設(shè)計程序
登陸成功的用戶,關(guān)閉瀏覽器后。下一次打開瀏覽器時
登陸頁自動顯示用戶名和密碼
解決自動登錄問題:Cookie

當用戶訪問到一在創(chuàng)建這個SESSION的時候,服務器首先檢查這個用戶發(fā)來的請求里是否包含了一個SESSION ID,如果包含了一個SESSION ID則說明之前該用戶已經(jīng)登陸過并為此用戶創(chuàng)建過SESSION,那服務器就按照這個SESSION ID把這個SESSION在服務器的內(nèi)存中查找出來(如果查找不到,就有可個服務器,如果服務器啟用Session,服務器就要為該用戶創(chuàng)建一個SESSION,能為他新創(chuàng)建一個),如果客戶端請求里不包含有SESSION ID,則為該客戶端創(chuàng)建一個SESSION并生成一個與此SESSION相關(guān)的SESSION ID。這個SESSION ID是唯一的、不重復的、不容易找到規(guī)律的字符串,這個SESSION ID將被在本次響應中返回到客戶端保存,而保存這個SESSION ID的正是COOKIE,這樣在交互過程中瀏覽器可以自動的按照規(guī)則把這個標識發(fā)送給服務器。
3.原理
瀏覽器第一次訪問服務器,服務器會在內(nèi)存中開辟一個空間(session),并把session對應的ID發(fā)送給瀏覽器.
那么下次瀏覽器再去訪問服務器,會把sessionID 交給服務器,服務器通過sessionID 找到剛才開辟的空間.
以上就是session的原理.
4.session細節(jié)問題
1> 服務器讓瀏覽器記住sessionID的cookie 默認過期時間是 (-1)==> 關(guān)閉瀏覽器 cookie就丟失 ==> cookie丟失 sessionID就丟失 ==> 找不到服務器的session
2> session中除了 4個操作 map的方法之外,還有哪些方法.
long getCreationTime() 獲得創(chuàng)建時間
String getId() 獲得sessionID
long getLastAccessedTime() 獲得最后一次訪問時間
int getMaxInactiveInterval() 獲得session的壽命
void setMaxInactiveInterval(int interval) 設(shè)置session的過期時間
void invalidate() 讓session立即失效
boolean isNew()
3> 關(guān)于設(shè)置session的最大有效時間
默認是30分鐘. ==> 在tomcat的web.xml中 <session-config> 配置的.
如何修改session的過期時間?
1.修改在tomcat的web.xml中 <session-config> ==> 影響服務器中的所有項目
2.在項目的web.xml中 加入<session-config> 配置.==> 影響的是當前項目
3.通過setMaxInactiveInterval(int interval)方法設(shè)置.==> 當前操作的session
4>(了解內(nèi)容)URL重寫
如果瀏覽器 禁用cookie功能不能保存任何cookie.那么session技術(shù)要是用 cookie來保存sessionID. 沒有cookie怎么保存?
使用url重寫解決該問題.
將頁面中所有的連接 末尾全都加上 cookieid的參數(shù). 這樣用戶點擊連接訪問網(wǎng)站,通過url把SeesionID帶到了服務器.這樣就解決了.
但是 互聯(lián)網(wǎng)行業(yè)沒有這么干的.
當用戶長時間沒有做出任何指令和動作時,自動退出。
解決方式:修改session的超時時間,默認30分鐘。當服務器(tomcat)檢查到用戶超過這個時間沒有任何動作時,將session銷毀。從session不活動的時候開始計算,如果session一直活動,session就總不會過期。從該Session未被訪問,開始計時; 一旦Session被訪問,計時清0;在web.xml配置<session-config> <session-timeout></~></session-config>
EL表達式:代替JSP中的JAVA代碼,作為動態(tài)數(shù)據(jù)的輸出。
JSP表達式如果為空值時,會報空指針異常,在代碼上需要做判斷處理
而EL表達式則不會有這樣的問題
語法:${表達式}
可以訪問req和res中的數(shù)據(jù),可以訪問cookie和其他請求報文中的信息
EL表達式默認從4個內(nèi)置對象中取值,并且是依次取值。(page,request ,session,appliction)
從小的作用域開始查找對應的數(shù)據(jù)對象,找到為止。
在實際開發(fā)中,不同的作用域不建議起相同的數(shù)據(jù)名
Cookie不是EL的內(nèi)置對象,取值 ${cookie.參數(shù)名.value}
練習:用EL表達式獲取bean(實體類)中的屬性和方法 ${user.username}
數(shù)據(jù)庫連接池
數(shù)據(jù)庫連接的建立和資源的關(guān)閉都是消耗巨大的
每次操作數(shù)據(jù)庫都要打開,關(guān)閉物理連接,系統(tǒng)的性能嚴重受損
解決方案:
系統(tǒng)初始運行的時候,主動建立足夠的連接,組成一個連接池。
每次程序請求數(shù)據(jù)庫連接時,無需重新打開數(shù)據(jù)庫連接,而是從連接池
中獲取已有的連接。使用完后,不再關(guān)閉,而是歸還給連接池。
private static BasicDataSource ds;// 數(shù)據(jù)庫連接池
static {
ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");// Class.forName(...)
ds.setUrl("jdbc:mysql://localhost:3306/mysql");
ds.setUsername("root");
ds.setPassword("root");
ds.setInitialSize(5);
System.out.println(ds.getInitialSize());
}
/**
* 獲取數(shù)據(jù)庫連接
*/
public static Connection getConnection() throws Exception {
return ds.getConnection();
}
public static void closeConnection(Connection conn) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
功能顯示查詢數(shù)據(jù) (組合查詢)
由于查詢的條件不同,所有顯示的數(shù)據(jù)也會有所不同(內(nèi)容和數(shù)量)
HTML本身的標簽無法實現(xiàn),需要使用自定義標簽JSTL
jstl.jar在jsp中通過taglib指令引入,才可以使用.<%@ taglib uri=”” prefix=”” %>
uri:是自定義標簽庫的地址 prefix:標簽庫的別名

<c:foreach items=”” var =””> </> 循環(huán)遍歷

分頁查詢

刪除功能
ServletConfig對象是什么?
封裝了servlet在web.xml中的配置.
方法:
1>getServletName ==> 獲得配置文件中 <servlet-name> 元素的內(nèi)容
2>getInitParameter ==> 根據(jù) <init-param>中的 <param-name> 獲得 </param-value>
<init-param>
<param-name>name</param-name>
<param-value>tom</param-value>
</init-param>
3>getInitParameterNames 返回所有<param-name> .
HTTPServlet:
1.因為我們web項目基于HTTP協(xié)議,所以Service方法中傳過來的request,response對象都是 基于HTTP協(xié)議的.
也就是HttpServletReueqst,也就是HttpServletResponse. 它幫我們進行了強轉(zhuǎn).
2.我們有可能在不同的請求方式時做不同的事情. 根據(jù)請求方式不同,調(diào)用不同的方法
例如 GET --> doGet()
POST ==> doPost();
相關(guān)對象之 ---- ServletContext
1.獲得: servletConfig ==> getServletContext
2.servletContext 的作用
1> servletContext 封裝了web.xml 中的配置
<context-param>
<param-name>name</param-name>
<param-value>jerry</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>1234</param-value>
</context-param>
getInitParameterNames(); ==> 獲得所有鍵
getInitParameter(key); ==> 根據(jù)鍵獲得對應的值
2> servlet技術(shù)中3大域?qū)ο笾?
ServletContext對應著Application(應用)域.利用了一個項目中只有一個ServletContext實例的特點.
在servletContext中放置了一個map用作數(shù)據(jù)通信.
這個Map就是所謂域.
關(guān)于域的操作,有4個.
放入鍵值對 setAttribute(key,value)
通過鍵取值 getAttribute(key)
通過鍵刪除 removeAttribute(key)
遍歷所有鍵 getAttributeNames()
application ==> servletContext
session ==>
request ==>
3>獲得項目中資源.
所有servletContext中關(guān)于路徑的獲得,相對路徑都是相對的 WebRoot(項目根)下
getRealPath ==> 通過相對路徑獲得絕對路徑
getResourceAsStream ==> 根據(jù)相對路徑獲得指定資源流
3.servlet技術(shù)中對象的范圍
servlet ==> 項目啟動期間一個servlet只有一個servlet實例
request ==> 項目啟動期間,request對象的數(shù)量,要看當前有多少個請求正在處理.
response ==> 同上.
servletConfig ==> 一個servlet實例對應一個servletConfig對象
servletContext ==> 整個項目中,永遠只有一個servletContext實例存在
在web.xml中配置錯誤頁面攔截(報錯后跳轉(zhuǎn)到錯誤頁面)
正常情況系統(tǒng)不應該將報錯的頁面顯示給用戶,或者說不應該讓用戶看到。對于一些懂技術(shù)的人來說,看到報錯信息,可能會找到系統(tǒng)的漏洞,造成不必要的麻煩。
解決:系統(tǒng)報錯時,根據(jù)錯誤類型,跳轉(zhuǎn)到相應的頁面
通過配置web.xml文件,讓tomcat統(tǒng)一處理異常,即告訴tomcat在發(fā)生異常時,轉(zhuǎn)發(fā)到什么錯誤頁面
1.通過異常類型聲明
<error-page>
<exception-type>java.langException</ exception-type>
<location>錯誤網(wǎng)頁的url</location>
</error-page>
2.通過錯誤編碼聲明(405,500寫法相同)
<error-page>
<error-code>404< /error-code>
<location>錯誤網(wǎng)頁的url</location>
</ error-page>
由于任何地方都可能報錯,所以無法確定相對路徑,所以JSP訪問路徑應該為絕對路徑
并且該路徑不能寫項目名,tomcat會自動補充。
過濾器
解決項目中的一些共性需求,如日志,過濾敏感詞,登錄檢查等。
創(chuàng)建一個過濾器:該類實現(xiàn)了Filter接口,重寫了三個方法 init(),destroy(),doFilter()
init() 初始化方法,destroy( ) 銷毀方法 ,通常不寫內(nèi)容
doFilter():在tomcat啟動時,會自動調(diào)用該方法,傳入ServletRequest,ServletResponse
由于需要獲取session和servlet中的訪問路徑,需要對參數(shù)進行強轉(zhuǎn)為HttpServletRequest
HttpServletResponse
配置webxml
<filter>
<filter-name></filter-name>
<filter-class></filter-class>
</filter>
<filter-mapping>
<filter-name></filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
過濾器原理:
1.通過過濾器統(tǒng)一解決亂碼問題
在過濾器的doFilter方法中設(shè)置編碼的轉(zhuǎn)換,在執(zhí)行chain.doFilter(request, response);之前
將編碼設(shè)置成utf-8
chain.doFilter(request, response);表示將請求交給下一個Filter或者Servlet處理
如果不調(diào)用該方法則請求結(jié)束。
2.通過Filter進行系統(tǒng)校驗,用戶只能通過登錄頁面進入系統(tǒng)
設(shè)置了過濾器之后,所有的請求都會被攔截,也就是登錄的請求也會被攔截
那么就需要將該請求排除攔截的范圍。其他的請求不變。
登錄的用戶會把信息保存在session中,若sesion中沒有數(shù)據(jù) 則該用戶沒有登錄,進行攔截
跳轉(zhuǎn)到登錄頁面。
FileUpload實現(xiàn)文件上傳
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
System.out.println(isMultipart);
//1、創(chuàng)建一個DiskFileItemFactory工廠
DiskFileItemFactory factory = new DiskFileItemFactory();
//2、創(chuàng)建一個文件上傳解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//解決上傳文件名的中文亂碼
upload.setHeaderEncoding("UTF-8");
upload.setSizeMax(1024 * 1024 * 5);//設(shè)置上傳的文件總的大小不能超過5M
try {
//解析請求對象
List<FileItem> fileList= upload.parseRequest(request);
//遍歷請求結(jié)果
Iterator<FileItem> iter = fileList.iterator();
while(iter.hasNext()){
FileItem item = iter.next();
//判斷當前遍歷到的元素是否為普通的表單
if(item.isFormField()){
String name = new String(item.getFieldName().getBytes("iso8859-1"),"utf-8");
String value = new String(item.getString().getBytes("iso8859-1"),"utf-8");
System.out.println(name);
System.out.println(value);
}else{
//圖片的上傳
//獲取文件名
String fileName = item.getName();
System.out.println(fileName);
//重命名
String newFileName = new Date().getTime()+fileName.substring(fileName.indexOf('.'));
//構(gòu)建File對象
System.out.println(getServletContext().getRealPath("/images/photo"));
File file = new File( getServletContext().getRealPath("/images/photo"),newFileName);
item.write(file);
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
文件上傳的問題
上傳的圖片保存在tomcat下的webapps中,并不是本地的項目空間。如果平時測試代碼時需要重新部署項目,這將導致webapps下的項目被項目空間的所替換,之前上傳到服務器中的文件也就消失了。
測試臨時解決辦法:將文件上傳路徑,設(shè)置為項目空間
歸根到底這些問題其實還是因為我們是在調(diào)試的工程中,發(fā)布后肯定是不會出現(xiàn)這些問題的。發(fā)布了之后你的tomcat服務器只有關(guān)閉和打開,而不會對工程重新部署,自然也就不會出現(xiàn)這些問題
上傳圖片文件(圖像)時如何立即顯示
<script type="text/javascript">
//判斷瀏覽器是否支持FileReader接口
if (typeof FileReader == 'undefined') {
alert("<h1>當前瀏覽器不支持FileReader接口</h1>");
}
//選擇圖片,馬上預覽
function xmTanUploadImg(obj) {
var file = obj.files[0];
var reader = new FileReader();
reader.onload = function(e) {
var img = document.getElementById("img1");
console.log(e.target.result);//Date url格式
img.src = e.target.result;
}
reader.readAsDataURL(file);
}
</script>
<form action="FileUpdateServlet" method="post" enctype="multipart/form-data">
<input type="file" name="headr" onchange="xmTanUploadImg(this)">
<input type="submit">
<img alt="" id="img1">
</form>
Ajax是一種用來改善用戶體驗的技術(shù)。其實質(zhì)是利用瀏覽器提供的ajax對象(XMLHttpRequest) 異步的向服務器發(fā)送請求,服務器響返回數(shù)據(jù),瀏覽器利用這些數(shù)據(jù)進行頁面的局部更新
整個過程,頁面無刷新效果,不打斷用戶的操作。
異步:指的是當ajax對象發(fā)送請求時,瀏覽器不會銷毀當前頁面
提交表單請求時,會銷毀當前頁面(刷新)
獲取ajax對象
function getXhr(){
var xhr;
if(window.XMLHttpRequest){
非IE
xhr=new XMLHttpRequest();
}else{
IE瀏覽器下獲取方式
xhr=new ActiveXObject("Microsoft.XMLHttp");
}
return xhr;
}
觸發(fā)ajax的事件函數(shù)
onreadystatechange:綁定事件的處理函數(shù)
當readyState屬性值發(fā)生改變時,會觸發(fā)readystatechange事件
readyState:有5個值(0,1,2,3,4),表示ajax對象與服務器的通信進度
當值為4的時候,表示已經(jīng)獲得了服務器返回的數(shù)據(jù)
status:表示服務器返回的狀態(tài)碼 200表示成功
responseText:表示服務器返回的文本數(shù)據(jù)
xhr.send():將請求發(fā)送給服務器,必須寫
function sendHttpReq(){
獲取ajax對象
var xhr=getXhr();
通過ajax向服務器發(fā)送請求
xhr.open("get","servlet映射路徑",true);
xhr.onreadystatechange=function(){
if(xhr.readyState==4&&xhr.status==200){
var msg=xhr.responseText;
}
};
xhr.send();
}
服務器相應ajax
PrintWriter pw= response.getWriter();
pw.print(響應信息);
pw.close();