本篇博客知识点
1.演示request、session、application(ServletContext)的生命周期
2.Session池的工作原理
3.网页验证码
演示request、session、application(ServletContext)的生命周期
主要思路: 在SaveServlet中 设置三个容器的name属性,分别赋值。再写个超链接个GetServlet中去读取出来,输出到页面。
在IE中存、在IE中拿(浏览器未关闭) session 和application拿到了
在IE中存。在360浏览器中拿 只拿到了application
总结:
request 生命周期是一次请求,一个request。所以Getsevlet和SaveSevlet 中是两个request 因此拿不到
session 生命周期和浏览器是一起的,浏览器不关闭,同一个浏览器上拿到的session是同一个 因此IE在IE上拿的到 360浏览器拿不到IE存的session
application 生命周期是和服务器一起的 服务器一直未关闭,所以不管什么浏览器都能拿到applicatton容器内的值
SavaServlet.java
package cn.hncu.servlets2;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class SaveServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println(" <BODY>");
// 通过三个容器request、session、application 分别设置三个属性 看看能在哪儿拿到 推出他们的生命周期
String name = "胡龙华";
request.setAttribute("name", name+"_request");
HttpSession session = request.getSession();
session.setAttribute("name", name+"_session");
ServletContext application = getServletContext();
application.setAttribute("name", name+"_application");
out.println(" <a href='GetServlet'>查看三个容器属性</a><br/>");
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
}
GetServlet.java
package cn.hncu.servlets2;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class GetServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println(" <BODY>");
String requestName = (String) request.getAttribute("name");
out.println("requestName:"+requestName+"<br/>");
String sessionName = (String) request.getSession().getAttribute("name");
out.println("sessionName:"+sessionName+"<br/>");
String applicationName = (String) getServletContext().getAttribute("name");
out.println("applicationName:"+applicationName);
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
}
Session池工作原理
当浏览器访问服务器时,服务器会去读取浏览器中的一个cookie ,这个cookie的name 为 JESSIONID 拿到他的value值,SESSIONID 去Session池匹配,找到了建立连接,未找到就重新创建一个SESSIONID并且写到cookie里
通过不断维护这个seesion池,完成回话。session池的底层原理是HashMap();
有的浏览器禁用了cookie,那么按照这种方式就没办法建立会话连接,因此为了兼容,可以值禁用cookie时,通过地址栏把JESSIONID发给服务器格式如下:
http://localhost:8080/cookieSessionWeb/GetServlet;jsessionid=2110E3A20145E759FEB31680E3ABB872
正是因为这种兼容方式,容易系统容易被人黑。用户退出后Session默认的时间是30分钟,因此要让用户安全退出—在Session池中去掉哪条记录
//安全退出
HttpSession s = request.getSession();
s.invalidate(); //让session失败
out.println("您已经安全退出!");
另外一种情况是:用户不小心关闭了浏览器,想要重新打开恢复刚刚的页面信息(恢复刚刚session通话),如何做? — 服务器像用户写一个普通cookie 把刚刚的SESSIONID放过去就好了
//本来,浏览器关闭之后重启,上一次的用户临时信息是访问不了的
//把cookie和session技术联合起来,实现让用户不小心关闭浏览器,用户的临时信息还能在5分钟之内重启浏览器有效
//我们在服务器端写代码手动创建一个 JSESSIONID=....的普通cookie,发向客户端
String id = request.getSession().getId();//拿到该用户的session id
Cookie c = new Cookie("JSESSIONID",id);
c.setMaxAge(60*5);//5分钟
c.setPath(request.getContextPath());
response.addCookie(c);
网页验证码
逻辑示意图: 每个用户都在请求验证码,因此必须放在Session中!!!!
CodeImgServlet.java代码 生成验证码
package cn.hncu.servlet2;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CodeImgServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//☆1☆--相比纯java方式有变化的地方
resp.setContentType("image/jpeg");//设置http响应头---告诉浏览器我现在发的是这个图片格式的数据,你用相应的方式来解析
//定义图片的宽和高
int w=60;
int h=30;
//声明一个RGB格式的内存中的图片
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics();
//把背景变白色
g.setColor(Color.white);
g.fillRect(0, 0, w, h);
//设置字体
g.setFont(new Font("aa",Font.BOLD,18));
//产生并draw出4个随机数字
Random r = new Random();
String sCode="";
for(int i=0;i<4;i++){
int a = r.nextInt(10);//生成0~9之间的随机整数
int y = 15+r.nextInt(20);//产生随机的垂直位置
//产生随机颜色
Color c = new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256));
g.setColor(c);
g.drawString(""+a, i*15, y);
sCode +=a; //生成真正的验证码
}
req.getSession().setAttribute("sCode", sCode);//把验证码标准答案存入session容器
//画几条干扰线
for(int i=0;i<10;i++){
//产生随机颜色
Color c = new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256));
g.setColor(c);
g.drawLine(r.nextInt(60), r.nextInt(30), r.nextInt(60), r.nextInt(30));
}
g.dispose();//类似于IO中的flush(),把图形数据刷到img中
//把内存图片img对象保存到一个jpg文件
ImageIO.write(img, "JPEG", resp.getOutputStream() );//☆2☆
}
}
LoginServlet.java
package cn.hncu.servlet2;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println(" <BODY>");
//获取用户上传参数中的验证码--待测数据
String code = request.getParameter("code");
//获取session中验证码的标准答案
HttpSession session = request.getSession();
String sCode = (String)session.getAttribute("sCode");
session.removeAttribute("sCode");//验证码用过一次就要让它失效,无论这次是否成功
//判断验证码是否正确
if(sCode==null || !sCode.equals(code)){
out.println("验证码输入错误!");
}else{//验证码正确
//把用户名和密码提交给后台数据库去校验----这里简单模拟一下
String nm = request.getParameter("name");
String pwd = request.getParameter("pwd");
if(nm!=null && nm.trim().equals(pwd)){//假设这样算登录成功
out.println("登录成功!");
}else{
out.println("登录失败!");
}
}
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
}
页面和xml
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Cookie-Session技术演示</title>
</head>
<body>
<h2>上一段Cookie技术演示</h2>
<a href="CookieDemo1">Cookie技术演示1</a> <br/>
<a href="servlet/CookieDemo2">该servlet用于演示Cookie的访问权限</a>
<br/><br/>
<a href="LoginServlet">利用Cookie技术显示上次登录的时间</a>
<br/><br/>
<a href="TestCookieNumServlet">测试浏览器支持cookie的数量和长度</a>
<br/><br/>
<a href="jsps/show.jsp">案例:利用cookie记录用户最近访问的图片信息</a>
<br/><br/>
<a href="jsps/cookie.jsp">前端页面中用js来操作cookie技术演示</a>
<br/><br/>
<hr/>
<h2>下一段演示Session技术</h2>
<a href="jsps/contain.jsp"> request, session, application(ServletContext) 这三个容器生命周期对比演示</a>
<br/>
<a href="LogoutServlet">安全退出</a>
<br/><br/>
<script type="text/javascript">
function changeImg(){
var img = document.getElementById("codeImg");
img.src="code?"+new Date().getTime();
}
</script>
<h2>用户注册</h2>
<form action="LoginServlet2" method="post">
姓名:<input type="text" name="name"><br/>
密码:<input type="password" name="pwd"><br/>
验证码:<input type="text" name="code"/><img id="codeImg" src="code"/><a href="javascript:changeImg();">看不清</a><br/>
<input type="submit" value="注册">
</form>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name></display-name>
<servlet>
<servlet-name>CookieDemo1</servlet-name>
<servlet-class>cn.hncu.servlet.CookieDemo1</servlet-class>
</servlet>
<servlet>
<servlet-name>CookieDemo2</servlet-name>
<servlet-class>cn.hncu.servlet.CookieDemo2</servlet-class>
</servlet>
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>cn.hncu.servlet.LoginServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>TestCookieNumServlet</servlet-name>
<servlet-class>cn.hncu.servlet.TestCookieNumServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>ShowServlet</servlet-name>
<servlet-class>cn.hncu.servlet.ShowServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>SaveServlet</servlet-name>
<servlet-class>cn.hncu.servlet2.SaveServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>GetServlet</servlet-name>
<servlet-class>cn.hncu.servlet2.GetServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>LogoutServlet</servlet-name>
<servlet-class>cn.hncu.servlet2.LogoutServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>LoginServlet2</servlet-name>
<servlet-class>cn.hncu.servlet2.LoginServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>CodeImgServlet</servlet-name>
<servlet-class>cn.hncu.servlet2.CodeImgServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CookieDemo1</servlet-name>
<url-pattern>/CookieDemo1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>CookieDemo2</servlet-name>
<url-pattern>/servlet/CookieDemo2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>TestCookieNumServlet</servlet-name>
<url-pattern>/TestCookieNumServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ShowServlet</servlet-name>
<url-pattern>/ShowServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>SaveServlet</servlet-name>
<url-pattern>/SaveServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>GetServlet</servlet-name>
<url-pattern>/GetServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>LogoutServlet</servlet-name>
<url-pattern>/LogoutServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>LoginServlet2</servlet-name>
<url-pattern>/LoginServlet2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>CodeImgServlet</servlet-name>
<url-pattern>/code</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
重写URL技术:当流浪器禁用cookie时,正常的方式就无法建立session,重写URL技术可以完美的解决这个问题。代码如下encodeURL
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Cookie-Session技术演示</title>
</head>
<body>
<h2>request, session, application(ServletContext) 这三个容器生命周期对比演示</h2>
<pre>
request:代表一次请求,每次请求的容器是独立的。
不同的请求之间是无法共享该容器中的数据的。
session:代表一个用户,通常是指同一个浏览器,
该浏览器中的多个请求甚至是多个页面是共享同一个session容器的。
如果浏览器关闭再打开,则是另一个session容器,无法共享到上一次的session。
application:代表一个项目(我们平时理解的一个网站)。
不但是多个请求,甚至是多个用户(浏览器)都是共享该容器。只要Tomcat不关闭,这个容器一直存在。
但如果Tomcat关闭(或项目停止运行)则该容器消亡。
</pre>
<!-- 重写url技术:
解决浏览器禁用cookie,导致浏览器在发出请求时不发送JSESSIONID这个特殊的cookie,
从面出现服务器不认识该session用户,由此造成无法共享session中的信息。
---每次请求都会被服务器当成一个新用户(session)。
重写url技术的本质是: 我们写代码在请求url后面手动加字符串: ";jsessionid=29E4A2378278DAE4"
-->
<!-- 往容器中放值 -->
<!-- 非重写url的方式,,,无法突破浏览器“禁用cookie”的情况
<form action="<%=request.getContextPath()%>/SaveServlet" method="post">
-->
<!-- 重写url的方式 ,,能突破浏览器“禁用cookie”的情况 -->
<%
String url = response.encodeURL( request.getContextPath()+"/SaveServlet" ); //重写url,即在参数(url)后面手动添加";jsessionid=5D787A90163F222827456857608E243D"
System.out.println("url:"+url);
%>
<form action="<%=url%>" method="post">
Name:<input type="text" name="name" /><br/>
<input type="submit"/>
</form>
<br/>
<%
url= response.encodeURL( request.getContextPath()+"/GetServlet" ); //重写url,即在参数(url)后面手动添加";jsessionid=5D787A90163F222827456857608E243D"
%>
<a href="<%=url%>">读取容器中的值</a>
</body>
</html>