1 HTTP协议
是一个无状态协议,所谓的无状态协议,是指上一次的请求和当前的请求之间没有任何的联系,无法共享数据。
会话技术概述
为了能够让多次请求之间可以共享数据,需要提供一门新的技术,这门技术就是会话技术
会话技术,就是为了实现某个功能,在浏览器和服务器建立连接之后,发送多次请求和响应可以共享数据,直到浏览器关闭,发送多次请求和多次响应都属于一次会话
2 会话技术—cookie
3 会话技术—session
概述
由于数据存储在浏览器安全性较差,所以考虑把数据存储在服务器中,提升数据的安全性。
将数据存储在服务器中这门技术—会话技术,就是session会话技术
3.1 session的原理
在浏览器访问服务器,如果有session对象创建的代码执行,则会在服务器其中创建一个session对象,这个session对象可以存储浏览器的数据,为多个浏览器创建多个单独的session对象,这些对象通过sessionID来进行区分。
session是一个基于Cookie工作的对象。本质是个cookie。浏览器中会保存sessionID,存储session对象的ID。
3.2session对象的创建
request.getSession();//如果当前服务器中没有当前浏览器的session对象,则会立刻创建一个session对象,如果有这个当前的session对象直接拿过来使用。
request.getSession(true);//如果当前服务器没有当前浏览器的session对象,则会立刻创建session对象,如果有这个当前的session对象直接拿过来使用。
request.getSession(false);//如果当前服务器中没有当前浏览器的session对象,则会返回一个null值,如果有这个当前session对象直接拿过来使用。
3.3session特点
服务器端技术,数据存储在服务器,安全性较高。擅长存储短时间的数据
功能一:作为域对象使用
域对象:如果一个对象身上有一个被看见的范围,在这个范围之内利用对象身上的map实现数据共享,对象就是域对象。
使用API
setAttribute(String name,Object obj);
getAttribute(String name);
removeAttribute(String name);
getAttributeNames();
生命周期
request.getSession();调用的时候,session对象创建,生命周期开始。
a.自杀:主动调用session.invalidate()方法释放对象。
b.意外身亡:在服务器中存有session对象,服务器意外关闭,session对象会被立刻销毁。如果服务器正常关闭,session对象里有数据,这个session就会被序列化到磁盘上—钝化 ,当服务器重启时会从之前磁盘已经序列化好的信息读取进来—活化
c.超时死亡:如果一个session兑现超过了30分钟未被使用,会被服务器自动销毁。这个超时的时间可以通过web.xml来设置
以上三种方式都会让session对象销毁,生命周期结束
作用范围:整个会话
作用范围:整个会话
作用范围:整个会话
代码实现:
package cn.tedu.session;
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;
import java.io.IOException;
@WebServlet("/SessionDemo1")
public class SessionDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取session对象--域对象
HttpSession session = request.getSession();
//设置域属性---共享数据
session.setAttribute("name","朴老师");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
在这里插入代码片
package cn.tedu.session;
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;
import java.io.IOException;
@WebServlet("/SessionDemo2")
public class SessionDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取session对象
HttpSession session = request.getSession();
//获取域属性的值
System.out.println("name:"+session.getAttribute("name"));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
实现简易的购物车来付账
修改index.jsp页面:
<%--
Created by IntelliJ IDEA.
User: tedu
Date: 2020/12/3
Time: 9:34
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>购物车</title>
</head>
<body>
<%--添加商品信息--%>
<a href="<%=request.getContextPath()%>/BuyServlet?prod=小米手机"
>小米手机</a>
<a href="<%=request.getContextPath()%>/BuyServlet?prod=拖鞋"
>拖鞋</a>
<a href="<%=request.getContextPath()%>/BuyServlet?prod=电脑"
>电脑</a>
<a href="<%=request.getContextPath()%>/BuyServlet?prod=大腰子"
>大腰子</a>
<a href="<%=request.getContextPath()%>/BuyServlet?prod=火龙果"
>火龙果</a>
<a href="<%=request.getContextPath()%>/PayServlet"
>付款</a>
</body>
</html>
新建BuyServlet:
package cn.tedu.session;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
@WebServlet("/BuyServlet")
public class BuyServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.乱码
//request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//2.获取请求参数
String prod = request.getParameter("prod");
prod = new String(prod.getBytes("iso8859-1"),
"utf-8");
//3.创建session对象
HttpSession session = request.getSession();
//关闭浏览器也可以通过使用上一次会话的JSESSIONID来找到对应session对象
//通过session对象来获取JSESSIONID
Cookie cookie=new Cookie("JSESSIONID",session.getId());
cookie.setMaxAge(60*60*24);
cookie.setPath(request.getContextPath()+"/");
response.addCookie(cookie);
//4.设置域属性
session.setAttribute("prod",prod);
//5.在浏览器中显示商品已经加入购物车
response.getWriter().write("恭喜,商品["+prod+"]已经添加到购物车");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
新建PayServlet
package cn.tedu.session;
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;
import java.io.IOException;
@WebServlet("/PayServlet")
public class PayServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//1.创建session对象
HttpSession session = request.getSession();
//2.获取域属性
Object prod = session.getAttribute("prod");
//3.在浏览器显示已经为商品付款
if(prod!=null){
response.getWriter().write("已为商品["+prod+"]付款$10000");
}else{
response.getWriter().write("您尚未选择任何商品");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
记住用户名
1.导入登录页面
2.修改_head.jsp页面
<divid="content">
<ahref="<%=request.getContextPath()%>/login.jsp">登录</a> |
<ahref="<%=request.getContextPath()%>/regist.jsp">注册</a>
</div>
3.修改login.jsp页面
<form action="<%=request.getContextPath()%>/LoginServlet"method="POST">
<table>
<%
/*获取后台(服务器发送cooki)*/
//把所有的cookie存放到数组中
Cookie[]cookies=request.getCookies();
//扩大cookie对象身上值的使用范围
Stringusername="";
//遍历数组,查找指定cookie
if(cookies!=null){
for(Cookiec:cookies){
//判断是否是指定的cookie(通过cookie名称来判断)
if("remname".equals(c.getName())){
//把cookie对象上的值赋值给username
username=c.getValue();
}
}
}
%>
<tr>
<%--回显cookie里存放用户名--%>
<td><inputtype="text"name="username"value="<%=username%>"/></td>
<inputtype="checkbox"name="remname"value="true"
<%--只有拿到了上一次勾选上记住用户名的cookie信息才能回显勾选--%>
<%="".equals(username)?"":"checked='checked'"%>
/>记住用户名
4.新建LoginServlet
package com.easymall.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.乱码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//2.获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String remname = request.getParameter("remname");
//3.记住用户名
//判断记住用户名是否打勾(已勾选)
if("true".equals(remname)){
//进了判断说明已勾选
//设置cookie信息
//创建cookie对象
//remname作为cookie对象的名称,username作为cookie对象的值
Cookie cookie=new Cookie("remname",username);
//设置最大生命时长
cookie.setMaxAge(60*60*24);
//设置有效路径
cookie.setPath(request.getContextPath()+"/");
//发送cookie(响应到浏览器)
response.addCookie(cookie);
}
//4.JDBC连接数据验证用户名和密码是否存在
//5.登录成功,跳转到首页
response.sendRedirect(request.getContextPath());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
5.cookie中文乱码的问题
在存储cookie时,通过URLEncoder.encode(String str,String enc));设置码表
Cookiecookie=newCookie("remname",URLEncoder.encode(username,"utf-8"));
在获取cookie时,通过URLDecoder.decode(String str,String enc);
username=URLDecoder.decode(c.getValue(),"utf-8");
登录功能实现
保存用户的登录状态,将用户名存放到某个域(域对象)中在需要的位置取出即可,认为是登录状态
request 范围太小
servletContext 范围太大
session 范围适中
修改LoginServlet
//4.JDBC连接数据验证用户名和密码是否存在
Connectionconn=null;
PreparedStatementps=null;
ResultSetrs=null;
try{
conn=JDBCUtiles.getConnection();
ps=conn.prepareStatement
("select*fromuserwhereusername=?andpassword=?");
ps.setString(1,username);
ps.setString(2,password);
rs=ps.executeQuery();
if(rs.next()){
//进了判断说明用户名和密码匹配
//保留用户的登录状态
//创建session对象
HttpSessionsession=request.getSession();
//设置域属性来共享数据
session.setAttribute("username",username);
}else{//用户名或者密码不正确
request.setAttribute("msg","用户名或者密码不正确");
//请求转发
request.getRequestDispatcher("/login.jsp")
.forward(request,response);
return;
}
}catch(SQLException|ClassNotFoundExceptione){
e.printStackTrace();
}
//5.登录成功,跳转到首页
response.sendRedirect(request.getContextPath());
前台_head.jsp页面回显用户名
<%
//判断是否有session对象,并且对象中是否包含名称为username的域属性
if(request.getSession(false)!=null
&&request.getSession().getAttribute("username")!=null){
%>
<ahref="#">欢迎,<%=request.getSession().getAttribute("username")%>回来</a> |
<ahref="<%=request.getContextPath()%>/LogoutServlet">登出</a>
<%
}else{//不需要保留用户登录状态,直接展示登录和注册
%>
<ahref="<%=request.getContextPath()%>/login.jsp">登录</a> |
<ahref="<%=request.getContextPath()%>/regist.jsp">注册</a>
<%
}
%>
新建LogoutServlet
packagecom.easymall.servlet;
importjavax.servlet.ServletException;
importjavax.servlet.annotation.WebServlet;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importjava.io.IOException;
@WebServlet("/LogoutServlet")
publicclassLogoutServletextendsHttpServlet{
protectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{
//判断是否有session对象
if(request.getSession(false)!=null){
//自杀
request.getSession().invalidate();
}
//跳转到主页---重新判断
response.sendRedirect(request.getContextPath());
}
protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{
doPost(request,response);
}
}
实现验证码
创建验证码工具类,从课前资料导入(如果出现乱码把内容粘贴过来)
把main方法注释掉
修改regist.jsp页面
<tr>
<tdclass="tds">验证码:</td>
<td>
<inputtype="text"name="valistr"/>
<imgid="img"src="<%=request.getContextPath()%>/ValistrServlet"width=""height=""alt=""/>
<span></span>
</td>
</tr>
//添加验证码的图片点击事件
$("#img").click(function(){
vardate=newDate();
vartime=date.getTime();
$(this).attr("src","<%=request.getContextPath()%>/ValistrServlet?time="+time);
});
新建ValistrServlet
packagecom.easymall.servlet;
importcom.easymall.utiles.VerifyCode;
importjavax.servlet.ServletException;
importjavax.servlet.annotation.WebServlet;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importjava.io.IOException;
@WebServlet("/ValistrServlet")
publicclassValistrServletextendsHttpServlet{
protectedvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{
//控制不使用缓存
response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("pragma","no-cache");
//生成验证码图片
VerifyCodevc=newVerifyCode();
//把图片输出到前台浏览器的验证码图片框
vc.drawImage(response.getOutputStream());
//获取验证码的字符内容
Stringcode=vc.getCode();
//把验证码内容存放到session域属性身上来进行共享
HttpSessionsession=request.getSession();
session.setAttribute("valistr",code);
}
protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{
doPost(request,response);
}
}
修改RegistServlet来验证验证码是否正确
//验证码是否正确
//获取域属性的值---验证码的值
Stringvalistr1=(String)request.getSession().
getAttribute("valistr");
//判断输入的验证码的内容和获取的session域属性的验证码的值是否一致
if(valistr!=""&&!valistr.equalsIgnoreCase(valistr1)){
//域对象设置域属性(共享数据)
request.setAttribute("msg","验证码不正确");
//请求转发---把数据共享到jsp页面
request.getRequestDispatcher("/regist.jsp")
.forward(request,response);
//此处进行非空验证,后续代码不能继续执行
return;
}