HTTP协议是无状态的,不能保存每次提交的信息,即当服务器返回与请求相对应的应答之后,这次事务的所有信息就丢掉了。
如果用户发来一个新的请求,服务器无法知道它是否与上次的请求有联系。
对于那些需要多次提交数据才能完成的Web操作,比如登录来说,就成问题了。
1.1.2 什么是状态管理
WEB应用中的会话是指一个客户端浏览器与WEB服务器之间连续发生的一系列请求和响应过程。
WEB应用的会话状态是指WEB服务器与浏览器在会话过程中产生的状态信息,借助会话状态,WEB服务器能够把属于同一会话中的一系列的请求和响应过程关联起来。
1.1.3 状态管理的两种常见模式
客户端状态管理技术:将状态保存在客户端。代表性的是Cookie技术。
服务器状态管理技术:将状态保存在服务器端。代表性的是session技术(服务器传递sessionID时需要使用Cookie的方式)和application
Cookie是在浏览器访问WEB服务器的某个资源时,由WEB服务器在HTTP响应消息头中附带传送给浏览器的一小段数据,WEB服务器传送给各个客户端浏览器的数据是可以各不相同的。
一旦WEB浏览器保存了某个Cookie,那么它在以后每次访问该WEB服务器时,都应在HTTP请求头中将这个Cookie回传给WEB服务器。
WEB服务器通过在HTTP响应消息中增加Set-Cookie响应头字段将Cookie信息发送给浏览器,浏览器则通过在HTTP请求消息中增加Cookie请求头字段将Cookie回传给WEB服务器。
一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。
一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie。
浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB
1.2.2 如何创建Cookie
//创建Cookie
Cookie ck=new Cookie("code", code);
ck.setPath("/");//设置Cookie的路径
ck.setMaxAge(-1);//内存存储,取值有三种:>0有效期,单位秒;=0失效;<0内存存储,默认-1
response.addCookie(ck);//让浏览器添加Cookie
//注意:有效路径: 当前访问资源的上一级目录,不带主机名
chrome浏览器查看cookie信息:chrome://settings/content/cookies
1.2.3 如何查询Cookie
//获取所有的Cookie
Cookie[] cks=request.getCookies();
//遍历Cookie
for(Cookie ck:cks){
//检索出自己的Cookie
if(ck.getName().equals("code"))
{
//记录Cookie的值
code=ck.getValue();
break;
}
}
只需要保证Cookie的名和路径一致即可修改
//创建Cookie
Cookie ck=new Cookie("code", code);
ck.setPath("/");//设置Cookie的路径
ck.setMaxAge(-1);//内存存储,取值有三种:>0有效期,单位秒;=0失效;<0内存存储
response.addCookie(ck);//让浏览器添加Cookie
注意:如果改变cookie的name和有效路径会新建cookie, 而改变cookie值、有效期、和httponly会覆盖原有cookie
1.2.5 Cookie的生存时间
ck.setMaxAge(-1);设置生成时间,默认-1
取值说明:
>0有效期,单位秒
=0失效
<0内存存储
1.2.6 Cookie的编码与解码
中文和英文字符不同,中文属于Unicode字符,在内存中占用4个字符,而英文属于ASCII字符,内存中
只占2个字节。Cookie中使用Unicode字符时需要对Unicode字符进行编码,否则会出现乱码。编码可以
使用java.net.URLEncoder类的encode(String str,String encoding)方法,解码使用java.net.URLDecoder类
的decode(String str,String encoding)方法
代码如下:
保存:Servlet类
// 使用中文的 Cookie. name 与 value 都使用 UTF-8 编码.
Cookie cookie = new Cookie(
URLEncoder.encode("姓名", "UTF-8"),
URLEncoder.encode("老邢", "UTF-8"));
// 发送到客户端
response.addCookie(cookie);
读取:Servlet读取
if(request.getCookies() != null){
for(Cookie cc : request.getCookies()){
String cookieName = URLDecoder.decode(cc.getName(), "UTF-8");
String cookieValue = URLDecoder.decode(cc.getValue(), "UTF-8");
out.println(cookieName + "=");
out.println(cookieValue + ";
");
}
}
else{
out.println("Cookie 已经写入客户端. 请刷新页面. ");
}
cookie 一般都是由于用户访问页面而被创建的,可是并不是只有在创建 cookie 的页面才可以访问这个cookie。在默认情况下,出于安全方面的考虑,只有与创建 cookie 的页面处于同一个目录或在创建cookie页面的子目录下的网页才可以访问。那么此时如果希望其父级或者整个网页都能够使用cookie,就需要进行路径的设置。
cookie.setPath("/");
1.3.2 发送Cookie的条件
浏览器在发送请求之前,首先会根据请求url中的域名在cookie列表中找所有与当前域名一样的cookie,
然后再根据指定的路径进行匹配,如果当前请求在域匹配的基础上还与路径匹配那么就会将所有匹配
的cookie发送给服务器。
1.3.3 如何设置Cookie的路径
通过Cookie的setPath方法设置路径
优点:
可配置到期规则:Cookie 可以在浏览器会话结束时到期,或者可以在客户端计算机上无限期存在,这取决于客户端的到期规则,不需要任何服务器资源,Cookie 存储在客户端并在发送后由服务器读取。
简单性:Cookie 是一种基于文本的轻量结构,包含简单的键值对。
数据持久性:虽然客户端计算机上 Cookie 的持续时间取决于客户端上的 Cookie 过期处理和用户干预,Cookie 通常是客户端上持续时间最长的数据保留形式
缺点:
大小受到限制:大多数浏览器对 Cookie 的大小有 4096 字节的限制,尽管在当今新的浏览器和客户端设备版本中,支持 8192 字节的 Cookie 大小已愈发常见。
用户配置为禁用:有些用户禁用了浏览器或客户端设备接收 Cookie 的能力,因此限制了这一功能。
潜在的安全风险:Cookie 可能会被篡改。用户可能会操纵其计算机上的 Cookie,这意味着会对安全性造成潜在风险或者导致依赖于Cookie 的应用程序失败。
Session用于跟踪客户的状态。Session指的是在一段时间内,单个客户与Web服务器的一连串相关的交互过程。在一个Session中,客户可能会多次请求访问同一个网页,也有可能请求访问各种不同的服务器资源。
2.1.2 Session工作原理
session被用于表示一个持续的连接状态,在网站访问中一般指代客户端浏览器的进程从开启到结束的
过程。session其实就是网站分析的访问(visits)度量,表示一个访问的过程。
session的常见实现形式是cookie(session cookie),即未设置过期时间的cookie,这个cookie
的默认生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。实现机制是当用户发起一个请求的时候,服务器会检查该请求中是否包含sessionid,如果未包含,则系统
会创造一个名为JSESSIONID的输出 cookie返回给浏览器(只放入内存,并不存在硬盘中),并将其以HashTable的形式写到服务器的内存里面;当已经包含sessionid时,服务端会检查
找到与该session相匹配的信息,如果存在则直接使用该sessionid,若不存在则重新生成新的 session。
这里需要注意的是session始终是有服务端创建的,并非浏览器自己生成的。
2.1.3 如何获得Session
//获取Session对象
HttpSession session=request.getSession();
System.out.println("Id:"+session.getId());//唯一标记,
System.out.println("getLastAccessedTime:"+session.getLastAccessedTime());//最后一次访问时间,毫秒
System.out.println("getMaxInactiveInterval:"+session.getMaxInactiveInterval());//获取最大的空闲时间,单位秒
System.out.println("getCreationTime:"+session.getCreationTime());//获取Session的创建,单位毫秒
2.1.4 如何使用Session绑定对象
使用HttpSession的setAttribute(属性名,Object)方法
2.1.5 如何删除Session
使用HttpSession的invalidate方法
HttpSession的最后一程访问时间和当前时间的差距大于了指定的最大空闲时间,这时服务器就会销毁Session对象。默认的空闲时间为30分钟。
2.2.2 如何修改Session的缺省时间限制
1 使用HttpSession的session.setMaxInactiveInterval(20*60);设置,单位秒
2 在web.xml中配置 ,单位分钟
20
2.2.3 Session失效的几种情况
1、超过了设置的超时时间
2、主动调用了invalidate方法
3、服务器主动或异常关闭
注意:浏览器关闭并不会让Session失效 而是等30分钟
如果浏览器禁用Cookie,session还能用吗?
答:不能,但有其他的解决方案
服务器在默认情况下,会使用Cookie的方式将sessionID发送给浏览器,如果用户禁止Cookie,则sessionID不会被浏览器保存,此时,服务器可以使用如URL重写这样的方式来发送sessionID.
使用Session区分每个用户的方式:
1、使用Cookie
2、作为隐藏域嵌入HTML表单中,附加在主体的URL中,通常作为指向其他应用程序页面的链接,即URL重写。
.3.2 什么是URL重写
浏览器在访问服务器上的某个地址时,不再使用原来的那个地址,而是使用经过改写的地址(即,在原来的地址后面加上了sessionID)
2.3.3 如何实现URL重写
如果是链接地址和表单提交,使用
response.encodeURL(String url)生成重写后的URL
如果是重定向,使用
response.encodeRedirectURL(String url)生成重写的URL
登录的html页面:
login.html
登录页面
登录的成功页面:
登录成功
登录的Servlet:
package com.qf.web.servlet;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
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 javax.servlet.http.HttpSession;
/**
* Servlet implementation class LoginServlet
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LoginServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//doGet(request, response);
request.setCharacterEncoding("utf-8");
String username=request.getParameter("email");
String pass=request.getParameter("psw");
System.out.println(request.getRemoteAddr()+":登录:账号:"+username+"----->密码:"+pass);
//将数据存储在Session中
HttpSession session=request.getSession();
System.out.println("Id:"+session.getId());//唯一标记,
System.out.println("getLastAccessedTime:"+session.getLastAccessedTime());//最后一次访问时间,毫秒
System.out.println("getMaxInactiveInterval:"+session.getMaxInactiveInterval());//获取最大的空闲时间,单位秒
System.out.println("getCreationTime:"+session.getCreationTime());//获取Session的创建,单位毫秒
//设置数据
session.setAttribute("username", username);
if(username.equals("admin")&&pass.equals("888")){
//重定向
response.sendRedirect("index.html");
}else{
request.getRequestDispatcher("login.html").forward(request, response);
}
}
}
注销登录的Servlet:
/**
* Servlet implementation class ExitLogin
*/
@WebServlet("/exit")
public class ExitLogin extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public ExitLogin() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//移除登录信息
request.getSession().removeAttribute("username");
request.getSession().invalidate();//将当前的Sessio失效
response.sendRedirect("login.html");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//doGet(request, response);
}
生成验证码:
/**
* Servlet implementation class CreateCode
* 验证码的生成
*/
@WebServlet("/createcode")
public class CreateCode extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public CreateCode() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//response.getWriter().append("Served at: ").append(request.getContextPath());
ValidateCode vc=new ValidateCode(200, 30, 4, 10);
String code=vc.getCode();
System.out.println(request.getRemoteAddr()+":生成:"+code);
//使用Session存储生成的验证码
HttpSession session=request.getSession();
session.setAttribute("code",code);
vc.write(response.getOutputStream());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
ServletContext:Servlet上下文,代表当前整个应用程序。(jsp中application)
ServletContext:Servlet上下文。
当WEB服务器启动时,会为每一个WEB应用程序(webapps下的每个目录就是一个应用程序)创建一块共享的存储区域
ServletContext也叫做“公共区域”,也就是同一个WEB应用程序中,所有的Servlet和JSP都可以共享同一个区域。
ServletContext在WEB服务器启动时创建,服务器关闭时销毁。
3.2 如何获得Servlet上下文
方式一:GenericServlet提供了getServletContext()方法。(推荐)
方式二:HttpServletRequest提供了getServletContext()方法。(推荐)
方式三:ServletConfig提供了getServletContext()方法。
方式四:HttpSession提供了getServletContext()方法。
3.3 Servlet上下文的作用及特点
作用:
1、获取真实路径
获取当前项目的发布路径
request.getServletContext().getRealPath("/");
2、获取容器的附加信息
System.out.println(request.getServletContext().getServerInfo());
System.out.println(request.getServletContext().getContextPath());
System.out.println(request.getContextPath());
3、全局容器
//设置信息到全局容器中
request.getServletContext().setAttribute("msg", "共享信息");
//获取数据
System.out.println(request.getServletContext().getAttribute("msg"));
//移除数据
request.getServletContext().removeAttribute("msg");
特点:
一性: 一个应用对应一个servlet上下文。
一直存在: 只要容器不关闭或者应用不卸载,servlet上下文就一直存在。
web.xml文件配置servletContext参数
appname
xxx管理系统
appversion
2.0
//获取servlet上下文参数
String appname=application.getInitParameter("appname");
String appversion=application.getInitParameter("appversion");
System.out.println(appname+"..."+appversion);
3.4案例演示:ServletContext统计Servlet访问次数
package com.qf.servlet;
import java.io.IOException;
import java.io.PrintWriter;
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;
/**
* Servlet implementation class Servlet3
*/
@WebServlet("/servlet3")
public class Servlet3 extends HttpServlet {
private static final long serialVersionUID = 1L;
public Servlet3() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
ServletContext application = request.getServletContext();
Integer count=(Integer) application.getAttribute("count");
if(count==null) {
count=1;
application.setAttribute("count", count);
}else {
count++;
application.setAttribute("count", count);
}
PrintWriter out=response.getWriter();
out.write("servlet共访问次数:"+count);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
总结:
1 Cookie:客户端状态管理,保存一小段信息,第一次访问时服务器,服务器cookie响应给浏览器,下次再访问服务器时,把cookie回传给服务器,服务器收到cookie。
Cookie cookie=new Cookie("xxx","141241232");
cookie.setMaxAge(); 默认-1 保存在内存中, 0 表示失效 正数 过期时间 单位是秒
cookie.setPath();设置有效路径,默认null (当前资源的上一级目录) 设置 /项目名 cookie.setPath("/)
cookie.sethttponly(true);
response.addCookie(cookie);
2 session:服务器端状态管理,是一个map集合,session使用sessionid区别,服务器会把SessionId作为cookie的值发送给浏览器,浏览器再次访问服务器时,服务器读取到cookie(sessionid)。
保存登录信息,购物车
HttpSession session=request.getSession();
session默认有效期:30分钟
web.xml中配置有效期
20
3 ServletContext:servlet上下文:是所有用户共享的区域,是一个map集合。
3.1获取ServletContext:
this.getServletContext();
request.getServletContext();
this.getServletConfig().getServletContext();
requst.getSession().getServletContext();
3.2 作用
//获取真实路径
request.getServletContext.getRealPath();
//获取服务器信息
request.getServletContext.getServerInfo();
//获取应用程序名称
request.getServletContext.getContextPath();
request.getContextPath();
//容器使用
appliction.setAttribute(name,value);
application.getAttribute(name);
application.removeAttribute(name);
3.3配置ServletContext启动参数 web.xml
app
xxxx
request.getServletContext.getInitparamenter("appname");