目录
session会话
理解会话机制
Servlet中对Cookie和Session提供的
HttpServletrequest类中的方法:
模拟实现登录功能
首先实现功能分为两个界面:
(1)登录页面代码(前端代码)
(2) 编写LoginServlet处理上述登录请求
登录http请求格式如下:
LoginServlet代码:
验证用户登录要做的几个步骤:
编写主页的Servlet(登录成功之后跳转到的页面)
index页面需要做的几个步骤:
登录功能运行效果:
session会话是否会持久化保存?
前言
虽然大部分客户端的数据都是从服务器中请求的,但是还有一小部分数据为了减轻服务器的负担,这一部分数据可以在浏览器本地中进行数据存储,如果此时的数据需要本地存储,是否可以直接写入硬盘呢,答案是否定的,如果允许网站直接把数据写入硬盘,此时有一些恶意网站就可能攻击客户端,把硬盘上的数据弄丢。
所以引入了cookie机制,这种机制是可以把数据写入一些特定的文件的。
此时身份标识如何分配,以及用户的身份信息如何具体存储(是需要服务器支持的),所以就有了Session(会话机制),通过Cookie和Session的配合,来完成本地数据的存储。
首先类比到医院看病的例子,如果去医院看病,此时就需要以下的步骤:
1. 到医院后先挂号,此时就得到了一张就诊卡,这个就诊卡就是Cookie,里边有一个令牌,就是session。 |
2. cookie中存储了这个令牌(你的身份标识)。 |
3. 后续去各个科室检查,开药,先刷就诊卡,就诊卡存储的是医生开的药,需要检查的项目。 |
4. 注:这个就诊卡中,只是存储了身份标识,此时你需要检查的项目,开的药方,都是根据就诊卡中的这个标识存储在医院的数据库中的,这个令牌(session)只是存储了你的身份标识。 |
cookie是浏览器在本地存储数据的一种机制。cookie中存储了用户表示用户身份的一些信息。
cookie从哪里来? | cookie是从服务器来,携带的数据就是用户需要在浏览器中保存的本地的数据,在响应中会带有Set-Cookie字段,通过这个字段就把本地数据返回给客户端。 |
cookie到哪去? | cookie先是从服务器中把需要本地存储的数据传给客户端,之后客户端访问浏览器时就把本地的所有cookie通过http请求带给服务器。 |
cookie的作用 | 最典型的应用就是用cookie保存当前用户的登录状态。 |
如上图所示;这个令牌就是在cookie中保存的,Cookie用于保存用户身份标识,这样的场景中,身份标识如何分配,以及身份标识信息具体时如何进行存储的,都是需要服务器支持的。
Session(会话)就是服务器用来实现用户身份区分的一种机制,通常是和Cookie搭配使用。
1. 首先给当前用户分配一个sessionId,同时记录下当前用户的一些身份信息(可以是自定义的) |
2. sessionId就会被返回到浏览器的Cookie中,后续浏览器访问服务器时,就会带着sessionId。 |
3. 此时服务器就可以通过这个sessionId识别当前用户的身份了。 |
服务器同一时刻收到的请求是很多的,同一时刻服务器需要处理不同客户端发来的不同的请求,此时服务器就需要清楚的区分每个请求是属于哪一个用户的,就需要服务器记录每个用户令牌以及用户信息的对应关系。
Session会话本质就是一个“哈希表”,存储了一些键值对结构,key就是令牌的id,value就是用户信息(用户信息是自定义的,灵活设计的)
注:Session会话中的key必须是String类型,value是Object类(value可以是任意类型)。
getSession方法的使用:
getSession()中有一个参数,是boolean类型的,
1. 如果参数为false,getSession的行为是:
(1)读取cookie中的sessionId |
(2)在服务器中根据sessionId来查询对应的session对象 |
(3)如果查到了直接返回这个session对象,如果没有查到则返回null |
2. 如果参数为true,getSession的行为是:
(1)读取请求中cookie中的sessionId |
(2)在服务器中根据sessionId来查询对应的session对象 |
(3)如果查到了,直接返回这个session对象 |
(4)如果没有查到,就会创建一个session对象,同时生成一个sessionId,以sessionId为key,session对象为value,把这个键值对鵆到服务器中的一个hash表中,同时把sessionId以 Set-Cookie的方式返回给浏览器 |
注:如果参数为true,此时允许创建session对象,如果参数为false,此时不允许创建session对象。
1. 登录页(包含两个输入框,输入用户名密码,以及一个登录按钮) | 点击登录按钮,就会发出一个http请求,服务器处理这个请求时会验证用户名和密码,如果用户名和密码都正确,就会跳转到主页。 |
2. 主页(只会显示当前登录的用户的用户名)(欢迎xxx) | 其中,登录页就是一个html页面,还需要写一个Servlet,实现登陆时候用户名的密码校验,最后需要写一个Servlet 来生成主页(点击登录之后,跳转到主页中)。 |
/* form会组织用户输入的用户名和密码这部分数据以键值对的形式提交给服务器,
其中 key 就是 input 的 name 属性
其中 value 就是input 的 用户输入的内容
最终会构造一个post请求,在body 中以键值对(类似query string)的格式进行数据的组织
*/
登录页面
POST /login(一般的登录请求都是post方法,就是向服务器提交一个什么样的数据) |
Content-Type: application/x-www-form-unlencoded(请求的数据是以form表单的形式进行提交的) |
username=zhangsan&passsword=123(这部分就是在url中携带的要交给服务器的数据) |
package login;
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("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.先从请求中拿到用户名和密码
//为了保证读出来的参数也能支持中文,要记得设置编码方式是 utf8
req.setCharacterEncoding("utf8");
String username = req.getParameter("username");
String password = req.getParameter("password");
//2.验证用户名和密码是否正确
if (username == null || password == null || username.equals("") || password.equals("")) {
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("当前输入的用户名和密码不能为空!");
return;
}
//此处假设用户名只能是 zhangsan 或者是 lisi,密码都是123
if (!username.equals("zhangsan") && !username.equals("lisi")) {
//用户名有问题
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("用户名或者密码有误!");
return;
}
if (!password.equals("123")) {
//密码有问题
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("用户名或者密码有误");
return;
}
//3. 用户名和密码都ok,此时就创建一个session会话,因为用户刚开始登录的时候是没有sessionId的
//当前用户是未登录的状态,此时请求的cookie没有sessionId
//此处的getSession是无法从服务器的 哈希表中查村到 该session对象的
//此处的参数是设为true,是允许在getSession在查询不到的时候,创建新的session和sessionId的
//并且会把这个session对象和sessionId 存储到哈希表中
//同时返回这个session对象,并且在后续的响应中自动把这个sessionId返回给客户端浏览器
HttpSession session = req.getSession(true);
//然后让刚创建好的session对象存储自己写的自定义的数据,就可以在这个对象中存储用户的身份信息
session.setAttribute("username",username);
//session对象本身可以看成一个哈希表,可以存储键值对,key必须是String类型的,值是object类型的
//4.登录成功之后,自动跳转到index主页
resp.sendRedirect("index");
}
}
1. 读取用户名和密码(先拿到用户名和密码才能验证数据是否是正确的) |
2. 验证用户民密码是否正确(正常的登录程序药用数据库进行查询的,此处只是简单的约定用户名只能是zhangsan 或者 lisi,密码都是123) |
3. 创建会话,保存必要的用户信息(因为此时是用户第一次进行登录,所以getSession中的参数药设置为true,允许创建一个会话,保存用户的登录信息) |
4. 重定向(如果用户名和密码都是ok的,此时就跳转到另一个html界面,告知用户 “欢迎xxx”,此时用户就知道登录成功了),这个跳转页面就是用响应的重定向实现的。 |
package login;
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;
//这个Servlet用来动态的生成主页面
@WebServlet("/index")
public class IndexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//此处禁止创建会话,如果没找到,用户就是未登录状态
//如果找到了才认为是登录状态
//这里和前边的创建session不一样,这里的目的只能是查询
//要想创建,就必须是登录成功之后才能创建
//此处浏览器跳转到这个界面,没有登录也不能创建session了
HttpSession session = req.getSession(false);
if (session == null) {
//当前是未登录状态
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("当前用户未登录!");
return;
}
//此时如果有session了并且登录成功了,就把这个username拿到
//此时这个session和刚才未登录时创建的session时同一个对象,这因为sessionId是一样的
//这里得到的username对应的value是object类型,需要强转成String类型
String username = (String) session.getAttribute("username");
if (username == null) {
//虽然有session对象,但是里面没有必要的属性,我们也认为是登录状态异常
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("当前用户未登录!");
return;
}
//如果上述的校验都是ok的,此时就生成一个动态的页面
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("欢迎你!" + username);
}
}
1. 跳转之后首先验证用户的身份(如果登录过,在登录时就会创建一个session),所以跳转页面不可以创建会话,只能是拿着这个session去服务器中查询,如果没有找到session则认为是未登录状态。 |
2. 如果找到了,就是登录状态,之后根据查到的session(此时这个session和刚才创建的session是一个session对象)拿到刚才登陆时存储的用户名。 |
3. 根据用户名在跳转之后的页面中返回一个响应。(欢迎xxx) |
注:刚才创建的session对象和登录之后查询的session对象是同一个对象,因为此时是同一个sessionId,刚才登录成功之后,sessionId会通过Set-Cookie返回给浏览器,浏览器下次访问IndexServlet的时候,就会带上这个同一个的sessiuonId,然后Indexservlet中拿着这个sessionId再查询,就查到了同一个session对象。
session会话不会一直存在,比如:服务器重启之后,原来hash表中的内容就没有了,此时再次访问,就会出现sessionId没有查询到,此时会被识别成“未登录状态”。
服务器默认保存会话,是在内存中的,一旦重启服务器,此时会话的数据就没了。
但是Smart Tomcat 例外,为了方便程序猿调试,它会在停止服务器时,把会话持久化保存,并且在下次启动的时候,自动把会话恢复到内存中。(此时会话是不会丢失的,但是这个流程是否生效和tomcat的版本是有关的)
但是如果是手动部署程序到Tomcat,则默认会话还是在内存中进行保存的,重启会丢失会话。