目录
四、书城项目四阶段:保持登录状态 | 注册验证码(kaptcha) |注销
会话控制
为什么需要会话控制?
保持用户登录状态,就是当用户在登录之后,会在服务器中保存该用户的登录状态,当该用户后续访问该项目中的其它动态资源(Servlet 或者 Thymeleaf)的时候,能够判断当前是否是已经登录过的。而从用户登录到用户退出登录这个过程中所发生的所有请求,其实都是在一次会话范围之内。保持登录,记住用户名、保存电影的播放进度。
Filter:负责拦截、过滤、放行
Cookie/Session:保持登录状态
一、域对象
1. 应用域的范围:
整个项目部署之后,只会有一个应用域对象,所有客户端都是共同访问同一个应用域对象,在该项目的所有动态资源中也是共用一个应用域对象。
2. 请求域的范围:
每一次请求都有一个请求域对象,当请求结束的时候对应的请求域对象也就销毁了
3. 会话域的范围:
会话域是从客户端连接上服务器开始,客户端关闭,这一整个过程中发生的所有请求都在同一个会话域中;而不同的客户端是不能共用会话域的。
二、Cookie
Cookie (饼干) 是一种客户端的会话技术,它是服务器存放在浏览器的一小份数据,浏览器以后每次访问该服务器的时候都会将这小份数据携带到服务器去。比如:三天免登录、保存电影的播放进度。
第一次发起请求时,在服务器创建Cookie,将Cookie添加到响应对象。通过响应,传递到客户端保存,再次发起请求,浏览器会携带Cookie数据。
相关API
创建一个Cookie对象 (cookie只能保存字符串数据。且不能保存中文)
new Cookie(String name,String value)把cookie传回浏览器
response.addCookie(cookie)获得浏览器带过来的所有Cookie (得到所有的cookie对象。是一个数组,开发中根据key得到目标cookie)
request.getCookies() --->Cookie[]
返回cookie中设置的keycookie.getName()
返回cookie中设置的value
cookie.getValue()设置持久化时间(时效性) — 以秒为单位,如果为-1,cookie将保留到服务器关闭为止。默认情况下Cookie的有效期是一次会话范围内。
cookie1.setMaxAge( int expiry )
设置cookie携带路径 — 向下匹配:设置为 “/hello1”时,“/hello1/hello2”也可以携带
浏览器会使用Cookie的path属性值来和当前访问的地址进行比较,从而决定是否携带这个Cookie。
cookie.setPath()
测试代码
<a href="hello1">访问Cookie01Hello</a> <br>
<a href="hello2">访问Cookie02getCookie</a>
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("----- Cookie01 -----");
//1.创建cookie (不支持中文)
Cookie cookie1 = new Cookie("uname", "zs");
Cookie cookie2 = new Cookie("pwd", "123");
//2.设置时效性 为30秒
//cookie1.setMaxAge(30);
//设置为0,为删除cookie
//cookie1.setMaxAge(0);
//3.设置携带cookie的地址
cookie1.setPath("hello02"); // /向下匹配:hello2/hello3也可以访问
cookie2.setPath("hello02"); // /hello2/hello3也可以访问
//4.将cookie添加到响应对象中
response.addCookie(cookie1);
response.addCookie(cookie2);
response.getWriter().println("Success");
}
获取cookie
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("----- hello02 -----");
//1.获取cookie
Cookie[] cookies = request.getCookies();
//2.判断是否存在
if(cookies!=null){
//迭代,获取value值
for (Cookie cookie : cookies) {
String name = cookie.getName();
String value = cookie.getValue();
System.out.println(name + "--->" + value);
}
}
response.getWriter().println("Success");
}
查看浏览器中存储的Cookie(谷歌为例):
cookie应用:记住密码,三天免登录
应用了使用了 Thymelea 模板引擎。
<a href="user?method=toLogin">访问三天免登录测试</a>
网页:
<form action="user">
<input type="hidden" name="method" value="login">
用户名:<input type="text" name="name" th:value="${unameValue}" > <br>
密码:<input type="text" name="pwd" th:value="${pwdValue}"> <br>
记住密码<input type="checkbox" name="rember"> <br>
<input type="submit">
</form>
public class Cookie04UserServlet extends ModelBaseServlet {
//跳转到登录页面
protected void toLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("---- tpLogin ----");
//1.判断是否请求是否携带cookie,
Cookie[] cookies = request.getCookies();
if(cookies!=null){
//2.遍历cookie集合
for (Cookie cookie : cookies) {
String name = cookie.getName();
String value = cookie.getValue();
//3.如果cookie name值匹配成功,将对应的value值存到请求域中 进行页面渲染
if("uname".equals(name)){
System.out.println(name);
request.setAttribute("unameValue",value);
}
if("pwd".equals(name)){
System.out.println(value);
request.setAttribute("pwdValue",value);
}
}
}
processTemplate("login",request,response);
}
//登录
protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("---- login ----");
//1.获取请求参数
String name = request.getParameter("name");
String pwd = request.getParameter("pwd");
//2.进行用户名密码校验
if("123".equals(name)&&"12345".equals(pwd)){
//3.判断是否点击了复选框: 点击为on 没有点击为null
String rember = request.getParameter("rember");
//4.如果用户选择保存,将数据存储到cookie,将cookie添加到响应对象中
if("on".equals(rember)){
Cookie cookie1 = new Cookie("uname",name);
Cookie cookie2 = new Cookie("pwd",pwd);
cookie1.setMaxAge(60*60*24*3); //时效三天
cookie2.setMaxAge(60*60*24*3);
response.addCookie(cookie1); //将cookie添加到响应对象
response.addCookie(cookie2);
}
response.getWriter().println("登陆成功");
}
}
}
三、Session
Session (会话)是服务器端的会话技术。服务器为每一个浏览器开辟一块内存空间,即session对象。由于每个客户端都有自己的Session会话,我们经常用来保存用户登录之后的信息。
Session的API
创建、获取session
(如果第一次调用的时候其实是创建session,第一次之后通过sessionId找到session进行使用)
request.getSession()
获取值
Object getAttribute(String name)
存储值
void setAttribute(String name, Object value)
移除值
void removeAttribute(String name)
销毁 session
session.invalidate();
设置默认的最大闲置时间 (Tomcat 配置中,不设置默认30分钟)
session.setMaxInactiveInterval( int interval );(单位为秒)Thymelea 中页面渲染 会话域中的值 session
${ session.key }
<span>欢迎你<b th:text="${session.LoginUser.uname}">张总</b></span>
工作原理
-
当第一次调用 request.getSession() 创建了Session对象,底层会自动创建一个Cookie,存储 session 的卡号信息,再次发起请求时会携带这个cookie
-
每一次请求都会携带这个cookie,当到达服务器后,会将请求携带的卡号与已经存在的session卡号进行对比,如果相同则返回已经存在的session。
四、书城项目四阶段:保持登录状态 | 注册验证码(kaptcha) |注销
//注册方法
protected void regist (HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("------ regist ------");
//1.获取表单输入的参数
Map<String, String[]> Map = request.getParameterMap();
try {
//2.1获取页面输入的验证码
String verify = request.getParameter("verify");
//2.2获取session域中的验证码
HttpSession session = request.getSession();
String kaptcha = (String) session.getAttribute("KAPTCHA_SESSION_KEY");
//2.3比较输入的验证码是否匹配
if(kaptcha.equalsIgnoreCase(verify)){
//3.封装为对象,调用业务层尝试注册
User user = new User();
BeanUtils.populate(user, Map);
UserService userService = new UserServiceImpl();
userService.registUser(user);
//4.1.注册成功,创建Session对象 (待验证 自定义功能)
/*HttpSession session = request.getSession();*/
//4.2.将登陆成功的对象存储到session中
session.setAttribute("LoginUser",user);
//5.完成注册,调用跳转注册成功页面方法
response.sendRedirect(request.getContextPath()+"/user?method=toRegistSuccess");
}else {
throw new RuntimeException("输入的验证码不正确!");
}
} catch (Exception e) {
e.printStackTrace();
//3.1发生异常则注册失败,将异常信息添加到请求域,返回注册页面
request.setAttribute("msg",e.getMessage());
Object msg = request.getAttribute("msg");
processTemplate("user/regist", request, response);
}
}
//登录方法
private void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("------ Login ------");
try {
Map<String, String[]> map = request.getParameterMap();
User user = new User();
BeanUtils.populate(user,map);
UserServiceImpl userService = new UserServiceImpl();
User u = userService.login(user);
//1.创建Session对象
HttpSession session = request.getSession();
//2.将登陆成功的对象存储到session中
session.setAttribute("LoginUser",user);
//重定向到登陆成功
response.sendRedirect(request.getContextPath()+"/user?method=toLoginSuccess");
} catch (Exception e) {
e.printStackTrace();
// response.getWriter().println("登陆失败"+e.getMessage());
//向请求域内添加登陆失败的信息
request.setAttribute("msg", e.getMessage());
//如果登陆失败 重新回到登陆界面
processTemplate("user/login", request, response);
}
}
//退出登录
private void loginOut(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("----- loginOut -----");
//1.获取Session
HttpSession session = request.getSession();
//2.移除登录的用户信息
session.removeAttribute("LoginUser");
//3.跳转到登录页面
response.sendRedirect(request.getContextPath()+"/user?method=toLoginPage");
}
首页页面(部分)
<div class="topbar-right" th:if="${session.LoginUser==null}">
<!--页面跳转-->
<a href="user?method=toLoginPage" class="login">登录</a> <!--修改-->
<a href="user?method=toRegistPage" class="register">注册</a>
<a href="book?method=toBookManager" class="admin">后台管理</a>
</div>
<!--登录后风格-->
<div class="topbar-right" th:if="${session.LoginUser!=null}">
<span>欢迎你<b th:text="${session.LoginUser.uname}">用户名</b></span>
<!--注销-->
<a href="user?method=loginOut" class="register">注销</a>
<a
href="pages/cart/cart.jsp"
class="cart iconfont icon-gouwuche
">
页面效果: