会话技术
可以简单理解为:浏览器打开到关闭就是一次会话
session和cookie可以实现会话跟踪技术,功能有重叠一般结合使用
session和cookie结合使用的例子:用户访问浏览器,服务器生成JESSIONID,JESSIONID是一个cookie,每次http请求会携带此cookie,用来让服务器知道选择哪个session,即JESSIONID相当于session的id。(因为服务器中存这好多用户的会话session),这个过程由服务器自动完成。
会话技术可以:记住浏览的商品,可以识别用户,可以实现会话时间内免登录
Cookie
简单使用:
//设置response的编码
response.setContentType("text/html;charset=UTF-8");
//创建Cookie对象,指定名称和值
Cookie cookie = new Cookie("username", "zhongfucheng");
//向浏览器给一个Cookie
response.addCookie(cookie);
response.getWriter().write("我已经向浏览器发送了一个Cookie");
cookie存储中文
- 中文属于Unicode字符,英文数据ASCII字符,中文占4个字符或者3个字符,英文占2个字符。
- 解决:Cookie使用Unicode字符时需要对Unicode字符进行编码负责出现异常。
response.setContentType("text/html;charset=UTF-8");
PrintWriter printWriter = response.getWriter();
String name = "中国";
//对Unicode字符进行编码
Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8"));
cookie.setMaxAge(2000);//存在了硬盘上
response.addCookie(cookie);
printWriter.write("我颁发了一个Cookie,值保存的是中文数据");
取出时进行解码:
Cookie[] cookies = request.getCookies();
for (int i = 0; cookies != null && i < cookies.length; i++) {
String name = cookies[i].getName();
//经过URLEncoding就要URLDecoding
String value = URLDecoder.decode(cookies[i].getValue(), "UTF-8");
printWriter.write(name + "------" + value);
}
cookie有效期
Cookie的有效期是通过setMaxAge()来设置的。
- 如果MaxAge为正数,浏览器会把Cookie写到硬盘中,只要还在MaxAge秒之前,登陆网站时该Cookie就有效【不论关闭了浏览器还是电脑】
- 如果MaxAge为负数,Cookie是临时性的,仅在本浏览器内有效,关闭浏览器Cookie就失效了,Cookie不会写到硬盘中。Cookie默认值就是-1。这也就为什么在我第一个例子中,如果我没设置Cookie的有效期,在硬盘中就找不到对应的文件。
- 如果MaxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie对应的方法,把MaxAge设置为0等同于删除Cookie
cookie的删除和修改
我们已经知道了Cookie机制没有提供删除Cookie的方法。其实细心点我们可以发现,Cookie机制也没有提供修改Cookie的方法。那么我们怎么修改Cookie的值呢?
Cookie存储的方式类似于Map集合
修改:
Cookie的名称相同,通过response添加到浏览器中,会覆盖原来的Cookie
删除:
除了名称相同外,设置setMaxAge(0)为零
String name = "看完博客就点赞";
//对Unicode字符进行编码
Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8"));
//一定不要忘记添加到浏览器中
cookie.setMaxAge(0);
response.addCookie(cookie);
printWriter.write("我删除了该Cookie");
- 注意:删除,修改Cookie时,新建的Cookie除了value、maxAge之外的所有属性都要与原Cookie相同。否则浏览器将视为不同的Cookie,不予覆盖,导致删除修改失败!
Cookie的domain
- Cookie的隐私安全机制决定Cookie是不可跨域名的。也就是说
www.baidu.com
和www.google.com
之间的Cookie是互不交接的。即使是同一级域名,不同二级域名也不能交接,也就是说:www.goole.com
和www.image.goole.com
的Cookie也不能访问 - 现在我希望一级域名相同的网页Cookie之间可以相互访问。也就是说
www.image.zhongfucheng.com
可以获取到www.zhongfucheng.com
的Cookie就需要使用到domain方法。
Cookie cookie = new Cookie("name", "ouzicheng");
cookie.setMaxAge(1000);
cookie.setDomain(".zhongfucheng.com");
response.addCookie(cookie);
printWriter.write("使用www.zhongfucheng.com域名添加了一个Cookie,只要一级是zhongfucheng
Cookie的path
- 一般地,Cookie发布出来,整个网页的资源都可以使用。现在我只想Servlet1可以获取到Cookie,其他的资源不能获取。
- 使用Servlet2颁发一个Cookie给浏览器,设置路径为"/Servlet1"。
Cookie cookie = new Cookie("username", "java");
cookie.setPath("/Servlet1");
cookie.setMaxAge(1000);
response.addCookie(cookie);
printWriter.write("该Cookie只有Servlet1获取得到");
cookie应用
详情查看3y的github
1. 记录上次访问时间
先检查(遍历)所有Cookie有没有我要的,如果得不到我想要的Cookie,Cookie的值是null,那么就是第一次登陆
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
response.setContentType("text/html;charset=UTF-8");
PrintWriter printWriter = response.getWriter();
//获取网页上所有的Cookie
Cookie[] cookies = request.getCookies();
//判断Cookie的值是否为空
String cookieValue = null;
for (int i = 0; cookies != null && i < cookies.length; i++) {
//获取到以time为名的Cookie
if (cookies[i].getName().equals("time")) {
printWriter.write("您上次登陆的时间是:");
cookieValue = cookies[i].getValue();
printWriter.write(cookieValue);
cookies[i].setValue(simpleDateFormat.format(new Date()));
response.addCookie(cookies[i]);
//既然已经找到了就可以break循环了
break;
}
}
//如果Cookie的值是空的,那么就是第一次访问
if (cookieValue == null) {
//创建一个Cookie对象,日期为当前时间
Cookie cookie = new Cookie("time", simpleDateFormat.format(new Date()));
//设置Cookie的生命期
cookie.setMaxAge(20000);
//response对象回送Cookie给浏览器
response.addCookie(cookie);
printWriter.write("您是第一次登陆啊!");
}
2. 记录浏览的商品
session
如果说Cookie是检查用户身上的”通行证“来确认用户的身份,那么Session就是通过检查服务器上的”客户明细表“来确认用户的身份的。Session相当于在服务器中建立了一份“客户明细表”
session使用
存:
//得到Session对象
HttpSession httpSession = request.getSession();
//设置Session属性
httpSession.setAttribute("name", "看完博客就要点赞!!");
取:
//获取到从Servlet4的Session存进去的值
HttpSession httpSession = request.getSession();
String value = (String) httpSession.getAttribute("name");
System.out.println(value);
session 生命周期和有效期
-
一个session存在于浏览器打开到关闭的时间内,且session还有setMaxInactiveInterval来设置其存活时间。如果关闭浏览器,或者新打开其他浏览器,原来的session都会失效,因为session通过jESESSIONID来区分session,而Jessionid的MaxAge为负数,即浏览器关闭就失效。
现在问题来了:服务器是如何实现一个session为一个用户浏览器服务的?换个说法:为什么服务器能够为不同的用户浏览器提供不同session? HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一个用户。于是乎:服务器向用户浏览器发送了一个名为JESSIONID的Cookie,它的值是Session的id值。其实Session依据Cookie来识别是否是同一个用户。 简单来说:Session 之所以可以识别不同的用户,依靠的就是Cookie 该Cookie是服务器自动颁发给浏览器的,不用我们手工创建的。该Cookie的maxAge值默认是-1,也就是说仅当前浏览器使用,不将该Cookie存在硬盘中
设置session超时时间的三种方式
方式一:tomcat/conf/web.xml修改
对所有的WEB应用都有效
<session-config>
<session-timeout>20</session-timeout>
</session-config>
方式二:单个的web.xml文件中设置
对单个web应用有效如果有冲突,以自己的web应用为准。
<session-config>
<session-timeout>20</session-timeout>
</session-config>
方式三:通过setMaxInactiveInterval()方法设置
//设置Session最长超时时间为60秒,这里的单位是秒
httpSession.setMaxInactiveInterval(60);
System.out.println(httpSession.getMaxInactiveInterval());
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q6fRPCRD-1607248393486)(C:\Users\hello\AppData\Roaming\Typora\typora-user-images\image-20201106222218876.png)]
session应用
1.购物
- 将已经购买的商品添加到,session中,添加多个session开销大,直接添加一个List为session,因为session不仅可以存字符串也可以存对象。
- 详细过程见3yhttps://segmentfault.com/a/1190000013130309
禁用cookie,session可使用吗?
我们知道Session 之所以可以识别不同的用户,依靠的就是Cookie(jessionid)
肯定不能正常使用了,但是有解决方法嘛?
有!URL地址重写
HttpServletResponse类提供了两个URL地址重写的方法:
- encodeURL(String url)
- encodeRedirectURL(String url)
URL地址重写的原理:将Session的id信息重写到URL地址中。服务器解析重写后URL,获取Session的id。这样一来,即使浏览器禁用掉了Cookie,但Session的id通过服务器端传递,还是可以使用Session来记录用户的状态。
String url="/kan";
resp.sendRedirect(resp.encodeURL(url));
2.session 防止表单重复提交
-
前端设置标志位,可以防止表单重复点击提交
-
刷新和后退再提交,无法通过前端防止,应该通过session
-
(没看太懂)
html> <head> <meta content="text/html" charset="UTF-8" /> <title>$Title$</title> </head> <body> <form action="/tt"> 姓名: <input type="text" name="name"> <input type="hidden" name="token" value="${token}"> <input value="提交" type="submit"> </form> </body> </html>
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { TokenProcessor tokenProcessor=TokenProcessor.getInstance(); String token=tokenProcessor.makeToken(); req.getSession().setAttribute("token",token); //resp.sendRedirect("/index.jsp"); req.getRequestDispatcher("/index.jsp").forward(req,resp); }
import sun.misc.BASE64Encoder; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Random; public class TokenProcessor { private final static TokenProcessor tokenProcessor =new TokenProcessor(); public static TokenProcessor getInstance(){ return tokenProcessor; } public String makeToken(){ String token=String.valueOf(System.currentTimeMillis()+new Random().nextInt(9999)); MessageDigest messageDigest= null; try { messageDigest = MessageDigest.getInstance("md5"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } byte[] md5 = messageDigest.digest(token.getBytes()); //如果我们直接 return new String(md5)出去,得到的随机数会乱码。 //因为随机数是任意的01010101010,在转换成字符串的时候,会查gb2312的码表,gb2312码表不一定支持该二进制数据,得到的就是乱码 //于是乎经过base64编码成了明文的数据 BASE64Encoder base64Encoder = new BASE64Encoder(); return base64Encoder.encode(md5); } }
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String serverValue = (String) req.getSession().getAttribute("token"); String clientValue = req.getParameter("token"); if (serverValue != null && clientValue != null && serverValue.equals(clientValue)) { System.out.println("处理请求"); //清除Session域对象数据 req.getSession().removeAttribute("token"); }else { System.out.println("请不要重复提交数据!"); } }
3.一次性校验
- 一次性校验码其实就是为了防止暴力猜测密码
- 思路:生成验证码后,把验证码的数据存进Session域对象中,判断用户输入验证码是否和Session域对象的数据一致
- 只需要在处理购买页面上创建Cookie,Cookie的值是Session的id返回给浏览器即可
Cookie cookie = new Cookie("JSESSIONID",session.getId());
cookie.setMaxAge(30*60);
cookie.setPath("/ouzicheng/");
response.addCookie(cookie);
止暴力猜测密码**
- 思路:**生成验证码后,把验证码的数据存进Session域对象中,判断用户输入验证码是否和Session域对象的数据一致**
[外链图片转存中...(img-Z8UYdcQu-1607248393492)]
[外链图片转存中...(img-Iq8UqE6g-1607248393495)]
- 只需要在处理购买页面上创建Cookie,Cookie的值是Session的id返回给浏览器即可
Cookie cookie = new Cookie("JSESSIONID",session.getId());
cookie.setMaxAge(30*60);
cookie.setPath("/ouzicheng/");
response.addCookie(cookie);