欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

目錄

柚子快報(bào)激活碼778899分享:Servlet

柚子快報(bào)激活碼778899分享:Servlet

http://yzkb.51969.com/

一 Servlet概述

1.1 什么是Servlet

Servlet 是 Server Applet 的簡(jiǎn)稱,是用Java編寫的,可以運(yùn)行在 Web 服務(wù)器(Tomcat)上的程序,是Sun公司制定的一套規(guī)范(接口)。

Servlet的主要用途:

接受、處理來自瀏覽器端(BS架構(gòu)中的B端)的請(qǐng)求和用戶輸入 響應(yīng)來自數(shù)據(jù)庫(kù)或者服務(wù)端(BS架構(gòu)中的S端)產(chǎn)生的數(shù)據(jù)到瀏覽器端,動(dòng)態(tài)構(gòu)建網(wǎng)頁(yè)。

1.2 手動(dòng)實(shí)現(xiàn)Servlet小程序

1.2.1 實(shí)現(xiàn)步驟

自定義一個(gè)類型,實(shí)現(xiàn)Servlet接口或者繼承HttpServlet類 使用javac指令,將源文件編譯成字節(jié)碼文件 將編譯完的字節(jié)碼文件按照一定的組織結(jié)構(gòu)打包,并編寫web.xml配置文件 將整個(gè)組織結(jié)構(gòu)放入Tomcat的webapps文件夾中 啟動(dòng)Tomcat,在瀏覽器上輸入符合規(guī)范的地址去訪問Servlet。

1.2.2 具體實(shí)現(xiàn)

步驟1: 編寫一個(gè)類HelloWorldServlet,繼承HttpServlet類型

package com.zrgj;

?

import java.io.IOException;

?

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

?

public class HelloWorldServlet extends HttpServlet{

@Override

public void service(HttpServletRequest request,HttpServletResponse response)

throws ServletException,IOException{

response.getWriter().println("hello world");

}

}

步驟2: 編譯,生成.class文件

javac HelloWorldServlet.java -classpath ? xxxxx\xxxxxx\servlet-api.jar

步驟3:項(xiàng)目的組織結(jié)構(gòu)

appName 項(xiàng)目名稱(主要用來區(qū)分其他項(xiàng)目的)

-- ? WEB-INF文件夾

-- classes文件夾: 用來存儲(chǔ)class文件的整個(gè)路徑

? com\zrgj\HelloWorldServlet.class

-- lib(可選文件夾)

-- web.xml: 當(dāng)前項(xiàng)目的主配置文件

-- index.jsp

? -- css

? -- js

? -- html

比如:

myfirstservlet ?

-- WEB-INF

? ? --classes

? ? --web.xml

web.xml里的內(nèi)容如下:

version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"

? ? ? ? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

? ? ? ? xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"

? ? ? ? version="4.0">

? ?

? ?<servlet>

? ? ? ?<servlet-name>aservlet-name>

? ? ? ?<servlet-class>com.zrgj.HelloWorldServletservlet-class>

? ?servlet>

? ?<servlet-mapping>

? ? ? ?<servlet-name>aservlet-name>

? ? ? ?<url-pattern>/hellourl-pattern>

? ?servlet-mapping>

web-app>

步驟4:將整個(gè)文件夾組織結(jié)構(gòu),拷貝到tomcat的webapps文件夾里。這一步的專業(yè)術(shù)語叫部署項(xiàng)目

步驟5:?jiǎn)?dòng)tomcat

找到tomcat的bin目錄下的startup.bat可執(zhí)行文件,啟動(dòng)后,不要關(guān)閉。

步驟6:在瀏覽器上輸入地址,向tomcat容器發(fā)送請(qǐng)求

http://localhost:8080/myfirstweb/hello ,回車后,應(yīng)該會(huì)看到hello world字樣

部署完項(xiàng)目后的執(zhí)行流程:

1. 瀏覽器向服務(wù)器發(fā)送請(qǐng)求,訪問服務(wù)器上的某一個(gè)項(xiàng)目下的某一個(gè)資源。 ?

? 路徑如下:http://服務(wù)器IP:服務(wù)器端口/項(xiàng)目名/資源路徑

2. 服務(wù)器收到請(qǐng)求后,會(huì)先確認(rèn)并找到該項(xiàng)目

3. 如果找到了該項(xiàng)目,會(huì)加載里面的web.xml配置文件

4. 然后通過資源路徑,去匹配servlet-mapping里的url-pattern,來確定servlet-name。

5. 根據(jù)servlet-name,定位到對(duì)應(yīng)的servlet里的servlet-class。

6. 根據(jù)servlet-class標(biāo)簽里的類全名,去項(xiàng)目的classes目錄下查找對(duì)應(yīng)的類文件

7. 執(zhí)行類文件里的service方法,將數(shù)據(jù)最終響應(yīng)給瀏覽器

1.3 Idea開發(fā)Servlet程序

第一步:創(chuàng)建java項(xiàng)目(java module):MyFirstWeb。

第二步:添加web框架支持。 也就是找到add Frameworks Support,選擇web application.

幫助我們自動(dòng)維護(hù)web項(xiàng)目的組織結(jié)構(gòu): web-inf,web.xml

第三步:在WEB-INF下創(chuàng)建lib文件夾,將第三方j(luò)ar包放入,比如servlet-api.jar文件

注意:別忘記 add as library

第四步:編寫Servlet組件

第五步:配置web.xml

第六步:關(guān)聯(lián)tomcat:

edit configuration...

?

add new ...

?

tomcat server (注意千萬不要用tomEE server)

?

local:

?

選擇tomcat home

?

fix ? 定義項(xiàng)目部署的虛擬名稱

?

apply ok

第七步:?jiǎn)?dòng)tomcat 進(jìn)行測(cè)試

1.4 常見的HTTP錯(cuò)誤代碼

404:Not found,表示您要請(qǐng)求的資源服務(wù)器無法幫您找到。原因可能如下:

1. 沒有寫web.xml配置文件

2. 地址欄上的地址信息寫錯(cuò)了,可能沒有寫部署的項(xiàng)目名稱,或者項(xiàng)目名后的資源路徑寫錯(cuò)誤

3. web.xml里的url-pattern對(duì)應(yīng)上了,但是兩個(gè)name沒有對(duì)應(yīng)上。

6:上面都改正確了,但是忘記了重新部署。 ? ^_^

405:Method Not Allowed

servlet組件里沒有重寫service/doGet/doPost方法,或者是方法寫的不標(biāo)準(zhǔn),比如參數(shù),異常的聲明等。

500:Internal Server Error,表示服務(wù)器內(nèi)部發(fā)生錯(cuò)誤

1. servlet-class標(biāo)簽里的類名書寫有誤。

2. 編寫的類型不是一個(gè)servlet組件,也就是沒有繼承HttpServlet或者實(shí)現(xiàn)Servlet接口

3. Servlet 代碼中拋出異常導(dǎo)致的,也就是servlet類里你寫的代碼有問題

二 Servlet工作原理

2.1 Servlet的生命周期

servlet容器是如何創(chuàng)建Servlet對(duì)象,如何為Servlet對(duì)象分配資源,如何調(diào)用Servlet對(duì)象的方法來處理請(qǐng)求,以及如何銷毀Servlet對(duì)象的整個(gè)過程。而這個(gè)過程可以分為四個(gè)階段,分別是實(shí)例化階段、初始化階段、就緒階段、銷毀階段

2.1.1 階段一:實(shí)例化

什么是實(shí)例化?

即容器調(diào)用Servlet的構(gòu)造器,創(chuàng)建一個(gè)Servlet對(duì)象 MySecondServlet s = new MySecondServlet() ? <------不是程序員調(diào)用的,而是容器幫助我們調(diào)用并創(chuàng)建的。

什么時(shí)候?qū)嵗?/p>

情形一,開始容器里面沒有Servlet對(duì)象,只有收到請(qǐng)求后才會(huì)創(chuàng)建Servlet對(duì)象(默認(rèn)情況) 當(dāng)瀏覽器發(fā)送請(qǐng)求:http://localhost:8088/employee_v1/listEmp

tomcat容器會(huì)收到該請(qǐng)求,該請(qǐng)求是請(qǐng)求的是ListEmp.class這個(gè)組件,因此tomcat容器會(huì)幫助程序員創(chuàng)建ListEmp這個(gè)組件的對(duì)象

?

其他的沒有訪問過的組件,比如AddEmp,DelEmp等這些組件,在容器中沒有。。。。。。 情形二,容器啟動(dòng)之后就立即創(chuàng)建相應(yīng)的實(shí)例, 需要添加配置1 1表示創(chuàng)建,-1表示不創(chuàng)建

addEmp

com.shuilidianli.employee.web.AddEmp

1

addEmp

/addEmp

總結(jié):

1. 誰負(fù)責(zé)實(shí)例化servlet類(也可以叫組件)的對(duì)象 : tomcat(servlet容器)

2. 什么時(shí)機(jī)實(shí)例化:

- 瀏覽器發(fā)送請(qǐng)求這個(gè)組件時(shí)創(chuàng)建

- 添加配置參數(shù)load-on-startup, 在tomcat服務(wù)器啟動(dòng)時(shí)創(chuàng)建。

2.1.2 階段二:初始化

什么是初始化?

容器在創(chuàng)建好Servlet對(duì)象后,會(huì)立即調(diào)用該對(duì)象的init方法 一般情況下,我們不用寫init方法,因?yàn)間enericServlet已經(jīng)提供了init方法的實(shí)現(xiàn)(將容器傳遞過來的ServletConfig對(duì)象保存下來,并且,提供了getServletConfig方法來獲取ServletConfig對(duì)象)。 init方法只會(huì)執(zhí)行一次

默認(rèn)情況下,init方法不需要重寫。但是有的時(shí)候,如果你有這方面的需求時(shí),比如將公司信息作為初始化參數(shù),用于init方法來到程序中,就可以重寫init進(jìn)行獲取。

Servlet的初始化參數(shù)如何配置,在web.xml中添加如下形式:

school

吉林大學(xué)

注意:init-param的位置必須放在load-on-startup前面

如何讀取Servlet的初始化參數(shù)

String ServletConfig.getInitParameter("school")

總結(jié):

servlet容器在實(shí)例化servlet對(duì)象后,會(huì)自動(dòng)調(diào)用init方法進(jìn)行初始化操作。程序員可以重寫init方法。 使用ServletConfig對(duì)象來讀取初始化參數(shù)。

2.1.3 階段三:就緒

容器收到請(qǐng)求后調(diào)用Servlet對(duì)象的service()來處理請(qǐng)求

2.1.4 階段四:銷毀

容器依據(jù)自身算法刪除Servlet對(duì)象,刪除前會(huì)調(diào)用destroy() 只會(huì)執(zhí)行一次 可以override destroy方法來實(shí)現(xiàn)自己的處理邏輯 應(yīng)用程序卸載時(shí)一定會(huì)調(diào)用destroy方法

web.xml

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"

version="4.0">

life

com.shuilidianli.web.LifeServlet

school

shuilidianli

1

life

/life

組件:

package com.shuilidianli.web;

import javax.servlet.*;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

public class LifeServlet extends GenericServlet {

public void service(ServletRequest request,

ServletResponse resp) throws ServletException, IOException {

//獲取初始化階段的數(shù)據(jù),

//獲取ServletConfig對(duì)象

ServletConfig servletConfig = super.getServletConfig();

//獲取初始化參數(shù)

String school = servletConfig.getInitParameter("school");

System.out.println(school);

}

@Override

public void init() throws ServletException {

System.out.println("------init--------");

}

@Override

public void destroy() {

System.out.println("------銷毀--------");

}

}

2.2 請(qǐng)求方式

2.2.1 請(qǐng)求方式介紹

不同的請(qǐng)求方式在數(shù)據(jù)傳輸時(shí),會(huì)有所不同;在表單提交以及服務(wù)器處理時(shí)都會(huì)采用不同的方式。瀏覽器針對(duì)每種請(qǐng)求方式也會(huì)使用不同的緩存技術(shù),提高相應(yīng)的處理速度。

常用的請(qǐng)求方式有:

get: 請(qǐng)求服務(wù)器上指定的資源

post: 向服務(wù)器上的資源提交數(shù)據(jù)

head: 和get相似

put: 上傳資源

delete: 刪除資源

get請(qǐng)求:

瀏覽器發(fā)送get請(qǐng)求的場(chǎng)景:

1. 在地址欄單純的輸入一個(gè)地址

2. a標(biāo)記產(chǎn)生的請(qǐng)求

3. form表單默認(rèn)提交方式,也是get請(qǐng)求

注意:

1. get請(qǐng)求,如果帶有一些提交數(shù)據(jù),比如用戶名,密碼等。那么這些數(shù)據(jù)會(huì)被添加到地址欄中,不安全。

2. get請(qǐng)求提交的數(shù)據(jù)量比較小,在4KB以內(nèi)。

post:

瀏覽器發(fā)送post請(qǐng)求的場(chǎng)景:

1. form表單的method屬性的值為post時(shí)。

注意:

要傳輸給服務(wù)器的處理數(shù)據(jù)都會(huì)在正文(http信息數(shù)據(jù)的body)中存儲(chǔ)。相對(duì)安全

小貼士:

如果想要提交form表單,兩個(gè)屬性要知道:

1. method屬性,用于指定請(qǐng)求方式,默認(rèn)不寫是get請(qǐng)求

2. action屬性,是必填項(xiàng),因?yàn)閍ction的值就是地址欄上的url-pattern.

2.2.2 service/doGet/doPost/

實(shí)際上:當(dāng)瀏覽器發(fā)送請(qǐng)求后,會(huì)默認(rèn)執(zhí)行servlet組件繼承過來的service方法,然后service方法里的邏輯:String method = req.getMethod(); 會(huì)獲取請(qǐng)求的方法,

如果是get請(qǐng)求,會(huì)執(zhí)行doGet(req, resp); 如果是post請(qǐng)求,會(huì)執(zhí)行doPost(req, resp);

上述代碼說明:程序員在寫servlet時(shí),可以選擇覆蓋service方法,也可以選擇覆蓋doGet() 或者是doPost方法。前提如果是get請(qǐng)求,可以直接覆蓋doGet(), 如果是post請(qǐng)求,可以直接覆蓋doPost()

注意:如果重寫了service方法,就不會(huì)再執(zhí)行doGet/doPost方法,除非重寫的service方法里調(diào)用了doGet/doPost

package com.shuilidianli.web;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.io.PrintWriter;

public class TestMethodServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

System.out.println("-----doGet-------");

PrintWriter pw = resp.getWriter();

pw.println("get");

pw.close();

}

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

System.out.println("-----doPost-------");

doGet(req,resp);

}

}

web.xml

test

com.shuilidianli.web.TestMethodServlet

test

/test

test.html

Title

2.3 請(qǐng)求對(duì)象

web服務(wù)器(tomcat容器)在接收到瀏覽器發(fā)送過來的請(qǐng)求后,發(fā)送過來的所有通信數(shù)據(jù)都會(huì)被web服務(wù)器進(jìn)行封裝和提供。這些信息主要被封裝到兩個(gè)對(duì)象上。

一個(gè)是HttpServletRequest類型的對(duì)象:

1. 瀏覽器發(fā)送的所有數(shù)據(jù)都會(huì)被web服務(wù)器封裝到HttpServletRequest類型的對(duì)象上,此類型提供了相應(yīng)的方法可以從對(duì)象上獲取相關(guān)的數(shù)據(jù)。比如請(qǐng)求行的數(shù)據(jù)、消息頭、實(shí)體內(nèi)容(正文、參數(shù)值)

2.作用:

讀取和設(shè)置http的請(qǐng)求數(shù)據(jù)

取得和設(shè)置cookies

實(shí)現(xiàn)請(qǐng)求轉(zhuǎn)發(fā)

取得路徑信息

標(biāo)識(shí)HTTP會(huì)話

2.3.1 參數(shù)值的獲取

不管是get請(qǐng)求提交的少量數(shù)據(jù),還是post請(qǐng)求提交的大量的數(shù)據(jù)。那么服務(wù)器端就要接受到這些數(shù)據(jù),并處理。

瀏覽器發(fā)送的數(shù)據(jù)有以下兩種情況:

1:1的情況:

localhost:8088/day42_servlet/web?username=zhangsan&password=123456

上述的地址,?后面是要傳入到服務(wù)端的數(shù)據(jù),username對(duì)應(yīng)一個(gè)值,password對(duì)應(yīng)一個(gè)值

1:N的情況

localhost:8088/day42_servlet/web?username=zhangsan&password=123456&hobby=book&hobby=movie&gender=f

上述的地址,?后面是要傳入到服務(wù)端的數(shù)據(jù),username對(duì)應(yīng)一個(gè)值,password對(duì)應(yīng)一個(gè)值,gender對(duì)應(yīng)一個(gè)值

而hobby對(duì)應(yīng)兩個(gè)值,hobby與它的值就是1:N的情況

服務(wù)端的請(qǐng)求對(duì)象提供了相應(yīng)的獲取參數(shù)值的方法。

方法1:String getParameter() :

解析:獲取的是1對(duì)1的參數(shù)值, 比如用戶名或密碼

用法: String value = request.getParameter("key")

注意: 如果沒有獲取值,那么返回的是null,而不是異常

方法2:String[] getParameterValues():

解析:獲取的是1對(duì)多的參數(shù)值, 比如 愛好

用法:String[] values = request.getParameter("key")

注意:如果沒有獲取值,那么返回的是null,而不是異常

參數(shù):瀏覽器封裝的參數(shù)是以鍵值對(duì)的形式體現(xiàn)的,比如username=zhangsan. username是參數(shù)名,zhangsan是參數(shù)值。

注意:input元素的name屬性用于指定參數(shù)名

2.4 響應(yīng)對(duì)象

一個(gè)是HttpServletResponse類型的對(duì)象

1.web服務(wù)器會(huì)對(duì)瀏覽器進(jìn)行響應(yīng),響應(yīng)的所有數(shù)據(jù)都會(huì)被封裝到HttpServletResponse類型的對(duì)象上。此類型提供了相關(guān)設(shè)置方法,可以設(shè)置狀態(tài)行、消息頭、實(shí)體內(nèi)容等。

2.作用:

設(shè)置客戶端的輸出內(nèi)容

設(shè)置響應(yīng)狀態(tài)碼

設(shè)置瀏覽器的解碼方式

設(shè)置cookies

實(shí)現(xiàn)重定向

2.5 中文亂碼問題

兩處亂碼:

第一處: 后端響應(yīng)瀏覽器時(shí): response向?yàn)g覽器返回中文時(shí)出現(xiàn)亂碼

response.getWriter().println("你好,Servlet");

第二處: post請(qǐng)求時(shí),瀏覽器向后端發(fā)送了中文時(shí)出現(xiàn)了亂碼

String username = request.getParameter("username"); username=張三 是漢字時(shí)

亂碼的情況原因很簡(jiǎn)單,就是編碼過程使用的字符集與解碼過程使用的字符集不一致造成的,不是邏輯問題。

編碼:字符串變成字節(jié)數(shù)組的形式 "中國(guó)"-->[-86,-92,-78,-12,-64,-23] 使用字符手冊(cè) UTF8 三個(gè)字節(jié)對(duì)應(yīng)一個(gè)漢字

解碼:字節(jié)數(shù)組變成字符串的形式 [-86,-92,-78,-12,-64,-23]-->"中國(guó)" 使用字符手冊(cè)u(píng)ncode 兩個(gè)字節(jié)對(duì)應(yīng)一個(gè)漢字

瀏覽器使用post請(qǐng)求方式提交中文時(shí):

1. 確保瀏覽器的html頁(yè)面是utf-8編碼集

2. 在servlet中(也就是服務(wù)端)的service方法的第一行處,使用

request.setCharacterEncoding("utf-8");即可

瀏覽器使用get請(qǐng)求方式提交中文時(shí):

1. 確保瀏覽器的html頁(yè)面是utf-8編碼集

2. 因?yàn)榉?wù)端默認(rèn)使用iso-8859-1進(jìn)行解碼。我們的解決方式就是在服務(wù)端再次使用iso-8859-1進(jìn)行編碼,然后在使用utf-8進(jìn)行解碼。

String username = request.getParameter("username") //

byte[] bs = username.getBytes("iso-8859-1") ;

//借助string的構(gòu)造器,重新解碼即可

String str = new String(bs,"utf-8");//

服務(wù)端向?yàn)g覽器發(fā)送中文亂碼情況:

只需要在服務(wù)端對(duì)中文進(jìn)行編碼前,寫入這一行代碼即可:

response.setContentType("text/html;charset=utf8");

2.6 Servlet調(diào)用DAO

第一步:引入第三方資源,比如相關(guān)依賴的jar包坐標(biāo), mysql驅(qū)動(dòng),druid數(shù)據(jù)源

第二步:在resources配置druid.properties

第三步:編寫DruidUtil工具類,并測(cè)試(里面提供main方法)

第四步:根據(jù)ORM關(guān)系模型,編寫emp表的實(shí)體類Emp

第五步:編寫相關(guān)的Dao接口以及Dao接口的實(shí)現(xiàn)類

第六步:編寫EmpServlet組件

第七步: 編寫web.xml

第八步:File–>Project structure–>Artifacts–>Available Elements–>右鍵點(diǎn)擊項(xiàng)目–>put into output root

第九步:重新部署項(xiàng)目(啟動(dòng)tomcat) 在瀏覽器上輸入地址進(jìn)行測(cè)試

2.7 總結(jié) servlet的運(yùn)行流程:

1: 瀏覽器發(fā)送地址請(qǐng)求

2: 根據(jù)ip和port號(hào)定位到tomcat容器

3: tomcat容器根據(jù)appName確定項(xiàng)目

4: 然后tomcat查找當(dāng)前項(xiàng)目下的web.xml配置信息,用url-pattern與地址信息進(jìn)行匹配

5: 根據(jù)兩個(gè)相同的name找到對(duì)應(yīng)的servlet組件

6: 執(zhí)行servlet組件里的service方法(執(zhí)行的是classes里的class文件)

7: 向?yàn)g覽器發(fā)送響應(yīng)信息。

8:瀏覽器收到響應(yīng)信息后會(huì)進(jìn)行解析和顯示。

三 Servlet對(duì)路徑的處理

3.1 重定向

用戶在瀏覽器輸入一個(gè)地址,或者點(diǎn)擊按鈕觸發(fā)一個(gè)請(qǐng)求地址,然后去往服務(wù)器端,此時(shí)服務(wù)端處理完相關(guān)計(jì)算后,再次向?yàn)g覽器發(fā)送一個(gè)302狀態(tài)和一個(gè)新的地址(比如www.baidu.com). 之后瀏覽器收到了302狀態(tài)碼和一個(gè)新的地址,然后瀏覽器就重新向這個(gè)新的地址發(fā)送請(qǐng)求。

302: 表示重定向, 當(dāng)瀏覽器收到的狀態(tài)碼是302,表示需要重新發(fā)送請(qǐng)求,請(qǐng)求地址是和302一起過來的那個(gè)新的地址。

適合的場(chǎng)景:

用戶使用瀏覽器觸發(fā)了一次請(qǐng)求后,然后服務(wù)端向?yàn)g覽器發(fā)送一個(gè)新的地址,由瀏覽器自動(dòng)再次發(fā)送一個(gè)請(qǐng)求。

比如:添加一個(gè)新員工后,然后頁(yè)面自動(dòng)顯示所有員工信息,包含兩次請(qǐng)求

第一次:insert, 用戶主動(dòng)觸發(fā)的

第二次: select, 是服務(wù)端告訴瀏覽器再次觸發(fā)

再比如: 登錄成功后,跳轉(zhuǎn)到主頁(yè)面(所有員工信息) :

第一次: 登錄驗(yàn)證(LoginServlet)

-- 調(diào)用DAO的checkLogin方法,返回true或者false

-- 如果登錄成功,此時(shí)應(yīng)該向?yàn)g覽器發(fā)送響應(yīng)數(shù)據(jù)(302,新地址appName/findAll)

第二次: 跳轉(zhuǎn)到主頁(yè)面(FindAllServlet)

-- 調(diào)用DAO的findAll方法,查詢所有的員工信息,返回ResulSet

-- 遍歷ResultSet ,然后使用流對(duì)象的println方法,拼接成一個(gè)table。

-- 響應(yīng)對(duì)象將數(shù)據(jù)打包,返回給瀏覽器,瀏覽器解析成一個(gè)table

如何重定向

response.sendRedirect(String url)

url: 是重定向的新地址, 該地址可以是任意地址, 302狀態(tài)碼是響應(yīng)對(duì)象自己設(shè)置的,不需要程序員設(shè)置

重定向的特點(diǎn):

1. 重定向的地址可以是任何地址

2. 重定向后,瀏覽器的地址發(fā)生了變化

3. 重定向所涉及到的web組件并不共享同一個(gè)request和response

4. 重定向前,不可以關(guān)閉流 ,即不能調(diào)用 pw.close()

3.2 轉(zhuǎn)發(fā)

3.2.1 什么是轉(zhuǎn)發(fā)

一個(gè)web組件(servlet/jsp)將未完成的任務(wù)轉(zhuǎn)交給另外一個(gè)web(servlet/jsp)組件。

3.2.2 如何轉(zhuǎn)發(fā)

步驟1: 綁定數(shù)據(jù)

request.getAttribute("school","shuilidianli")

步驟2: 獲取轉(zhuǎn)發(fā)器,同時(shí)指定目的地的地址

RequestDispatcher rd = request.getRequestDispatcher("/servlet03");

步驟3: 開始轉(zhuǎn)發(fā),帶上request和response對(duì)象

rd.forward(request,response);

3.2.3 轉(zhuǎn)發(fā)的特點(diǎn)

轉(zhuǎn)發(fā)是服務(wù)器的行為

瀏覽器在這個(gè)過程中只有一次行為,路徑不會(huì)發(fā)生任何的變化

轉(zhuǎn)發(fā)可以帶有數(shù)據(jù) request對(duì)象中

轉(zhuǎn)發(fā)只能在當(dāng)前項(xiàng)目中進(jìn)行轉(zhuǎn)發(fā),不能轉(zhuǎn)發(fā)外部資源

3.3 員工管理系統(tǒng)v1

3.3.0 準(zhǔn)備工作

第一步:創(chuàng)建java的項(xiàng)目(注意,是module) employee_v1

第二步:添加web項(xiàng)目支持

第三步:引入相關(guān)jar包,放入lib下

第四步:定義項(xiàng)目的源碼組織結(jié)構(gòu)

com.employee.util

com.employee.vo

com.employee.dao

com.employee.dao.impl

com.employee.web

com.employee.test

第五步:編寫DruidUtil連接池工具類

第六步:編寫emp表的實(shí)體類Employee類型

第七步:編寫emp表的Dao接口:EmployeeDao

public interface EmpDao {

void addEmp(Emp emp);

void delEmpById(int id);

void modEmp(Emp emp);

Emp findById(int id);

ArrayList findAll();

ArrayList findByPage(int page,int pageSize);

}

第八步:編寫Dao接口的實(shí)現(xiàn)類:EmployeeDaoImpl

3.3.1 員工列表界面的實(shí)現(xiàn)

請(qǐng)求地址: https://localhost:8088/employee_v1/findAll

1)編寫員工列表的Servlet組件: FindAllServlet

2)編寫web.xml

3)啟動(dòng)tomcat,進(jìn)行測(cè)試。

3.3.2 添加員工的功能實(shí)現(xiàn)

1)在web目錄下,編寫一個(gè)addEmp.html

添加員工信息頁(yè)面

員工編號(hào):

員工姓名:

員工職位:

領(lǐng)導(dǎo)編號(hào):

入職日期:

員工工資:

員工獎(jiǎng)金:

部門編號(hào):

2)編寫添加員工的組件AddEmpServlet

3)修改web.xml,新添加

4)重新部署tomcat,進(jìn)行測(cè)試

- 先訪問添加員工的HTMl頁(yè)面。https://localhost:8088/employee_v1/addEmp.html

- 然后添加數(shù)據(jù),點(diǎn)擊提交

3.3.3 刪除員工的功能實(shí)現(xiàn)

1)修改員工列表界面:添加刪除按鈕

2)修改web.xml,新添加一對(duì)配置信息

3)創(chuàng)建對(duì)應(yīng)的組件 DelEmpServlet

4)部署tomcat,進(jìn)行測(cè)試

3.3.4 修改員工的功能實(shí)現(xiàn)

邏輯應(yīng)該經(jīng)過一個(gè)查詢組件,進(jìn)行顯示該員工原有的信息,然后在該頁(yè)面中,進(jìn)行修改部分值,最后點(diǎn)擊提交,保存到數(shù)據(jù)庫(kù)。

第一部分:編寫跳轉(zhuǎn)到修改頁(yè)面的邏輯。

1)修改員工列表界面:添加去修改按鈕

2)編寫web.xml,新添加一對(duì)配置

2)編寫ToUpdateEmp組件:獲取瀏覽器傳輸過來的員工id,從數(shù)據(jù)庫(kù)中查詢出來,顯示到一個(gè)form表單中,在瀏覽器中顯示

3)啟動(dòng)tomcat,去測(cè)試

第二部分:編寫在修改頁(yè)面上修改信息,點(diǎn)擊提交的邏輯

4)編寫web.xml,新添加一對(duì)配置

5)編寫對(duì)應(yīng)的UpdateEmp組件

6)啟動(dòng)tomcat,去測(cè)試

3.4 處理請(qǐng)求資源路徑

3.4.1 什么是請(qǐng)求資源路徑

在瀏覽器地址欄中輸入的地址格式如下:

https://ip:port/appName/xxx.html?..... addEmp.html

http://localhost:8088/day44_servlet/findAll findAllServlet

https://ip:port/虛擬資源/具體資源

解析:

ip: 服務(wù)器所在IP地址

port: 服務(wù)器的端口號(hào)

appName: 要訪問的項(xiàng)目名稱

/appName/xxx.html?..... 就是請(qǐng)求資源路徑,也就是getRequestURI()方法的返回值。

3.4.2 處理請(qǐng)求資源路徑的過程

當(dāng)瀏覽器地址欄上輸入https://ip:port/appName/xxx.html時(shí)

瀏覽器依據(jù)ip和port,與servlet容器建立連接,然后將后面的請(qǐng)求資源路徑發(fā)送給servlet容器 servlet容器依據(jù)應(yīng)用名/appName找到應(yīng)用所在的文件夾,容器會(huì)默認(rèn)請(qǐng)求的是一個(gè)servlet。 開始查找web.xml文件中的所有的servlet配置 ,查看是否有匹配的請(qǐng)求資源路徑,如果有,就定位到對(duì)應(yīng)的servlet組件

匹配方式以下有三種

1)精確匹配

通過將請(qǐng)求資源路徑中的具體資源名稱與web.xml文件中的url-pattern進(jìn)行對(duì)比,嚴(yán)格匹配相等后找到對(duì)應(yīng)資源并執(zhí)行。 如

/abc.html

此時(shí),盡管應(yīng)用中有abc.html這個(gè)具體的頁(yè)面,也會(huì)去執(zhí)行該url-pattern對(duì)應(yīng)的servlet組件,而不是返回這個(gè)具體的abc.html

2)通配符匹配

使用“*”號(hào)來匹配0個(gè)或者多個(gè)字符,如下寫法

/*

代表輸入任何不同的url地址都將匹配成功,比如

http://ip:port/appName/abc.html

http://ip:port/appName/abc/def/ghi 這些地址都會(huì)匹配成功

3)后綴匹配

不能使用斜杠開頭,使用*. 開頭的任意多個(gè)字符,如

*.do

會(huì)匹配以.do結(jié)尾的請(qǐng)求,以下的地址都能匹配成功

http://ip:port/appName/abc.do

http://ip:port/appName/abc/def/gh/abc.do

以什么結(jié)尾,自行決定,有意義即可。比如

*.school

*.company

4)無匹配的Servlet的處理

如果上述三者匹配都沒有匹配成功時(shí),容器就會(huì)查找相應(yīng)的文件

查找到對(duì)應(yīng)的文件,則返回 找不到對(duì)應(yīng)的文件,返回404

5)三者的優(yōu)先級(jí)

精確匹配> 通配符匹配 > 后綴匹配

6)三種匹配方式的共存問題:

在web.xml文件中可以有精確匹配,也可以有通配符匹配

在web.xml文件中可以有精確匹配,也可以有后綴匹配

在web.xml文件中通配符匹配和后綴匹配可以共存的,但是通配符已經(jīng)可以攔截所有的后綴匹配了,因此后綴匹配無效。所以寫與不寫都一樣了。

3.4.3 Servlet合并

一般情況下,Servlet的主要作用是充當(dāng)控制器的角色,即接受請(qǐng)求后,分發(fā)給不同的資源,這時(shí)Servlet只需要有一個(gè)就可以完成分發(fā)的過程,所以需要將Servlet合并。

實(shí)現(xiàn)合并的步驟如下:

第一步:使用后綴匹配模式,修改web.xml文件

將配置的多個(gè)相關(guān)的Servlet節(jié)點(diǎn)刪除 保留一對(duì)servlet、servlet-mapping 修改url-pattern節(jié)點(diǎn)的內(nèi)容為: *.emp

第二步:獲取請(qǐng)求資源路徑,分析具體請(qǐng)求資源后,依據(jù)分析結(jié)果調(diào)用不同的分支處理代碼

調(diào)用request.getRequestURI()方法獲取請(qǐng)求資源路徑 分析對(duì)應(yīng)資源后分發(fā)

String uri = request.getRequestURI();

if(uri.contains("/appName/findAll.emp")){

//......

}else if(uri.contains("/appName/addEmp.emp")){

//....

}else if(...){

//....

}

3.5 員工管理系統(tǒng)v2

1)創(chuàng)建module名 employee_v2

2)添加web支持,即 add framework support

3)創(chuàng)建lib文件夾,將jar拷貝過來

4))將com包拷貝到新項(xiàng)目下、以及druid.properties拷貝過來

5))將web下的addEmp.html拷貝過來

6)修改web.xml

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"

version="4.0">

web

com.shuilidianli.employee.web.ActionServlet

web

*.emp

7)將五個(gè)Servlet組件合成一個(gè)ActionServlet

小貼士:

修改所有請(qǐng)求資源路徑位置處的內(nèi)容。添加.emp

1: addEmp.html--->action="addEmp.emp"

2: 修改和刪除按鈕處的a鏈接,要添加.action

3: 三處重定向也要改

4: 修改頁(yè)面的action的值也要改

測(cè)試:

localhost:8088/employee_v2/listEmp.action

四 狀態(tài)管理

建議,建議,強(qiáng)烈建議

在講這個(gè)章節(jié)前,建議先講第五章節(jié)的第一小節(jié):5.1 servlet注解。 方便編寫代碼。畢竟前面的內(nèi)容已經(jīng)熟悉了web.xml的配置了。

4.1 狀態(tài)管理概述

4.1.1 為什么需要狀態(tài)管理

Web應(yīng)用程序使用的是HTTP協(xié)議進(jìn)行通信,而HTTP協(xié)議是“無狀態(tài)”協(xié)議,即服務(wù)器一旦響應(yīng)完客戶的請(qǐng)求后,就斷開連接,而同一個(gè)客戶的下一次請(qǐng)求將重新建立網(wǎng)絡(luò)連接。 說白點(diǎn),就是HTTP協(xié)議只能用于傳輸數(shù)據(jù),不記錄狀態(tài)(就是不記錄時(shí)誰發(fā)送的請(qǐng)求)

服務(wù)器端有時(shí)需要判斷是否為同一個(gè)客戶發(fā)送的請(qǐng)求。比如客戶的多次選購(gòu)商品。因此有必要跟蹤同一個(gè)客戶發(fā)送的多次請(qǐng)求。

不然會(huì)出現(xiàn)的情況: 如果不跟蹤,那么多個(gè)客戶添加的商品可能在同一個(gè)購(gòu)物車?yán)?,某一個(gè)客戶添加的商品可以在多個(gè)購(gòu)物車?yán)铩?/p>

4.1.2 什么是狀態(tài)管理

有的時(shí)候,需要將瀏覽器與服務(wù)器之間的多次交互(請(qǐng)求和響應(yīng))看成一個(gè)整體(同一個(gè)用戶的多次請(qǐng)求),并將多次交互時(shí)所涉及的數(shù)據(jù)(即狀態(tài))保存下來,提供給后續(xù)的交互進(jìn)行數(shù)據(jù)的管理即狀態(tài)管理。

狀態(tài)就是數(shù)據(jù) 管理指的是在這個(gè)多次交互的過程中對(duì)數(shù)據(jù)的存儲(chǔ)、修改、刪除。

生活中很多與狀態(tài)管理類似的案例。如洗車卡記錄洗車次數(shù)就是很典型的狀態(tài)管理。

洗車卡可以是一張記錄簡(jiǎn)單次數(shù)的標(biāo)示,車主每次攜帶卡片洗車后由商家修改,車主即可帶走這張記錄數(shù)據(jù)的卡片,商家不會(huì)保存任何數(shù)據(jù),客戶自己負(fù)責(zé)攜帶需要維護(hù)的數(shù)據(jù)。

還有一種處理方式就是商家只給客戶一個(gè)卡號(hào),每次客戶來洗車時(shí)自己不會(huì)記錄洗車次數(shù),只要報(bào)上卡號(hào),商家就會(huì)從系統(tǒng)中找到與卡號(hào)對(duì)應(yīng)的數(shù)據(jù),修改后仍然是商家保存,客戶帶走的只是一個(gè)卡號(hào)這個(gè)標(biāo)示。

以上兩種模式都能實(shí)現(xiàn)洗車次數(shù)的記錄,也就是數(shù)據(jù)的管理,只是各有利弊,程序中的狀態(tài)管理與這個(gè)案例都采用了同樣的處理原理。

name:用于區(qū)分不同Cookie的名字 value:Cookie的值

案例演示:

1. 編寫一個(gè)Servlet,實(shí)現(xiàn)將用戶名及區(qū)域兩個(gè)信息以Cookie的形式保存的功能

2. 程序運(yùn)行后,通過查看瀏覽器的輔助功能確認(rèn)兩個(gè)Cookie是否保存成功

在瀏覽器上查看Cookie信息: 右鍵檢查或者F12

4.2.3 如何查詢Cookie

當(dāng)客戶端向服務(wù)器發(fā)出請(qǐng)求時(shí),服務(wù)器端可以嘗試著從請(qǐng)求數(shù)據(jù)包的消息頭中獲取是否攜帶了Cookie信息。實(shí)現(xiàn)這一功能的代碼如下:

Cookie[] request.getCookies();

注意:如果沒有Cookie信息, 返回null.

由于客戶端是可以存放多個(gè)Cookie的,所以request提供的獲取Cookie的方法的返回值是Cookie數(shù)組,如果想進(jìn)一步獲取某一個(gè)Cookie信息可以通過遍歷數(shù)組,分別使用相應(yīng)的getXXX方法來獲取每一個(gè)Cookie的name和value。

獲取一個(gè)Cookie對(duì)象的名稱或值

String getName();

String getValue();

4.2.4 如何修改Cookie

所謂Cookie的修改,本質(zhì)是獲取到要變更值的Cookie,通過setValue方法將新的數(shù)據(jù)存入到cookie中,然后由response響應(yīng)對(duì)象發(fā)回到客戶端,對(duì)原有舊值覆蓋后即實(shí)現(xiàn)了修改。

主要實(shí)現(xiàn)代碼:

Cookie[] cookies = request.getCookies();

if(cookies!=null){

for(Cookie c : cookies){

String cookieName = c.getName();

if(name.equals(“uname”)){

c.setValue(“Mark”);

}

}

其中response.addCookie(c)是非常重要的語句,如果沒有這一行代碼,那么就算是使用setValue方法修改了Cookie的值,但是不發(fā)回到客戶端的話,也不會(huì)實(shí)現(xiàn)數(shù)值的改變。所以只要見到response.addCookie這行代碼,即服務(wù)器端發(fā)回了帶有Set-Cookie消息頭的信息。

4.2.5 cookie的過期時(shí)間

默認(rèn)情況下,cookie保存到瀏覽器端的內(nèi)存中,只要不關(guān)閉瀏覽器,cookie就一直在。只要瀏覽器已關(guān)閉,就消失。 如果想要在關(guān)閉瀏覽器后,還想要將cookie保存一段時(shí)間,就可以通過設(shè)置cookie過期時(shí)間來達(dá)到目的。

設(shè)置Cookie的過期時(shí)間使用如下代碼:

void setMaxAge(int seconds);

該方法是Cookie提供的實(shí)例方法。參數(shù)seconds的單位為秒,但精度不是很高。

seconds > 0 :代表Cookie保存在硬盤上的時(shí)長(zhǎng)

seconds = 0 : 代表Cookie的生命時(shí)長(zhǎng)為現(xiàn)在,而這一刻稍縱即逝,所以馬上Cookie就等同于過了生存時(shí)間,所以會(huì)被立即刪除。這也是刪除Cookie的實(shí)現(xiàn)方式。

seconds < 0 :缺省值,瀏覽器會(huì)將Cookie保存在內(nèi)存中。

以下代碼實(shí)現(xiàn)了Cookie保存在硬盤上40秒:

import java.io.IOException;

import java.io.PrintWriter;

import java.net.URLEncoder;

import javax.servlet.*;

import javax.servlet.*;

public class AddCookieServlet extends HttpServlet {

public void service(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException {

response.setContentType(

"text/html;charset=utf-8");

PrintWriter out = response.getWriter();

//創(chuàng)建cookie

Cookie c = new Cookie("username","Lisa");

Cookie c2 = new Cookie("city","NewYork");

response.addCookie(c);

response.addCookie(c2);

out.close();

}

}

4.2.6 cookie的路徑問題

1)客戶端如何保存cookie的路徑

客戶端存儲(chǔ)Cookie之后,并不是針對(duì)同一個(gè)應(yīng)用訪問任何資源時(shí)都自動(dòng)發(fā)送Cookie到服務(wù)器端,而是會(huì)進(jìn)行路徑的判斷。只有符合路徑規(guī)范的請(qǐng)求才會(huì)發(fā)送Cookie到服務(wù)器端。

客戶端在接受Cookie時(shí)會(huì)為該Cookie記錄一個(gè)默認(rèn)路徑,這個(gè)路徑記錄的是添加這個(gè)Cookie的Web組件的路徑。

如,當(dāng)客戶端向 http://localhost:8080/test/file/addCookie.jsp發(fā)送請(qǐng)求時(shí)創(chuàng)建了cookie,那么該cookie的路徑就是 /test/file.

2)客戶端什么時(shí)候發(fā)送Cookie

只有當(dāng)訪問的地址是Cookie的路徑或者其子路徑時(shí),瀏覽器才發(fā)送Cookie到服務(wù)器端。

如,Cookie的路徑是 /test/file,那么如果訪問的是 /test/file/a.jsp 或者 /test/file/b/c.jsp時(shí),都會(huì)發(fā)送Cookie。

如果訪問的是 /test/d.jsp,則瀏覽器不會(huì)發(fā)送Cookie。

3) 如何設(shè)置Cookie的路徑

設(shè)置Cookie的路徑可以使用Cookie的API方法,setPath(String uri);

如以下代碼就實(shí)現(xiàn)了設(shè)置Cookie的路徑為應(yīng)用的頂級(jí)目錄,這樣所有資源路徑要么與此路徑相等,要么是子路徑,從而實(shí)現(xiàn)了客戶端發(fā)送任何請(qǐng)求時(shí)都會(huì)發(fā)送Cookie。

Cookie c = new Cookie(“uname”,“jack”);

c.setPath(“/appName”);

response.addCookie(c);

cookie.setPath("/appName/account")

appName/acount/add

appName/acount/del

appName/acount/update

appName/manager/add

appName/manager/del

appName/manager/update

appName/program/add

appName/program/del

appName/program/update

1.4.5 cookie的限制

--cookie可以被用戶禁止

--cookie會(huì)將狀態(tài)數(shù)據(jù)保存到瀏覽器端,不安全,

--cookie只能保存少量數(shù)據(jù),大約在4kb左右

--cookie的個(gè)數(shù)有限制

--cookie只能保存字符串

4.3 Session狀態(tài)管理

4.3.1 什么是session

見名知意,是會(huì)話的意思。當(dāng)瀏覽器訪問服務(wù)器時(shí),服務(wù)器會(huì)為每一個(gè)瀏覽器在服務(wù)器端的內(nèi)存中分配空間,單獨(dú)維護(hù)一個(gè)Session對(duì)象,每個(gè)session對(duì)象都有一個(gè)唯一標(biāo)識(shí)符,叫sessionId。服務(wù)器會(huì)將sessionId以cookie的方式發(fā)給瀏覽器,瀏覽器會(huì)保存sessionid.

當(dāng)瀏覽器再次向服務(wù)器發(fā)送請(qǐng)求時(shí),會(huì)帶上sessionId。服務(wù)端收到sessionId后,會(huì)依據(jù)sessionId查找是否有對(duì)應(yīng)的session對(duì)象。

flag = true:先從請(qǐng)求中找找看是否有SID,沒有會(huì)創(chuàng)建新Session對(duì)象,有SID會(huì)查找與編號(hào)對(duì)應(yīng)的對(duì)象,找到匹配的對(duì)象則返回,找不到SID對(duì)應(yīng)的對(duì)象時(shí)則會(huì)創(chuàng)建新Session對(duì)象。 總結(jié):填寫true就一定會(huì)得到一個(gè)Session對(duì)象。要么返回找到的,要么返回新創(chuàng)建的 flag = false:不存在SID以及按照SID找不到Session對(duì)象時(shí)都會(huì)返回null,只有根據(jù)SID找到對(duì)應(yīng)的對(duì)象時(shí)會(huì)返回具體的Session對(duì)象。 總結(jié):填寫false時(shí),不會(huì)創(chuàng)建新的Session. 要么返回找到的,要么返回null。

如何想要設(shè)置flag為true, 可以使用以下重載方法, 相當(dāng)于設(shè)置了flag為true. 提供該方法主要是為了書寫代碼時(shí)更方便,大多數(shù)情況下還是希望能夠返回一個(gè)Session對(duì)象的。

HttpSession s = request.getSession();

4.3.3 Session的常用API

Session對(duì)象,也是采用name-value對(duì)的形式來區(qū)分每一組數(shù)據(jù)。

1)綁定數(shù)據(jù)的代碼:

void session.setAttribute(String name,Object obj)

Session對(duì)象可以保存更復(fù)雜的對(duì)象類型數(shù)據(jù)了,不像Cookie只能保存字符串。

2)獲取綁定數(shù)據(jù)的代碼:

Object obj = session.getAttribute(String name)

3)移除綁定數(shù)據(jù)的代碼

void session.removeAttribute(String name)

4)刪除session對(duì)象

session.invalidate(): 立即失效

該方法會(huì)使得服務(wù)器端與該客戶端對(duì)應(yīng)的Session對(duì)象不再被Session容器管理,進(jìn)入到垃圾回收的狀態(tài)。對(duì)于這種立即刪除Session對(duì)象的操作主要應(yīng)用于不再需要身份識(shí)別的情況下,如登出操作。

4.3.4 Session的有效時(shí)間(超時(shí)時(shí)間)

Session會(huì)以對(duì)象的形式占用服務(wù)器端的內(nèi)存,過多的以及長(zhǎng)期的消耗內(nèi)存會(huì)降低服務(wù)器端的運(yùn)行效率,所以Session對(duì)象存在于內(nèi)存中時(shí)會(huì)有默認(rèn)的時(shí)間限制,一旦Session對(duì)象存在的時(shí)間超過了這個(gè)缺省的時(shí)間限制則認(rèn)為是Session超時(shí),Session會(huì)失效,不能再繼續(xù)訪問。

Web服務(wù)器缺省的超時(shí)時(shí)間設(shè)置一般是30分鐘。

如果用戶想要自定義session的時(shí)間,有如下兩種方式,

1)第一種:聲明式 (全局)

在web.xml中添加如下配置

30

使用聲明式來修改缺省時(shí)間,那么該應(yīng)用創(chuàng)建的所有Session對(duì)象的生命周期都會(huì)應(yīng)用這個(gè)規(guī)定的時(shí)間,單位為分鐘。

2)第二種:編程式 (局部)

在代碼中使用session的api進(jìn)行設(shè)置

session.setMaxInactiveInterval(int seconds) //單位是秒

4.3.5 session的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

安全(狀態(tài)數(shù)據(jù)保存到服務(wù)器端)

session綁定的數(shù)據(jù)類型更加豐富,cookie只能是字符串

session保存的數(shù)據(jù)量更大,cookie只能是4kb

缺點(diǎn):

session占服務(wù)器的內(nèi)存。

案例演示:登錄驗(yàn)證

需求:如果訪問的頁(yè)面沒有經(jīng)過登錄,那么需要立即跳轉(zhuǎn)到登錄頁(yè)面

4.4 員工管理系統(tǒng) v3

步驟1: 整合pom.xml

javax.servlet

javax.servlet-api

3.1.0

provided

mysql

mysql-connector-java

8.0.31

com.alibaba

druid

1.1.20

javax.servlet

jstl

1.2

taglibs

standard

1.1.2

步驟2: 將v3里的源碼src 全部拷貝到v4的src里

步驟3: 將v3里的web文件夾里的內(nèi)容全部拷貝到v4的web文件夾里面

步驟4: 測(cè)試是否好使。 添加tomcat, 修改虛擬項(xiàng)目名,配置項(xiàng)目構(gòu)建(project structure), 訪問如下地址

http://localhost:8088/employee_v4/listEmp.action

4.4.1 添加注冊(cè)功能

1)維護(hù)mysql的user表

use mydb;

create table if not exists user(

id int primary key auto_increment,

username varchar(10) not null,

realname varchar(10) not null,

password varchar(20) not null,

gender varchar(1) not null

) engine=InnoDB auto_increment=1 default charset=utf8;

delete from user;

insert into user values(null,'zhangsan','張大三','zs123456','m');

commit;

select * from user;

2)為user表創(chuàng)建實(shí)體類User, 定義UserDao接口,實(shí)現(xiàn)UserDaoImpl實(shí)現(xiàn)類

五 Servlet的特性

5.1 Servlet注解

5.1.1 注解簡(jiǎn)介

Servlet注解是?==Java Servlet 3.0版本==引入的一種特性,允許在Servlet類上使用注解來配置Servlet,而不需要傳統(tǒng)的web.xml配置文件。通過使用@WebServlet注解,可以指定Servlet的名稱、URL模式以及其他相關(guān)配置。

?Servlet注解的優(yōu)點(diǎn)?

?簡(jiǎn)化配置?:通過注解,可以避免在web.xml文件中進(jìn)行繁瑣的配置,減少代碼量,提高開發(fā)效率。 ?動(dòng)態(tài)配置?:注解允許在運(yùn)行時(shí)動(dòng)態(tài)地添加、修改或刪除Servlet的配置,提高了系統(tǒng)的靈活性。

Servlet注解的缺點(diǎn)

?兼容性問題?:雖然Servlet注解提供了很多便利,但在一些較舊的Java EE環(huán)境中可能不支持,需要額外的兼容性處理。 ?復(fù)雜性增加?:對(duì)于復(fù)雜的配置需求,可能需要結(jié)合web.xml文件使用,增加了配置的復(fù)雜性。

5.1.2 注解應(yīng)用

注解要寫在每個(gè)Servlet組件的類上面 格式:@WebServlet(…) 常用屬性:value和urlPatterns一般是必須的,但是二者不能共存,若同時(shí)指定,一般自動(dòng)忽略value。

屬性名類名屬性描述nameString指定servlet的name屬性,等價(jià)于,若沒有指定,則默認(rèn)是類的全限定名valueString[]等價(jià)于urlPatterns,兩者不能共存,只有一個(gè)值時(shí),可以省略{}urlPatternsString[]指定一組servlet的url的匹配模式,等價(jià)于loadOnStartupint指定servlet的加載順序,等價(jià)于initParamsWebinitParams[]指定一組初始化參數(shù),等價(jià)于asyncSupportedboolean聲明servlet是否支持異步操作模式,等價(jià)于displayNameStringservlet的顯示名,等價(jià)于descriptionStringservlet的描述信息,等價(jià)于

案例演示1:

@WebServlet(name = "MyServlet", //Servlet名

urlPatterns = "/serv02", //Servlet訪問的url

loadOnStartup = 1, //Servlet創(chuàng)建的時(shí)機(jī)

initParams = { //ServletConfig的相關(guān)配置

@WebInitParam(name="name", value="YWANG"),

@WebInitParam(name="pwd", value="123456")

}

)

案例演示2:

@WebServlet("/web01")

5.2 ServletContext的應(yīng)用

5.2.1 ServletContext的簡(jiǎn)介

ServletContext:Servlet上下文對(duì)象,它是一個(gè)接口。一個(gè)web工程,只有一個(gè)ServletContext對(duì)象實(shí)例(單例),同一個(gè)web應(yīng)用程序中,所有的Servlet組件共享同一個(gè)ServletContext對(duì)象。web服務(wù)器啟動(dòng)時(shí)創(chuàng)建,web服務(wù)器關(guān)閉時(shí)銷毀,也就是說,只要容器不關(guān)閉或者應(yīng)用不卸載,servlet上下文對(duì)象就一直存在。

ServletContext一般有以下四個(gè)用途:

1.獲取web.xml中配置的上下文參數(shù)context-param

2.獲取當(dāng)前的工程路徑(項(xiàng)目名稱),格式:/工程路徑

3.獲取工程部署后在服務(wù)器硬盤上的絕對(duì)路徑

4.像Map一樣存取數(shù)據(jù)

獲取ServletContext對(duì)象的方式

1. GenericServlet提供了getServletContext()方法。(推薦)

2. HttpServletRequest提供了getServletContext()方法。(推薦)

3. ServletConfig提供了getServletContext()方法。

4. HttpSession提供了getServletContext()方法。

5.2.1 案例演示:

全局參數(shù),在web.xml中配置

deptname

開發(fā)部門

可以有多個(gè)

package com.servlet.context;

import javax.servlet.ServletContext;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

/**

* ServletContext對(duì)象:

* 1. 在整個(gè)項(xiàng)目中是唯一的,只有一個(gè)。(單例)

* 2. 所有的Servlet組件(包括JSP)都可以拿到這個(gè)對(duì)象

* 3. 既然是唯一的,我們就可以使用該對(duì)象來存儲(chǔ)一個(gè)共享數(shù)據(jù)。 此時(shí):ServletContext對(duì)象也可以稱之為域?qū)ο?/p>

* 域:就是用來存儲(chǔ)數(shù)據(jù)的。

* 4. 也可以使用上下文對(duì)象,獲取全局變量context-param,以及項(xiàng)目名,以及項(xiàng)目在服務(wù)器硬盤上的絕對(duì)路徑

*/

@WebServlet(value = "/testServletContext")

public class ServletContextDemo extends HttpServlet {

@Override

protected void service(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {

// 獲取ServletContext對(duì)象

ServletContext sct1 = this.getServletContext();//從GenericServlet中繼承過來的

ServletContext sct2 = request.getServletContext(); //從請(qǐng)求對(duì)象上獲取

ServletContext sct3 = this.getServletConfig().getServletContext(); //從ServletConfig上獲取

ServletContext sct4 = request.getSession().getServletContext();

//判斷四個(gè)變量指向的是不是同一個(gè)對(duì)象

System.out.println(sct1 == sct2);

System.out.println(sct1 == sct3);

System.out.println(sct1 == sct4);

//獲取全局參數(shù): 全局參數(shù)在web.xml中配置

String deptname = sct3.getInitParameter("a");

System.out.println("deptname: " + deptname);

//獲取當(dāng)前項(xiàng)目的名稱

String contextPath = sct1.getContextPath();

String contextPath1 = request.getContextPath();//從請(qǐng)求對(duì)象身上也可以獲取到

System.out.println(contextPath+" "+contextPath1);

//獲取當(dāng)前項(xiàng)目在服務(wù)器端的硬盤上的絕對(duì)路徑

String realPath = sct3.getRealPath(""); // 傳入一個(gè)字符串 ,可以是空字符串,可以是斜杠

System.out.println(realPath);

}

}

5.3 過濾器接口

5.3.1 什么是過濾器

Servlet規(guī)范中的三大接口:==Servlet接口,F(xiàn)ilter接口、Listener接口。==

過濾器接口,是Servlet2.3版本以來,定義的一種小型的,可插拔的Web組件,可以用來攔截和處理Servlet容器的請(qǐng)求和響應(yīng)過程。以便查看,提取或以某種方式操作正在客戶端與服務(wù)器端之間交換的數(shù)據(jù)。

應(yīng)用場(chǎng)景如下:

1. 對(duì)請(qǐng)求的數(shù)據(jù)是否包含敏感詞進(jìn)行提前篩選過濾,沒有必要在下一層(業(yè)務(wù)層)進(jìn)行處理。

2. 用戶沒有進(jìn)行登錄,應(yīng)該跳往登錄頁(yè)面等操作

插拔的理解:

方便增加或減少某個(gè)功能模塊,需要添加過濾就多部署一個(gè)class修改一下web.xml文件,需要減少某個(gè)功能只要?jiǎng)h除web.xml中對(duì)應(yīng)的聲明即可。

方便修改處理邏輯。當(dāng)把一些功能獨(dú)立到某個(gè)模塊時(shí),如果邏輯變了,只修改這一個(gè)文件并更新就可以實(shí)現(xiàn)功能的改變,而不用修改每一個(gè)使用這個(gè)插件的組件。

5.3.2 如何編寫過濾器

編寫過濾器遵循下列步驟:

編寫一個(gè)實(shí)現(xiàn)了Filter接口的類 實(shí)現(xiàn)Filter接口的三個(gè)方法,過濾邏輯在doFilter方法中實(shí)現(xiàn) 在Web程序中注冊(cè)過濾器 把過濾器和Web應(yīng)用一起打包部署

5.3.3 過濾器的執(zhí)行流程

單個(gè)過濾器的執(zhí)行流程:

1. 客戶端發(fā)來請(qǐng)求后,不會(huì)直接將請(qǐng)求送達(dá)Servlet,而是先走過濾器1的doFilter方法中的code1。

2. 當(dāng)遇到chain.doFilter()方法時(shí),就會(huì)調(diào)用Servlet組件的service()方法,執(zhí)行里面的邏輯代碼。

3. service()方法執(zhí)行結(jié)束后并不會(huì)立即將響應(yīng)返回給客戶端,而是回到過濾器1的doFilter()方法中code2部分,如果該部分有代碼就會(huì)執(zhí)行,執(zhí)行結(jié)束后才會(huì)將response對(duì)象返回給客戶端。

從流程中可以看到,過濾器不僅僅對(duì)Servlet的執(zhí)行前起到過濾作用,對(duì)于執(zhí)行后同樣有過濾效果。所以,過濾器是對(duì)request和response的檢查

多個(gè)過濾器的執(zhí)行流程:

過濾器1的doFilter的code1 ,然后 過濾器2的doFilter的code1 ,然后再試 service()方法 ,再然后是過濾器2的doFilter的code2 ,之后是 過濾器1的doFilter的code2 ,最后返回給客戶端

在這個(gè)動(dòng)作的傳遞過程中一定要寫 chain.doFilter()

多個(gè)過濾器的優(yōu)先級(jí)

在一個(gè)Web應(yīng)用中,可以有多個(gè)過濾器,它們的優(yōu)先級(jí)由位于web.xml文件中的聲明順序決定,具體是按照的順序來決定的。如下代碼所示,filter1和filter2都已經(jīng)注冊(cè),執(zhí)行順序是filter2 ,然后 filter1 。

filter1

filter2

filter2

/comment2

filter1

/comment1

5.3.4 過濾器的初始化參數(shù)

容器啟動(dòng)之后,會(huì)創(chuàng)建過濾器實(shí)例。通過init方法來完成過濾器的初始化。初始化時(shí)可以添加一些配置,提升動(dòng)態(tài)性。而這些參數(shù)通過在web.xml文件中的以name-value對(duì)的形式存在。

讀取這些name-value對(duì)需要使用FilterConfig對(duì)象,從web.xml文件到FilterConfig對(duì)象的過程由容器完成,并通過參數(shù)傳入到init方法之中,只需要設(shè)定一些成員對(duì)象保存數(shù)值就可以在doFilter方法中使用。

初始化參數(shù)配置方法如下:

filter1

web.CommentFilter1

illegalStr

xxx

filter1

/comment

讀取初始化參數(shù)使用如下代碼:

public class CommentFilter implements Filter{

FilterConfig config = null;

public void init(FilterConfig arg0) throws ServletException {

config = arg0;

}

public void doFilter(ServletRequest arg0,ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {

String illegalStr = config.getInitParameter("illegalStr");

// … …

}

public void destroy() {

// … …

}

}

5.3.5 案例演示:敏感詞過濾

CommentFilter1類

package com.shuilidianli.filter;

import javax.servlet.*;

import java.io.IOException;

public class CommentFilter1 implements Filter {

//添加全局變量FilterConfig

FilterConfig config = null;

@Override

public void init(FilterConfig filterConfig) throws ServletException {

//給全局變量config賦值

config = filterConfig;

}

@Override

public void doFilter(ServletRequest request,

ServletResponse response,

FilterChain chain) throws IOException, ServletException {

request.setCharacterEncoding("utf-8");

response.setContentType("text/html;charset=utf8");

//使用全局變量config獲取一些敏感詞

String word1 = config.getInitParameter("word1");

System.out.println("word1:"+word1);

//獲取評(píng)論內(nèi)容

String comment = request.getParameter("comment");

if(comment.contains(word1)){

//轉(zhuǎn)發(fā)到comment.jsp頁(yè)面進(jìn)行提醒

request.setAttribute("message","您輸入了敏感詞"+word1);

request.getRequestDispatcher("comment.jsp").forward(request,response);

}else{

//繼續(xù)向下執(zhí)行

chain.doFilter(request,response);

}

}

@Override

public void destroy() {

}

}

CommentFilter2類

package com.shuilidianli.filter;

import javax.servlet.*;

import java.io.IOException;

public class CommentFilter2 implements Filter {

//添加全局變量FilterConfig

FilterConfig config = null;

@Override

public void init(FilterConfig filterConfig) throws ServletException {

//給全局變量config賦值

config = filterConfig;

}

@Override

public void doFilter(ServletRequest request,

ServletResponse response,

FilterChain chain) throws IOException, ServletException {

request.setCharacterEncoding("utf-8");

response.setContentType("text/html;charset=utf8");

//使用全局變量config獲取一些敏感詞

String word2 = config.getInitParameter("word2");

//獲取評(píng)論內(nèi)容

String comment = request.getParameter("comment");

if(comment.contains(word2)){

//轉(zhuǎn)發(fā)到comment.jsp頁(yè)面進(jìn)行提醒

request.setAttribute("message","您輸入了敏感詞"+word2);

request.getRequestDispatcher("comment.jsp").forward(request,response);

}else{

//繼續(xù)向下執(zhí)行

chain.doFilter(request,response);

}

}

@Override

public void destroy() {

}

}

CommentServlet類

package com.shuilidianli.web;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.io.PrintWriter;

@WebServlet("/toComment")

public class CommentServlet extends HttpServlet {

@Override

protected void service(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

//處理中文亂碼問題

request.setCharacterEncoding("utf-8");

response.setContentType("text/html;charset=utf8");

String comment = request.getParameter("comment");

PrintWriter pw = response.getWriter();

pw.println("評(píng)論通過,您的評(píng)論內(nèi)容如下:
");

pw.println("

"+comment+"

");

pw.close();

}

}

web.xml

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"

version="4.0">

f1

com.shuilidianli.filter.CommentFilter1

word1

尼瑪

f2

com.shuilidianli.filter.CommentFilter2

word2

qusi

f2

/toComment

f1

/toComment

employee_v3:

增刪改查:

登錄注冊(cè):

驗(yàn)證碼在登錄或者注冊(cè)頁(yè)面其中一個(gè)即可

過濾器:驗(yàn)證是否登錄過,如果沒有登錄過,重定向到登錄頁(yè)面

5.4 監(jiān)聽器

5.4.1 監(jiān)聽器的概念

Servlet規(guī)范中的三大接口,除了Servlet接口,F(xiàn)ilter接口,剩下的就是==Listener接口==了。

監(jiān)聽器采用了設(shè)計(jì)模式中的觀察者模式,監(jiān)聽器本身是觀察者,被監(jiān)聽的對(duì)象是被觀察者。當(dāng)被監(jiān)聽對(duì)象的狀態(tài)發(fā)生改變時(shí),就會(huì)通知觀察者,也就是監(jiān)聽器,監(jiān)聽器在收到通知后可以做出相應(yīng)的處理邏輯。

Servlet監(jiān)聽器是Servlet規(guī)范中定義的一種特殊類,用于監(jiān)聽ServletContext、HttpSession和ServletRequest等域?qū)ο蟮膭?chuàng)建與銷毀事件,以及監(jiān)聽這些域?qū)ο笾袑傩园l(fā)生修改的事件。

5.4.2 監(jiān)聽器的分類

在Servlet2.5版本以來,定義了以下三類8種監(jiān)聽器:

第一大類:監(jiān)聽 Session、request、context 這三個(gè)==對(duì)象的創(chuàng)建與銷毀==的:

HttpSessionListener ServletContextListener ServletRequestListener

第二大類:監(jiān)聽==對(duì)象屬性==變化的:

HttpSessionAttributeLister ServletContextAttributeListener ServletRequestAttributeListener

第三類:監(jiān)聽Session 內(nèi)的對(duì)象的:

HttpSessionBindingListener HttpSessionActivationListener。 與上面六類不同,這兩類 Listener 監(jiān)聽的是Session 內(nèi)的對(duì)象,而非 Session 本身,不需要在 web.xml中配置。

5.4.3 如何編寫監(jiān)聽器

步驟1:編寫一個(gè)java類,依據(jù)監(jiān)聽的事件類型選擇實(shí)現(xiàn)相應(yīng)的監(jiān)聽器接口,如,要監(jiān)聽Sessioin對(duì)象的創(chuàng)建和銷毀,要實(shí)現(xiàn)HttpSessionListener

步驟2:在監(jiān)聽器接口方法中,實(shí)現(xiàn)相應(yīng)的監(jiān)聽處理邏輯

步驟3:在web.xml文件中注冊(cè)該監(jiān)聽器

public class CouListener implements HttpSessionListener{

public void sessionCreate(HttpSessionEvent arg0){

//..

HttpSession session = arg0.getSession();

//獲取sesssion或者上下文對(duì)象的

ServletContext ctx = session.getServletContext();

//..

}

}

在web.xml文件中,增加以下節(jié)點(diǎn)

web.CouListener

5.4.4 應(yīng)用場(chǎng)景

由于ServletRequest,HttpSession,ServletContext對(duì)象都是容器創(chuàng)建的,通過對(duì)這些對(duì)象注冊(cè)監(jiān)聽器,就可以得知何時(shí)創(chuàng)建了。比如

1)在contextDestroyed方法中對(duì)應(yīng)用級(jí)別的資源進(jìn)行釋放

2)統(tǒng)計(jì)在線人數(shù)可以通過HttpSessionListener監(jiān)聽器的sessionCreated方法監(jiān)聽session的創(chuàng)建動(dòng)作。

案例演示:統(tǒng)計(jì)在線人數(shù)

統(tǒng)計(jì)在線人數(shù)(基于Session的統(tǒng)計(jì))

監(jiān)聽Session的創(chuàng)建及銷毀事件,修改在線人數(shù),并將這個(gè)數(shù)據(jù)輸出顯示。

(一)單態(tài)登錄:一個(gè)賬號(hào)只能在一臺(tái)機(jī)器上登錄。

package servlet.listener.singleton;

import java.util.HashMap;

import java.util.Map;

import javax.servlet.http.HttpSession;

import javax.servlet.http.HttpSessionAttributeListener;

import javax.servlet.http.HttpSessionBindingEvent;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

/**

*

* LoginSessionListener.java

*

* @title 實(shí)現(xiàn)單態(tài)登錄的監(jiān)聽器

* @description

* @author SAM-SHO

* @Date 2014-12-10

*/

public class LoginSessionListener implements HttpSessionAttributeListener {

Log log = LogFactory.getLog(this.getClass());

Map map = new HashMap();

public void attributeAdded(HttpSessionBindingEvent event) {

String name = event.getName();

// 登錄

if (name.equals("personInfo")) {

PersonInfo personInfo = (PersonInfo) event.getValue();

if (map.get(personInfo.getAccount()) != null) {

// map 中有記錄,表明該帳號(hào)在其他機(jī)器上登錄過,將以前的登錄失效

HttpSession session = map.get(personInfo.getAccount());

PersonInfo oldPersonInfo = (PersonInfo) session.getAttribute("personInfo");//map已經(jīng)存在的舊的信息

log.info("帳號(hào)" + oldPersonInfo.getAccount() + "在" + oldPersonInfo.getIp() + "已經(jīng)登錄,該登錄將被迫下線。");

session.removeAttribute("personInfo");

session.setAttribute("msg", "您的帳號(hào)已經(jīng)在其他機(jī)器上登錄,您被迫下線。");

}

// 將session以用戶名為索引,放入map中

map.put(personInfo.getAccount(), event.getSession());

log.info("帳號(hào)" + personInfo.getAccount() + "在" + personInfo.getIp() + "登錄。");

}

}

public void attributeRemoved(HttpSessionBindingEvent event) {

String name = event.getName();

// 注銷

if (name.equals("personInfo")) {

// 將該session從map中移除

PersonInfo personInfo = (PersonInfo) event.getValue();

map.remove(personInfo.getAccount());

log.info("帳號(hào)" + personInfo.getAccount() + "注銷。");

}

}

public void attributeReplaced(HttpSessionBindingEvent event) {

String name = event.getName();

// 沒有注銷的情況下,用另一個(gè)帳號(hào)登錄

if (name.equals("personInfo")) {

// 移除舊的的登錄信息

PersonInfo oldPersonInfo = (PersonInfo) event.getValue();

map.remove(oldPersonInfo.getAccount());

// 新的登錄信息

PersonInfo personInfo = (PersonInfo) event.getSession().getAttribute("personInfo");

// 也要檢查新登錄的帳號(hào)是否在別的機(jī)器上登錄過

if (map.get(personInfo.getAccount()) != null) {

// map 中有記錄,表明該帳號(hào)在其他機(jī)器上登錄過,將以前的登錄失效

HttpSession session = map.get(personInfo.getAccount());

session.removeAttribute("personInfo");

session.setAttribute("msg", "您的帳號(hào)已經(jīng)在其他機(jī)器上登錄,您被迫下線。");

}

map.put("personInfo", event.getSession());

}

}

}

package servlet.listener.singleton;

import java.io.Serializable;

import java.util.Date;

/**

*

* PersonInfo.java

*

* @title

* @description

* @author SAM-SHO

* @Date 2014-12-10

*/

public class PersonInfo implements Serializable {

private static final long serialVersionUID = 4063725584941336123L;

// 帳號(hào)

private String account;

// 登錄IP地址

private String ip;

// 登錄時(shí)間

private Date loginDate;

public String getAccount() {

return account;

}

public void setAccount(String account) {

this.account = account;

}

public String getIp() {

return ip;

}

public void setIp(String ip) {

this.ip = ip;

}

public Date getLoginDate() {

return loginDate;

}

public void setLoginDate(Date loginDate) {

this.loginDate = loginDate;

}

@Override

public int hashCode() {

final int prime = 31;

int result = 1;

result = prime * result + ((account == null) ? 0 : account.hashCode());

result = prime * result + ((ip == null) ? 0 : ip.hashCode());

return result;

}

@Override

public boolean equals(Object obj) {

if (this == obj)

return true;

if (obj == null)

return false;

if (getClass() != obj.getClass())

return false;

PersonInfo other = (PersonInfo) obj;

if (account == null) {

if (other.account != null)

return false;

} else if (!account.equals(other.account))

return false;

if (ip == null) {

if (other.ip != null)

return false;

} else if (!ip.equals(other.ip))

return false;

return true;

}

}

servlet.listener.singleton.LoginSessionListener

(二)顯示在線人數(shù):會(huì)需要3個(gè)監(jiān)聽器

1、ContextListener:獲取服務(wù)啟動(dòng)的時(shí)間等。

2、RequestListener:獲取客戶端的IP、訪問地址,訪問次數(shù)等。

3、SessionListener:需要監(jiān)聽 Session 的創(chuàng)建與屬性變化。

4、代碼如下:

package com.helloweenvsfei.listener;

import java.util.Date;

import javax.servlet.ServletContextEvent;

import javax.servlet.ServletContextListener;

import com.helloweenvsfei.util.ApplicationConstants;

public class MyContextListener implements ServletContextListener {

public void contextInitialized(ServletContextEvent event) {

// 啟動(dòng)時(shí),記錄服務(wù)器啟動(dòng)時(shí)間

ApplicationConstants.START_DATE = new Date();

}

public void contextDestroyed(ServletContextEvent event) {

// 關(guān)閉時(shí),將結(jié)果清除。也可以將結(jié)果保存到硬盤上。

ApplicationConstants.START_DATE = null;

ApplicationConstants.MAX_ONLINE_COUNT_DATE = null;

}

}

package com.helloweenvsfei.listener;

import javax.servlet.ServletRequestEvent;

import javax.servlet.ServletRequestListener;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;

public class MyRequestListener implements ServletRequestListener {

public void requestDestroyed(ServletRequestEvent event) {

}

public void requestInitialized(ServletRequestEvent event) {

HttpServletRequest request = (HttpServletRequest) event

.getServletRequest();

HttpSession session = request.getSession(true);

// 記錄IP地址

session.setAttribute("ip", request.getRemoteAddr());

// 記錄訪問次數(shù),只記錄訪問 .html, .do, .jsp, .action 的累計(jì)次數(shù)

String uri = request.getRequestURI();

String[] suffix = { ".html", ".do", ".jsp", ".action" };

for (int i=0; i

if (uri.endsWith(suffix[i])) {

break;

}

if(i == suffix.length-1)

return;

}

Integer activeTimes = (Integer) session.getAttribute("activeTimes");

if (activeTimes == null) {

activeTimes = 0;

}

session.setAttribute("activeTimes", activeTimes + 1);

}

}

package com.helloweenvsfei.listener;

import java.util.Date;

import javax.servlet.http.HttpSession;

import javax.servlet.http.HttpSessionAttributeListener;

import javax.servlet.http.HttpSessionBindingEvent;

import javax.servlet.http.HttpSessionEvent;

import javax.servlet.http.HttpSessionListener;

import com.helloweenvsfei.util.ApplicationConstants;

public class MySessionListener implements HttpSessionListener,

HttpSessionAttributeListener {

public void sessionCreated(HttpSessionEvent sessionEvent) {

HttpSession session = sessionEvent.getSession();

// 將 session 放入 map

ApplicationConstants.SESSION_MAP.put(session.getId(), session);

// 總訪問人數(shù)++

ApplicationConstants.TOTAL_HISTORY_COUNT++;

// 如果當(dāng)前在線人數(shù)超過歷史記錄,則更新最大在線人數(shù),并記錄時(shí)間

if (ApplicationConstants.SESSION_MAP.size() > ApplicationConstants.MAX_ONLINE_COUNT) {

ApplicationConstants.MAX_ONLINE_COUNT = ApplicationConstants.SESSION_MAP

.size();

ApplicationConstants.MAX_ONLINE_COUNT_DATE = new Date();

}

}

public void sessionDestroyed(HttpSessionEvent sessionEvent) {

HttpSession session = sessionEvent.getSession();

// 將session從map中移除

ApplicationConstants.SESSION_MAP.remove(session.getId());

}

public void attributeAdded(HttpSessionBindingEvent event) {

if (event.getName().equals("personInfo")) {

// 當(dāng)前登錄用戶數(shù)++

ApplicationConstants.CURRENT_LOGIN_COUNT++;

HttpSession session = event.getSession();

// 查找該帳號(hào)有沒有在其他機(jī)器上登錄

for (HttpSession sess : ApplicationConstants.SESSION_MAP.values()) {

// 如果該帳號(hào)已經(jīng)在其他機(jī)器上登錄,則以前的登錄失效

if (event.getValue().equals(sess.getAttribute("personInfo"))

&& session.getId() != sess.getId()) {

sess.invalidate();

}

}

}

}

public void attributeRemoved(HttpSessionBindingEvent event) {

// 注銷 當(dāng)前登錄用戶數(shù)--

if (event.getName().equals("personInfo")) {

ApplicationConstants.CURRENT_LOGIN_COUNT--;

}

}

public void attributeReplaced(HttpSessionBindingEvent event) {

// 重新登錄

if (event.getName().equals("personInfo")) {

HttpSession session = event.getSession();

for (HttpSession sess : ApplicationConstants.SESSION_MAP.values()) {

// 如果新帳號(hào)在其他機(jī)器上登錄過,則以前登錄失效

if (event.getValue().equals(sess.getAttribute("personInfo"))

&& session.getId() != sess.getId()) {

sess.invalidate();

}

}

}

}

}

然后在web.xml中配置這三個(gè)監(jiān)聽器即可

默認(rèn)鈍化的位置:

%CATALINA_BASE%\work\Catalina\localhost\項(xiàng)目名\下

柚子快報(bào)激活碼778899分享:Servlet

http://yzkb.51969.com/

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/2027342543.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄