前言
这一节主要讲会话跟踪技术
1.补充
为了提交Gitee我修改了模块的目录,就是移动了模块,导致模块不是Maven了,可以在右边的Maven小工具,点加号,把模块重新添加为Maven
2. 概述
3. Cookie
3.1 基本使用
//发送cookie//1.创建cookie对象Cookie cookie=new Cookie("username","zs");//2.发送response.addCookie(cookie);
怎么看cookie来的数据呢,
点设置
点第三个
搜localhost
或者用开发者模式也可以
//获取cookie//1.获取cookie数组Cookie[] cookies = request.getCookies();//2.遍历数组for (Cookie cookie : cookies) {//3.获取数据String name = cookie.getName();if("username".equals(name)){String value = cookie.getValue();//但我只想要username和zs的cookieSystem.out.println(name+":"+value);break;}}
先访问aServlet,这样浏览器就有cookie了,在访问bCookie
这样的话,一次会话(一个浏览器)两次请求(两个窗口)之间共享了数据
对于我们,我们只需要干,发送和获取
3.2 原理
在访问bServlet,浏览器里面已经有cookie信息了,那么访问的时候就会把cookie里面的数据携带到bServlet里面的资源里面去
这个就是cookie的请求头,而且cookie对应数据不止一个,因为浏览器会把这个域名下的locallhost下的所有cookie都带过去
3.3 使用细节
这个的意思就是你使用aServlet,然后关闭浏览器,cookie就不见了。在打开bServlet,就不会有输出了
但是我们记住密码,肯定有记住一个月啊,要多记住一些时间,就不能浏览器关闭,cookie就不见了
cookie.setMaxAge(60*60*24*7);
这样的话,就算我们关闭浏览器也不会删除cookie了,再次点开bServlet也可以访问cookie了
现在我们演示一下存储中文
Cookie cookie=new Cookie("username","张三");
这样直接就报错了
String value="张三";//URL编码value = URLEncoder.encode(value, "UTF-8");System.out.println(value);Cookie cookie = new Cookie("username", value);
这样bServlet获取的数据就是URL编码的数据了
这样的话,我们需要解码
value = URLDecoder.decode(value, "UTF-8");
4. Session
4.1 基本使用
//存储到Session中//1.获取session对象HttpSession session = request.getSession();//2.存储数据session.setAttribute("username","sz");//第二个参数为任意类型
//获取数据,从session中//1.获取session对象,这个对象只有一个HttpSession session = request.getSession();//2.获取数据Object username = session.getAttribute("username");System.out.println(username);
4.2 原理
两次获取的session是同一个,不信可以打印一下地址,分别打印一下
请求1和请求2是同一会话,就是同一session,请求3和请求1不是同一会话,就不是同一个session
其实session就是一个cookie,往sessio存入数据,就是存入cookie
创建了一个cookie这个cookie就是JESSIONID,值就是对应id,id就是服务端session的唯一标识,不同会话有不同的id
这里就有id
4.3 使用细节
一般来说,还是存在的,因为万一你买了什么东西,离开了一下,资源就直接不见了?
然后终端ctrl+c,正常停止
再次启动
这样就看出来,还是存在的
那在哪里看这个文件呢
里面有tomcat–》work–》找
这里就有了
在启动的时候,这个文件就被删除了
浏览器关闭的话,访问的session就不是同一个session了
<session-config>
<!-- 这里就表示session失效时间是100分钟,默认是就是30分钟--><session-timeout>100</session-timeout></session-config>
所以很长一段时间没有操作就会退出登录,30分钟
//销毁session.invalidate();//自己把自己销毁了
这里先demo1,在demo2,就会报错了
5.小结
购物车用cookie
登录信息就要存在cookie,但是不安全,但是可以长期存
验证码用session
5. 案例
我们要实现的功能就是,登录的时候,账号和密码错误,会提示错误,点了记住我,下次就不用输入密码了
注册的时候,验证码错误也会提示,账号已存在也会提示,验证码不区分大小写
5.1 登录
补充一下:下载这个插件,我们的Mapper就有小鸟了
现在我们导入User,UserMapper,还有对应xml
以前写过的
下面写services层:
//2.获取sqlSessionSqlSession sqlsession = factory.openSession();//3.获取UserMapperUserMapper mapper = sqlsession.getMapper(UserMapper.class);//4.调用方法User user=mapper.select(username,password);sqlsession.close();
web:
前端的页面直接就拷贝了
资源在
资源
不知道能不能打开
这四个全拷贝到webapp下
但是要显示动态的数据的话,我们要改造成jsp
把login.html的代码全部粘贴到login.jsp中
LoginServlet:
brand.jsp:
<h1>${user.username},欢迎您</h1>
但是user要共享数据(多个页面,多个servlet间)—》存在cookie或者session里面—》session–》因为要安全
//存储sessionHttpSession session = request.getSession();session.setAttribute("user", user);
现在开始写登录失败
跳转到login.jsp–》要显示登录失败的提示—》要携带用户名和密码----》数据存在request域中,采用转发的方式
//2.登录失败//存储错误信息到requestrequest.setAttribute("login_msg","用户名或密码错误");//跳转到login.jsprequest.getRequestDispatcher("/login.jsp").forward(request, response);
login.jsp:
<div id="errorMsg">${login_msg}</div>
然后就是我们的数据库里面也有表的
先随便输
登录失败的信息只和那一次请求有关系,如果存在session中,那么就会在那一次会话多次请求中一直存在,只是在login.jsp显示一下就可以了
,存在request域中就可以了
登录成功的信息存在session中,方便后期再每一个页面都能访问到对应用户名的信息,user只有一个,每一次登录都会替代原来session的user
5.2 记住用户
登录成功且勾选了就写cookie
login.jsp:
<p>Remember:<input id="remember" name="remember" value="1" type="checkbox"></p>
看值是不是1就知道勾没勾选了
LoginServlet:
//获取复选框数据String remember = request.getParameter("remember");
//判断用户是否勾选记住我if("1".equals(remember)){//因为万一remember为空呢//勾选了,发送cookie//1.创建---》用户名和密码两个cookieCookie c_username = new Cookie("username",username);Cookie c_password = new Cookie("password",password);//设置存活值--》一周c_username.setMaxAge(60*60*24*7);c_password.setMaxAge(60*60*24*7);//2.发送response.addCookie(c_username);response.addCookie(c_password);}
写cookie我们就做完了
先写个错误密码–》不会有cookie
有个小问题就是这个是get请求,待会儿改
这里没有cookie
也没有cookie
现在我们正确登录就有cookie了
这里还有过期时间
在login.jsp上获取cookie
login.jsp:
<p>Username:<input id="username" name="username" value="${cookie.username.value}" type="text"></p><p>Password:<input id="password" name="password" value="${cookie.password.value}" type="password"></p>
这里我们一刷新就填上了
5.3 注册案例
services:
UserService:
web:
register.html:
因为要动态生成数据,所以要写成jsp
直接复制过去就可以了
<form id="reg-form" action="/brand-demo/registerServlet" method="post">
RegisterServlet:
register.jsp:
<span id="username_err" class="err_msg" style="display: none">${register_msg}</span>
login.jsp:
<div id="errorMsg">${login_msg} ${register_msg}</div>
login.jsp:
<a href="register.jsp">没有账号?</a>
左下角有提示,点没有账号
但是这个没有展示注册信息
原因可能是register_msg写错了,然后可能就是span给隐藏掉了
点击style的三个点可以发现,display==none
删掉style就可以了
<span id="username_err" class="err_msg">${register_msg}</span>
5.4 验证码之展示和验证
我们在资料里面复制一个工具类
我们只需要管这一个函数就可以了
在这个工具类里面写一个测试方法
public static void main(String[] args) throws Exception {OutputStream fos=new FileOutputStream("d://a.jpg");String s = CheckCodeUtil.outputVerifyImage(100, 50, fos, 4);//返回的字符串就是验证码数据System.out.println(s);}
控制台输出的这个数据,就是验证码NRCR
然后d盘对应有一个图片
因为图片机器是无法识别的,只有人来用肉眼观察,才能注册
register.jsp:
中的
这个是写死的
将来我们是要访问一个动态的资源,而且每一次访问都会获取到一个新的图片
<img src="/brand-demo/checkCodeServlet">
将来就是我访问这个Servlet,这个Servlet就返回一个图片的数据,就放在了这个img的src里边,就获取到了验证码
CheckCodeServlet:
// OutputStream fos=new FileOutputStream("d://a.jpg");//这个流换一下,换成response的字节输出流ServletOutputStream os = response.getOutputStream();String s = CheckCodeUtil.outputVerifyImage(100, 50, os, 4);//返回的字符串就是验证码数据
写这一行代码就可以把图片输出到验证码的位置了
它的作用就是提供验证码
没刷新一次,验证码就换一次
下面我们来做第二个功能,就是看不清,换一张
给看不清添加一个单击事件就可以了
register.jsp:
或者写一个JavaScript的代码
接下来我们需要干的事就是获取对应图片,取个id
<script>document.getElementById("changeImg").onclick = function() {document.getElementById("checkCodeImg").src = "/brand-demo/checkCodeServlet";}
</script>
这样就可以了
但是我们点了看不清还是没换,为什么呢,原因就是这个图片的路径已经被缓存了
因为这两个路径是一模一样的,所以这个图片就被浏览器缓存了,解决办法就是给script加个参数就可以了
<script>document.getElementById("changeImg").onclick = function() {document.getElementById("checkCodeImg").src = "/brand-demo/checkCodeServlet?a";}
</script>
但是这样还是不能一直换,因为带有参数a的图片又被浏览器缓存了
<script>document.getElementById("changeImg").onclick = function() {document.getElementById("checkCodeImge").src = "/brand-demo/checkCodeServlet?a";}
</script>
注意我的ID少写了一个e,但还是只能刷新一次,原因一样的,被缓存了,但为了是个单词,后面我又去掉了e
所以在后面加个永远不一样的数据-》时间–》因为时间一去不复返
<script>document.getElementById("changeImg").onclick = function() {// new Date().getMilliseconds();获取时间的毫秒值document.getElementById("checkCodeImg").src = "/brand-demo/checkCodeServlet?"+new Date().getMilliseconds();}
</script>
这样就可以了,这样我们真的就可以一直换了
填写验证码一样就注册,不一样就阻止注册
用户填写的用户数据,可以通过request获取,在注册的servlet获取
但验证码图片生成的数据,访问的是CheckCodeServlet,是一次新的请求,怎么共享呢,在一次会话的两次请求之间,用cookie或者session
又因为验证码要安全,所以存session
CheckCodeServlet:
//存入sessionHttpSession session = request.getSession();session.setAttribute("checkCodeGen", checkCode);
RegisterServlet:
//获取用户输入的验证码
// <tr>
// <td>验证码</td>
// <td class="inputs">
// <input name="checkCode" type="text" id="checkCode">
// <img id="checkCodeImg" src="/brand-demo/checkCodeServlet">
// <a href="#" id="changeImg">看不清?</a>//验证码的名字叫做checkCodeString checkCode = request.getParameter("checkCode");//获取程序生成的验证码,从Session中获取HttpSession session = request.getSession();// session.setAttribute("checkCodeGen", checkCode);String checkCodeGen = (String)session.getAttribute("checkCodeGen");//要对应起来
接下来就来比对验证码
是要在注册service之前比对,之后在比对的话,都已经注册进去了
//比对if(!checkCodeGen.equalsIgnoreCase(checkCode)){//因为程序生成的不可能为null,因为要忽略大小写比对,所以我们用这个equalsIgnoreCase//不允许注册//注册失败,跳转到注册页面request.setAttribute("register_msg","验证码错误");request.getRequestDispatcher("/register.jsp").forward(request, response);return;}
显示出来了验证码错误,还重新生成了验证码
总结
这个会话跟踪技术我们就讲完了,主要精彩的部分就是后面的案例了,前面的比较枯燥
Gitee