servlet原理


1 B/S concept
B/S结构(Browser/Server结构)结构即浏览器和服务器结构。
它是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。

2 How to develop a WebApp.
1)WebApp的组成(符合JAVAEE规范).
2)例子.
firstWeb(webroot)
/WEB-INF/web.xml
/index.html
/student.html
3) 部署到应用服务器.
通过url访问:
http://localhost:8080/firstWeb/
or
http://127.0.0.1:8080/firstWeb/
思考:通过url访问index.html和直接用浏览器打开index.html文件效果一样么?
其过程有何差别?

3 HTTP introduction.
HTTP(Hyper Text Transfer Protocol)是超文本传输协议的缩写,
它用于传送WWW方式的数据。HTTP协议采用了请求/响应模型。

客户端向服务器发送一个请求,请求头包含请求的方法、URI、协议版本、
以及包含请求修饰符、客户信息和内容的类似于 MIME的消息结构。
request:
<!--start-->
GET /firstWeb/ HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
If-Modified-Since: Fri, 11 May 2007 03:46:02 GMT
If-None-Match: W/"216-1178855162000"
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host: 127.0.0.1
Connection: Keep-Alive
<!--end-->


服务器以一个状态行作为响应,相应的内容包括消息协议的版本,
成功或者错误编码加上包含服务器信息、实体元信息以及可能的实体内容。
response:
<!--start-->
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ETag: W/"216-1178955948000"
Last-Modified: Sat, 12 May 2007 07:45:48 GMT
Content-Type: text/html
Content-Length: 216
Date: Sat, 12 May 2007 07:45:56 GMT

<html>
<head>
<title>Welcome to SD0702 HomePage</title>
</head>
<body>
<center>
<h1>
<font color="blue">
Welcome to SD0702...
</font>
</h1>
</center>
</body>
</html>
<!--end-->
1xx:信息响应类,表示接收到请求并且继续处理
2xx:处理成功响应类,表示动作被成功接收、理解和接受
3xx:重定向响应类,为了完成指定的动作,必须接受进一步处理
4xx:客户端错误,客户请求包含语法错误或者是不能正确执行
5xx:服务端错误,服务器不能正确执行一个正确的请求
(具体代码含义参看http代码对照表)

4 Servlet introduction.
1) 什么是Servlet
Servlet是用Java编写的Server端程序,它与协议和平台无关。是服务器端的组件。
只能在容器内运行,有自己的生命周期(当然可以给servlet一个main方法,
然后在客户端运行。这是servlet失去了它原有的意义,退化成了一个普通的Java类)。
a) 高效
CGI:进程(开销大,共享资源不方便)
Servlet:线程(开销小,共享资源方便)
b) 方便
Servlet提供了大量的实用工具例程,例如自动地解析和解码HTML表单数据、
读取和设置HTTP头、处理Cookie、跟踪会话状态等。
c) 功能强大
在Servlet中,许多使用传统CGI程序很难完成的任务都可以轻松地完成。
例如,Servlet能够直接和Web服务器交互,而普通的CGI程序不能。
Servlet还能够在各个程序之间共享数据,使得数据库连接池之类的功能很容易实现。

d) 可移植性好
Servlet用Java编写
Servlet: java class, 接收HttpRequest, 生成HttpResponse(生成动态页面)

2) 如何开发Servlet
a) Servlet class有特定的继承关系
interface: Servlet javax.servlet.*)
class: GenericServlet (javax.servlet.*)
class: HttpServlet (javax.servlet.http.*)
GenericServlet implements Servlet
HttpServlet extends GenericServlet

Http POST,GET,...
HttpServlet doPost(),doGet(),...
GenericServlet service()

b) 实现特定的生命周期方法
init(), init(ServletConfig config)
service(HttpServletRequest request, HttpServletResponse response)
destroy()

c) 例子:
需要导入的包
import javax.servlet.*;
import javax.servlet.http.*;
public class ConcreteServlet extends HttpServlet{
init(){}
service(HttpServletRequest request, HttpServletResponse response){}
destroy(){}
}

HelloServlet.java
功能:
标题:Welcome to SD0702 HomePage
内容:居中显示 Hello our friends,today is (current date),
Welcome to visit our HomePage.
firstWeb
/WEB-INF/web.xml
/WEB-INF/classes/HelloServlet.class

http://localhost:8080/firstWeb/hello


d)如何部署一个包含了Servlet的Web应用
I 建立特定的目录结构(Done)
II 编写Servlet源文件(Done)
III 编译Sevlet,并将class文件放到/WEB-INF/classes位置(Done)
IV 修改web.xml,增加Servlet的描述信息(remained step)
<servlet>
<servlet-name>helloServlet</servlet-name> --->Servlet name
<servlet-class>HelloServlet</servlet-class> --->Servlet class的位置
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name> -->Servlet name(has been defined)
<url-pattern>/hello</url-pattern> -->Access the servlet thru url pattern
</servlet-mapping>
--->Servlet的映射名,Browser通过此名字来访问Servlet
V 将整个应用目录复制到%TOMCAT_HOME%/webapps/下,Tomcat自动激活应用。

3) 使用Servlet接收用户输入信息
a)通过表单(form)提交数据
<form action="login" method="POST" enctype="multipart/form-data">
action: 表单提交给服务器的哪个资源处理
method: 提交方式 "POST","GET"等
GET---->通过URL提交表单信息,由于受到URL长度的限制,只能传递大约1024字节。
<!--get方法提交表单-->
GET /guessWeb/guess?answer=abc&times=&luckNo= HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: http://localhost:8090/guessWeb/
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host: 127.0.0.1
Connection: Keep-Alive
<!--end-->

POST--->通过Http Body提交表单信息,传输的数据量大,可以达到2M。
<!--post方法提交表单-->
POST /guessWeb/guess HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: gb2312,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://127.0.0.1:8090/guessWeb/index.html
Content-Type: application/x-www-form-urlencoded
Content-Length: 25

answer=abc&times=&luckNo=
<!--end-->

enctype: multipart/form-data 通常可用于上传文件

例:
//表单通过GET方法(默认)提交给login映射的资源处理
//login为在web.xml中配置的url-pattern或者是jsp文件等
<form action="login">
student name:<input type="text" name="name"/>
<br>
student age:<input type="text" name="age"/>
<br>
student nick:<input type="text" name="nick"/>
<br>
<input type="text" name="nick"/>
<br>
<inut type="submit" value="submit"/>
</form>

b)如何在服务器端获得表单提供的数据

I request对象
HttpServletRequest对象由Web Container封装用户Http请求数据报而成,
可通过它获得所有跟用户请求数据报相关的信息。
getProtocol():String
getMethod():String
getRemoteHost():String
getRemotePort():int
getHeader():String

getParameter(String name):String
返回指定输入参数(名为name)的值
getParameterValues(String name):String[]
返回指定输入参数(名为name)的所有值
getParameterNames():Enumeration
返回请求对象中全部输入参数的名称
例:
String name=request.getParameter("name");
String age=request.getParameter("age");
String[] nicks=request.getParameter("nick");

II 解决Servlet中的中文乱码问题:
<1>静态中文信息乱码
response.setContentType("text/html; charset=gbk");
<2>中文输入乱码
a request.setCharacterEncoding("gbk");(解决post方法提交表单中文乱码问题)
b String name =new String(request.getParamete("name").getBytes("iso-8859-1"));
(b不推荐使用)
c 通过修改%TOMCAT%/conf/server.xml (解决get方法提交表单中文乱码问题)
加入 URIEncoding="gbk"
<3>静态html页面的中文化问题
<meta http-equiv="content-type" content="text/html; charset=gbk">

III 用户管理
功能:用户登录和用户注册
登录:username,password,role(select)
注册:姓名,密码,婚否(radio),电话(用户最多可以有填写3个电话号码,无需验证合法性)
loginWeb
/WEB-INF/web.xml
/WEB-INF/classes/com.LoginServlet.class
/WEB-INF/classes/com.RegisterServlet.class
/login.html
/register.html


1 IDE+Tomcat Server.
2 Servlet Life cycle.
3 ServletConfig&ServletContext.
4 SingleThreadModel(interface).
5 RequestDispatcher.
6 exercise.
*****************************************************************

1 IDE+Tomcat Server.
熟悉Myeclipse环境下配置Tomcat服务器以及部署和运行Web App。

tomcat
/bin 可执行文件
/conf 配置文件
/logs 日志文件
/temp 临时文件
/work 工作目录
/server 服务器包
/common 公用包
/shared 共享包
/webapps WebApp发布目录

2 Servlet Life cycle.
1) ClassLoader载入Servlet类并实例化
2) 调用init()
3) 调用service()<doGet(),doPost(),etc>处理客户端请求
4) 调用destroy()

<servlet>
<servlet-name>s1</servlet-name>
<servlet-class>com.S1Servlet</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet>
<servlet-name>s2</servlet-name>
<servlet-class>com.S2Servlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
load-on-startup: 表示Servlet在部署时通过ClassLoader直接载入并初始化,
数值越低(从1开始计数),载入的优先级越高。否则,用户第一次访问的时候才实例化Servlet。
值相同,一般按在web.xml文件中的出现的顺序执行。

init()--->对Servlet将要使用的资源作初始化,如读入配置文件信息等(只执行一次)
init(ServletConfig config)
service()----->为客户端提供服务,能够被多客户端多次调用(每个请求都要执行一次)
destroy()--->在Web Container停止Web App或WebApp被停止/reload时调用,
通常完成一些资源释放,停止后台程序等工作。释放或销毁一些非内存资源。
(只执行一次)
例子:
观察三个生命周期方法何时执行
lifecycleWeb
/WEB-INF/web.xml
/WEB-INF/classes/com/LifeCycleServlet.class

部署和实例化一个Servlet的情况有两种
1)web.xml中没有load-on-startup标记
a 在用户第一次请求的时候tomcat服务器加载servlet类,
并且实例化一个对象,接着执行init方法。最后执行service方法为第一次请求服务。
b 用户的第二次以及其后的所有请求,servlet对象直接调用service方法为其服务。
2)web.xml中有load-on-startup标记
a 在webapp被启动的时候,tomcat服务器加载servlet类,并且实例化一个对象,
接口执行init方法。
b 用户任何请求,servlet对象都调用service方法为其服务。

destroy方法什么时候执行?:关闭webapp的时候(只执行一次)。

3 ServletConfig&ServletContext.

ServletConfig:从一个servlet被实例化后,对任何客户端在任何时候访问有效,
但仅对本servlet有效,一个servlet的ServletConfig对象不能被另一个servlet访问。

ServletContext:对同一个WebApp的任何servlet,任何人在任何时间都有效,
这才是真正全局的对象。

<servlet>
<servlet-name>lifecycleServlet</servlet-name>
<servlet-class>com.LifeCycleServlet</servlet-class>
<init-param>
<param-name>email</param-name>
<param-value>narci.ltc@gmail.com</param-value>
</init-param>
<load-on-startup>5</load-on-startup>
</servlet>

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

ServletConfig---->对应某个具体的Servlet,主要用来读取web.xml中配置的
Servlet初始信息,不能被其它Servlet共享

如何获得ServletConfig对象
1)init(ServletConfig config)
2)this.getServletConfig()


ServletContext---->对应整个Web Application运行环境,可以用来读取web.xml
中配置的应用初始信息,写日志,共享数据等,ServletContext被所有Servlet共享

如何获得ServletContext对象
1)config.getServletContext()
2)this.getServletContext()

利用ServletContext写日志
log(String info)

例子:
如何获取web.xml配置文件中的context param和init param。
比较它们的作用域范围有什么不同。学会使用context对象写日志。
classNo:context param
email:intit param
phone:init param
configWeb
/WEB-INF/web.xml
/WEB-INF/classes/com/ConfigServlet.class
/WEB-INF/classes/com/ContextServlet.class


4 SingleThreadModel(interface).
该接口已经废弃(deprecated)
请不要实现 SingleThreadModel 接口。
这种实践将导致 Web 容器创建多个 servlet 实例;
即为每个用户创建一个实例。对于任何大小的应用程序,
这种实践都将导致严重的性能问题。
request <--->servlet实例(对象) 一一对应的

正常servlet:
n个request <--->一个servlet实例(对象)
深入理解:servlet是单实例多线程
servlet对象只有一个

public class SomeServlet extends HttpServlet implements SingleThreadModel{}

代替SingleThreadModel的方案:
Servlet是单实例,多线程:使用synchronized块解决同步问题。
提示:在Servlet中尽量少使用成员变量,一旦使用必须自己维护其并发问题。

实际应用中,service()方法中使用synchronized来解决并发问题,synchronized
块作用域应该越小越好,并且通常只在对实例变量作修改时使用。
同步控制的粒度要尽量小。

建议:
1)尽量不要使用成员变量。一旦使用,必须自己控制并发问题。
2)同步块应该尽可能小。

例子:

count:int 访问计数
name:String 用户名称
singleWeb
/WEB-INF/web.xml
/WEB-INF/classes/com/VisitorServlet.class (SingleThreadModel)
/WEB-INF/classes/com/Visitor2Servlet.class
注意:对成员变量的访问必须注意同步操作


5 RequestDispatcher.

RequestDispatcher---->实现Servlet之间的请求传递(页面跳转)
forward(ServletRequest, ServletResponse) //跳转到其他资源
include(ServletRequest, ServletResponse) //包含其他资源

如何获得RequestDispatcher对象
1) request.getRequestDispatcher(String page) ---->相对路径
2) ServletContext.getRequestDispather(String page) ---->绝对路径

例子:
用户登录,成功跳转到target servlet,失败则跳转到fail.html
target servlet包含版权声明页面(copyright.html)。
login2Web
/WEB-INF/web.xml
/WEB-INF/classes/com/LoginServlet.class
/WEB-INF/classes/com/TargetServlet.class
/login.html
/fail.html
/copyright.html

6 exercise.
改写用户登录WebApp,要求通过读取web.xml来决定用户登录成功和失败后分别跳转到的那个
资源。不管用户登录成功还是失败,必须写日志,记录下用户名、密码、角色以及登录时间。
login3Web
/WEB-INF/web.xml
/WEB-INF/classes/com/LoginServlet.class
/WEB-INF/classes/com/TargetServlet.class (登录成功,需要包含版权信息)
/login.html
/fail.html
/copyright.html

练习:(ServletConfig,ServletContext,RequestDispatcher)
一个网上书店系统,用户分5个等级,对网上书店上所有商品,
一星会员可以享受 95%的优惠。
二星会员可以享受 90%的优惠。
三星会员可以享受 85%的优惠。
四星会员可以享受 80%的优惠。
五星会员可以享受 75%的优惠。
其中外文书籍对任何用户都有额外的95%的优惠,计算机类书籍也有额外的85%的优惠
bookWeb
/WEB-INF/web.xml
/WEB-INF/classes/com/ForeignBookServlet.class
/WEB-INF/classes/com/ComputerBookServlet.class
/WEB-INF/classes/com/OtherBookServlet.class
/foreign.html
/computer.html
/other.html

用户输入要购买的图书以及价格等信息提交后,将这打折后的价格和其他信息返回显示
给用户。每次购买行为要求写日志。
日志格式为:用户名 购买的图书名称 原价 打折后的价格 购买时间

ServletConfig:
1)this.getServletConfig() 任何方法中都可以调用
2)config.getServletConfig() 在init(ServletConfig config)方法可以调用

ServletContext:
1)this.getServletContext() 任何方法中都可以调用
2)config.getServletContext() 在init(ServletConfig config)方法可以调用

public MyServlet extends HttpServlet{

ServletConfig config=getServletConfig();//可不可以? null
//不可以!
//原因:成员变量的初始化次序优先于构造方法。
//而我们ServletConfig对象是在调用了init方法之后才初始化的。
//init的执行肯定是在执行了构造方法之后才执行。

ServletContext context=getServletContext();//null?
//?

public void init(){}
...

}


1 Access Resources.
2 Connection Pool.
3 DataSource.
4 DAO.
5 exercise.
**************************************************************
1 Access Resources.
1)要在WebApp中访问数据库,必须先将其JDBC Driver复制至%TomcatHome%/common/lib下。
2)直接创建数据源方式获得数据库连接
重写用户登录模块
create database test;

use test;
//创建用户表
create table t_user(
t_id int auto_increment primary key,
t_name varchar(20),
t_pass varchar(128),
t_role varchar(20)
)

insert into t_user(t_name,t_pass,t_role) values ('Alice','Alice','admin');
insert into t_user(t_name,t_pass,t_role) values ('Maxwell','Maxwell','guest');
insert into t_user(t_name,t_pass,t_role) values ('test','test','admin');
...

login3Web
/WEB-INF/web.xml
/...

3)通过配置连接池获得数据库连接。
a 在WebApp需要配置web.xml文件
资源引用
web.xml需要作如下配置:
<resource-ref>
<res-ref-name>jdbc/test</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth> 可选值:Application
<res-sharing-scope>Shareable</res-sharing-scope> 可选值:Unshareable
</resource-ref>

通过JNDI访问数据源
import javax.naming.*;
Context ic=new InitialContext();
DataSource ds=(DataSource)ic.lookup("java:comp/env/jdbc/test");
//ds=is.lookup("jdbc/test");
Connection con=ds.getConnection();//代替DriverManager.getConnection();

web.xml中配置环境变量(可以通过JNDI访问)
<env-entry>
<description>my email</description>
<env-entry-name>email</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>narci.ltc@gmail.com</env-entry-value>
</env-entry>
<env-entry>
<description>Is Trainer</description>
<env-entry-name>isTrainer</env-entry-name>
<env-entry-type>java.lang.Boolean</env-entry-type>
<env-entry-value>true</env-entry-value>
</env-entry>
b 在应用服务器要配置连接池。
Tomcat:server.xml
...
<Context
path="/login3Web">
<Resource
name="jdbc/test"
type="javax.sql.DataSource"
username="narci"
password="11"
driverClassName="com.mysql.jdbc.Driver"
maxIdle="10"
maxWait="5000"
validationQuery="select * from student"
url="jdbc:mysql://localhost/test"
maxActive="10"/>
</Context>
...
* maxActive
- 同一时刻可以自数据库连接池中被分配的最大活动实例数。
* maxIdle
- 同一时刻数据库连接池中处于非活动状态的最大连接数。
* maxWait
- 当连接池中没有可用连接时,连接池在抛出异常前将等待的最大时间,单位毫秒。


2 Web App访问数据库
1)从结构上优化()
DAO: Data Access Object
设计DAO接口可进一步抽象持久化逻辑
VO: Value Object:其实就是标准的Java Bean,只是对应数据库中的一张表。
Java Bean的要求
a 空参数的构造器
c 对属性的标准访问方法setter、getter方法
String name;
public void setName(String name){}
public String getName(){}
3、远程传递时需要实现java.io.Serializable

2)从性能上作优化
使用连接池,减少因物理连接带来的系统开销,提升数据库访问性能


关键字: cookie session 1 Trace state:Cookie.
2 Trace state:Session.
3 exercise.
************************************************************

1 Trace state:Cookie.

Cookie:客户端保存状态的机制,通过cookie文件来记录信息
Cookie编程:
从request中获得cookie:Cookie[] request.getCookies()
创建一个Cookie: new Cookie(String name,String value)
获得cookie中的信息: Cookie.getValue() getName()
设置cookie的有效时间: Cookie.setMaxAge(int seconds)//单位秒
0:不支持cookie
负数:会话cookie,即不写文件
把cookie写回客户端: response.addCookie(Cookie cookie)
例子:
用户访问计数(CookieVisitorServlet):cookie版本
第100名访问者奖励一个小礼品
C:\Documents and Settings\%user%\Cookies

创建TwoCookieServlet
要求:创建两个Cookie写回客户端,并设置有效时间10s,观察cookie文件中的内容及
TCP Monitor监视到的HTTP数据报内容
Cookie cookie1=new Cookie("userName","Tommy");
Cookie cookie2=new Cookie("className","SD0702");

HTTP response的内容
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: userName=Tommy; Expires=Fri, 18-May-2007 03:01:10 GMT
Set-Cookie: classNo=SD0702; Expires=Fri, 18-May-2007 03:01:10 GMT
Content-Type: text/html;charset=gbk
Transfer-Encoding: chunked
Date: Fri, 18 May 2007 03:01:00 GMT

7a
<HTML>
<HEAD><TITLE>Two Cookie Servlet</TITLE></HEAD>
<BODY>
<h1 align=center>两个小甜饼</h1>
</BODY>
</HTML>

0
在cookie没有超时的情况下,HTTP request会带上cookie的信息
GET /cookieWeb/two HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host: 192.168.2.53:8082
Connection: Keep-Alive
Cookie: userName=Tommy; classNo=SD0702


例子:显示所有的Cookie
ListCookieServlet

三种类型的cookie
寿命
setMaxAge:0 不支持Cookie
负数,会话Cookie,保持在浏览器,不写文件
整数,普通Cookie,写文件
注意:Cookie需要客户端浏览器的支持,
如果浏览器禁用Cookie的话,我们的所有Cookie就无效

2 Trace state:Session.
Session:服务器端保存状态的机制,通过HttpSession对象来记录信息
Session编程:
获得Session: request.getSession() getSession(boolean b)
request.getSession()与getSession(true)等价:
没有session对象时候自动创建session对象
getSession(false):没有session对象时候返回null,不会自动创建session对象
Session存信息: HttpSession.setAttribute(String name,Object o)
Session取信息: Object HttpSession.getAttribute()
设置Session有效时间:(单位秒)
HttpSession.setMaxInactiveInterval(int interval)
设置session无效的时间,负数表示永不过时。
手工销毁Session: HttpSession.invalidate()
判断Session是否新建: boolean HttpSession.isNew()
获得SessionID: HttpSession.getId()

用户访问计数(SessionVisitorServlet):session版本
第100名访问者奖励一个小礼品

客户端维护SessionID:
1)通过Cookie来维护SessionID
Web Server生成Session对象后,每次作response时,会自动把SessionID发回到客户端,
客户端把SessionID记入会话Cookie,下次请求时自动带上
服务器第一次的相应会生成一个session id,发送到客户端
HTTP response:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=46C8177FB3EAC6F7FD868E6FA147E9CD; Path=/sessionWeb
Content-Type: text/html;charset=gbk
Transfer-Encoding: chunked
Date: Fri, 18 May 2007 03:54:31 GMT

+++++++++++++++++++++++++++++++++++++++++++++++++++++
下一次客户端的请求会带上以cookie的形式session id
HTTP request:
GET /sessionWeb/visitor HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host: 192.168.2.53:8082
Connection: Keep-Alive
Cookie: JSESSIONID=46C8177FB3EAC6F7FD868E6FA147E9CD


2)重写URL来维护SessionID(当客户端阻止cookie时,可采用这种方式维护sessionid)
把sessionID加到请求的URL中
out.println("<a href="+response.encodeURL("visitor")+">access again</a>");
http://192.168.2.53:8082/sessionWeb/visitor;jsessionid=1CA21297D00524960931F00F69FF7A4A


销毁Session:
1)session.invalidate()
2)
a session.setMaxInactiveInterval(int interval)(a优先级高于b方法) 1800
也可通过web.xml来设最长不激活时间:
b <session-config>
<session-timeout>30</session-timeout>
</session-config>
default value: 60min
3)Web Server crash(服务器定制,webapp被停止,session都会被销毁。


3
维护状态的方式
1)Cookie
2)Session
3)隐藏表单域
<input type="hidden" name="times" value=""/>
4)URL重写
http://localhost:8080/visitorWeb/visitor?name=Alice&age=23

1 Filter.
2 Listener.
3 exercise.
*************************************************************
过滤器

1. 什么是过滤器?
答:与Servlet相似,过滤器是一些Web应用程序组件,可以绑定到一个Web应用程序档案中。但是与其他Web应用程序组件不同的是,过滤器是“链”在容器的处理过程中的。这就意味着它们会在servlet处理器之前访问一个进入的请求,并且在外发的响应信息返回到客户前访问这些响应信息。这种访问使得过滤器可以检查并修改请求和响应的内容。

2. 过滤器可以用于:
答:1) 为一个Web应用程序的新功能建立原型(可被添加到Web应用程序中或者从Web应用程序中删除而不需重写基层应用程序代码);
2) 向过去的代码中添加新功能。

3. 过滤器放在容器结构什么位置?
答:过滤器放在Web资源之前,可以在请求抵达它所应用的Web资源(可以是一个servlet、一个JSP页面,甚至是一个HTML页面这样的静态内容)之前截获进入的请求,并且在它返回到客户之前截获输出请求。

4. 过滤器的存活周期
答:过滤器有四个阶段(与servlet类似):
1) 实例化;
2) 初始化(调用init()方法);
3) 过滤(调用doFilter()方法);
4) 销毁(调用destroy()方法);

5. 过滤器类和接口
答:所有的过滤器都必须实现javax.servlet.Filter接口:
1) 容器调用init()方法初始化过滤器实例:
public void init(FilterConfig config) throws ServletException
2) doFilter()方法包含过滤器逻辑:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
3) destroy()方法由容器在销毁过滤器实例之前调用:
public void destroy();
4) FilterChain的doFilter()方法之后的代码构成了后期处理过滤器调用。

6. 配置过滤器
答:使用<filter>和<filter-mapping>元素来配置:
<filter>
<filter-name>XSLTFilter</filter-name> //过滤器名
<filter-class>filters.SmartXSLFilter</filter-class> //具体过滤器类
<init-param> //初始化参数
<param-name>xsltfile</param-name>
<param-value>/xsl/stockquotes.xsl</param-value>
</init-param>
</filter>
<filter-mapping> //将过滤器应用于Web应用程序中的每个Web资源
<filter-name>Logger</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

如何开发Filter:
1)implement javax.servlet.Filter
2)生命周期方法
init()
doFilter()
destroy()
3)filter在webapp启动时候被实例化,容器会执行其init()方法。
4)filter request, response
public void doFilter(ServletRequest request, ServletResponse response,FilterChain filterChain) {
try {
//filter request
request.setCharacterEncoding("gbk");
//检查filter是不是同一个实例
System.out.println("process request:"+this);

filterChain.doFilter(request, response);

//filter response
System.out.println("process response:"+this);
}
catch (ServletException sx) {
filterConfig.getServletContext().log(sx.getMessage());
}
catch (IOException iox) {
filterConfig.getServletContext().log(iox.getMessage());
}
}
5)deploy filter in web.xml
<filter>
<filter-name>encodingfilter</filter-name>
<filter-class>filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encodingfilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

6)多个filter的执行次序
根据 <filter-mapping> 的先后次序决定
web.xml
<filter-mapping>
<filter-name>encodefilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>visitorfilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
把所有请求客户端的IP地址和请求的时间写入日志文件。
用户投票
例子:
惰性认证
保护某些页面
if (role == null || !role.equals("admin")) {

try {
res.sendRedirect("../login.html");
}
catch (IOException ex) {
}
}
try {
filterChain.doFilter(request, response);
}
catch (ServletException sx) {
filterConfig.getServletContext().log(sx.getMessage());
}
catch (IOException iox) {
filterConfig.getServletContext().log(iox.getMessage());
}

2 Listener.

Listener:
--->ServletContext,HttpSession(2.3) ServletRequest(2.4)

1)implements ServletContextListener.
2)override listener method.
3)在webapp启动是被实例化。
4)web.xml
<listener>
<listener-class>com.MyListener</listener-class>
</listener>

例子:
Web应用程序生命周期事件及监听器(Servlet V2.3版本以后新增功能)

1. 什么是事件监听器?
答:1) 支持ServletContext、HttpSession(since v2.3)及ServletRequest(since v2.4)中状态改变的事件通知;
2) 实现了一个或多个servlet事件监听器接口的类型;
3) 控制ServletContext、HttpSession(since v2.3)及ServletRequest(since v2.4)中的生命周期;

2. Servlet Context事件监听器
答:1) 对于应用程序而言在JVM层别管理资源或保存状态
2) 有二种类型的事件监听器:
a. ServletContextListener(以下是该监听器的方法)
contextDestroyed(ServletContextEvent sce)
contextInitialized(ServletContextEvent sce)
b. ServletContextAttributeListener(以下是该监听器的方法)
attributeAdded(ServletContextAttributeEvent scab)
attributeRemoved(ServletContextAttributeEvent scab)
attributeReplaced(ServletContextAttributeEvent scab)

3. HTTP Session事件监听器
答:1) 管理从同一个客户端或用户向一个Web应用程序发出的一系列请求相关的状态或资源;
2) 有二种类型的事件监听器:
a. HttpSessionListener(以下是该监听器的方法)
sessionCreated(HttpSessionEvent se)
sessionDestroyed(HttpSessionEvent se)
b. HttpSessionAttributeListener(以下是该监听器的方法)
attributeAdded(HttpSessionBindingEvent se)
attributeRemoved(HttpSessionBindingEvent se)
attributeReplaced(HttpSessionBindingEvent se)

4. Servlet Requst事件监听器
答:1) 管理整个request生命周期的状态
2) 有二种类型的事件监听器
a. ServletRequestListener(以下是该监听器的方法)
requestDestroyed(ServletRequestEvent sre)
requestInitialized(ServletRequestEvent sre)
b. ServletRequestAttributeListener(以下是该监听器的方法)
attributeAdded(ServletRequestAttributeEvent srae)
attributeRemoved(ServletRequestAttributeEvent srae)
attributeReplaced(ServletRequestAttributeEvent srae)

5. 监听器类的规定
答:1) 必须在部署描述符中配置实现类;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值