目录
(一)Cookie概述
1.什么叫Cookie
2.Cookie规范
3.Cookie的覆盖
(二) Cookie的API
1.创建Cookie:new 构造方法
2.保存到客户端浏览器上,通过响应对象addCookie()
(三)案例:记住我功能的实现
1.实现思路
第一步: 在servlet中写逻辑代码,判断是否勾选“记住我”
(四) HttpSession
1.什么是HttpSesssion
2.获取HttpSession对象
3.HttpSession是域对象
4.案例:在登录中引入验证码
第一步:在login.jsp页面显示验证码
第二步:定义函数,在jsp页面编写refreshCode()方法
第三步:修改LoginServlet类的代码,当验证码错误时,显示“验证码错误”,若验证码不成功,不验证用户名和密码是否正确
(一)Cookie概述
1.什么叫Cookie
Cookie翻译成中文是小甜点,小饼干的意思。在HTTP中它表示服务器送给客户端浏览器的小甜点。其实Cookie就是一个键和一个值构成的,随着服务器端的响应发送给客户端浏览器。然后客户端浏览器会把Cookie保存起来,当下一次再访问服务器时把Cookie再发送给服务器。
Cookie是由服务器创建,然后通过响应发送给客户端的一个键值对。客户端会保存Cookie,并会标注出Cookie的来源(哪个服务器的Cookie)。当客户端向服务器发出请求时会把所有这个服务器Cookie包含在请求中发送给服务器,这样服务器就可以识别客户端了!
总结:
cookie特征:
- 创建于服务器,保存于客户端
- 不同的浏览器之间不能共享,
- 不能跨浏览器
- Cookie的key,value都是String
- 在之后的请求中,cookie会以请求头的方式自动发送给服务器
请求头:
缺点:
- 不安全,在客户端浏览器的键值不加密
- key,value的数据类型有限,只能存string类型的数据
2.Cookie规范
Cookie大小上限为4KB;(不同的浏览器cookie的内存大小可能不同)
一个服务器最多在客户端浏览器上保存20个Cookie;
一个浏览器最多保存300个Cookie;
注意:
不同浏览器之间是不共享Cookie的。也就是说在你使用IE访问服务器时,服务器会把Cookie发给IE,然后由IE保存起来,当你在使用FireFox访问服务器时,不可能把IE保存的Cookie发送给服务器。
3.Cookie的覆盖
如果服务器端发送重复的Cookie那么会覆盖原有的Cookie,例如客户端的第一个请求服务器端发送的Cookie是:Set-Cookie: a=A;第二请求服务器端发送的是:Set-Cookie: a=AA,那么客户端只留下一个Cookie,即:a=AA。
如果cookie的name与path一样, 覆盖value, 如果没有设置path: 默认值, 创建Cookie的资源上级路径
虽然name相同,但path不一样,所以没有覆盖
name相同,path相同,覆盖
cookie的path:
- localhost:8090/bbb
访问的cookie: path为/下的cookie
- localhost:8090/user/ccc
访问的cookie: path为/下的cookie和path为/user下的cookie
- localhost:8090/a/b/c/d: 能访问的cookie: /c 下, /b 下 /a下 /下
path为/下的cookie,可以被所有的资源访问
某个url能访问的cookie: path为父辈级目录的Cookie,
调用setPath()给cookie设置path
4.cookie的最大存活时间 (Cookie的生命)
默认存活时间:会话级别,浏览器关闭,这个cookie就会被删除
调用setMaxAge(int 参数) 设置最大存活时间 单位: 秒
-1: 会话级别
>0: 存活多少秒, 时间一到,浏览器自动清除
0: 立即删除cookie
会话的概念:客户端打开浏览器,访问服务器表示会话的开始
- 只要浏览器不关闭, 这次会话一直存在, 这次会话内所有的请求, 共享同一个session域
- 当客户端关闭浏览器, 表示会话的结束
- 类似于生活中的通话
(二) Cookie的API
1.创建Cookie:new 构造方法
构造方法:
2.保存到客户端浏览器上,通过响应对象addCookie()
//创建Cookie保存到客户端浏览器上Cookie cookie1 = new Cookie("k1","v100");Cookie cookie2 = new Cookie("k2","v200");//cookie的设置代码,一定在addCookie()之前//给cookie设置最大存活时间cookie1.setMaxAge(150);cookie2.setMaxAge(150);//保存到客户端resp.addCookie(cookie1);resp.addCookie(cookie2);
添加成功:
3.在服务器端获取cookie内容 请求对象:Cookie[] getCookies()
@WebServlet("/bbb") public class BServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取客户端浏览器传递Cookie// System.out.println(req.getHeader("Cookie"));Cookie[] cookies = req.getCookies();//循环遍历for (Cookie cookie : cookies) {//获取Cookie的key, valueString name = cookie.getName();if(name.equals("username") || name.equals("pwd")){String value = cookie.getValue();System.out.println("key:"+name+",value:"+value);}}}
(三)案例:记住我功能的实现
登录成功之后, 把用户名,密码保存起来, 保存方式?
(1)服务器? 客户端? 选择方案: 客户端
(2)如果保存在服务器, 存在哪
(3)如果保存在客户端, 存在哪 存在客户端浏览器
在客户端浏览器上有这三个地方可以存
那么我们应该选择哪一个来保存我们的数据呢?
因为我们需要实现的是登录成功之后,把用户名、密码保存起来,所以这两个数据应该在服务器端的逻辑代码执行完毕之后传给客户端,所以是服务器传给客户端的数据。
1.本地存储 localStorage, 会话存储 sessionStorage: 纯js技术, java没有
2.Cookie:js操作, java也能操作
所以我们选择使用cookie来存储从服务器端传来的数据,也就是登录成功之后的用户名和密码。
1.实现思路
登录成功之后,并且用户勾选了“记住我”用户名,密码保存到cookie
第一步: 在servlet中写逻辑代码,判断是否勾选“记住我”
LoginServlet代码:
@WebServlet("/login") public class LoginServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//1.设置post请求编码, 响应编码resp.setCharacterEncoding("UTF-8");resp.setContentType("text/html;charset=UTF-8");//进行验证码验证String verify=req.getParameter("verifycode");HttpSession session=req.getSession();String code=(String)session.getAttribute("CHECKCODE_SERVER");if (code.equals(verify)){//2.获取请求参数String username = req.getParameter("user");String password = req.getParameter("password");//3.调用业务层LoginService的登录方法LoginService loginService = new LoginServiceImpl();LoginInfo loginInfo = loginService.login(username, password);if(loginInfo != null){ //登陆成功String rem=req.getParameter("rem");if(Objects.nonNull(rem)){//把用户名,密码保存到cookieCookie cookie1 = new Cookie("username", username);Cookie cookie2=new Cookie("pwd",password);//设置存活时间 7天cookie1.setMaxAge(60*60*24*7);cookie2.setMaxAge(60*60*24*7);//设置path为/ 项目下任何资源可以访问cookie1.setPath("/");cookie2.setPath("/");//保存到客户端resp.addCookie(cookie1);resp.addCookie(cookie2);}session.setAttribute("login",loginInfo);resp.sendRedirect("/index.jsp");}else{ //登录失败//转发到登录页面//把错误信息保存到request域req.setAttribute("error", "用户名或密码错误");req.getRequestDispatcher("/login.jsp").forward(req, resp);}}else{req.setAttribute("error","验证码错误");req.getRequestDispatcher("/login.jsp").forward(req,resp);}} }
记住我部分:
第二步:在login.jsp 获取服务器传过来的cookie的值,设置到表单元素上
login.jsp代码:
<body> <%Cookie[] cookies=request.getCookies();String username="";String password="";if(cookies!=null && cookies.length > 0){for (Cookie cookie:cookies){if(cookie.getName().equals("username")){username=cookie.getValue();}if (cookie.getName().equals("pwd")){password=cookie.getValue();}}} %> <div class="container" style="width: 400px;"><h3 style="text-align: center;">管理员登录</h3><form action="/login" method="post"><div class="form-group"><label for="user">用户名:</label><input type="text" name="user" class="form-control" id="user" placeholder="请输入用户名" value="<%=username%>"/></div><div class="form-group"><label for="password">密码:</label><input type="password" name="password" class="form-control" id="password" placeholder="请输入密码" value="<%=password%>"/></div><div class="form-inline"><label for="vcode">验证码:</label><input type="text" name="verifycode" class="form-control" id="verifycode" placeholder="请输入验证码" style="width: 120px;"/><a href="javascript:refreshCode()"><img src="vcode" title="看不清点击刷新" id="vcode"/></a></div><div class="form-inline"><input type="checkbox" name="rem" class="form-control" id="rem" value="rem" /><label for="rem">记住我</label></div><hr/><div class="form-group" style="text-align: center;"><input class="btn btn btn-primary" type="submit" value="登录"></div></form><!-- 出错显示的信息框 --><div class="alert alert-warning alert-dismissible" role="alert"><button type="button" class="close" data-dismiss="alert" ><span>×</span></button><strong>${error}</strong></div> </div> </body>
实现:
(四) HttpSession
Cookie和HttpSession的区别:
Cookie:创建于服务器,保存于客户端
HttpSession:域对象,创建于服务器,保存于服务器,同一次会话有效
1.什么是HttpSesssion
javax.servlet.http.HttpSession
接口表示一个会话,我们可以把一个会话内需要共享的数据保存到HttpSession对象中!每一个客户端都有自己的Session
session作用: 域对象功能, 存,取数据
2.获取HttpSession对象
通过request对象的getSession()来获取
HttpSession request.getSesssion():如果当前会话已经有了session对象那么直接返回,如果当前会话还不存在会话,那么创建session并返回;
HttpSession request.getSession(boolean):当参数为true时,与requeset.getSession()相同。如果参数为false,那么如果当前会话中存在session则返回,不存在返回null;
3.HttpSession是域对象
HttpServletRequest:一个请求创建一个request对象,所以在同一个请求中可以共享request,例如一个请求从AServlet转发到BServlet,那么AServlet和BServlet可以共享request域中的数据;
ServletContext:一个应用只创建一个ServletContext对象,所以在ServletContext中的数据可以在整个应用中共享,只要不启动服务器,那么ServletContext中的数据就可以共享;
HttpSession:一个会话创建一个HttpSession对象,同一会话中的多个请求中可以共享session中的数据;
下面是session的域方法:
void setAttribute(String name, Object value):用来存储一个对象,也可以称之为存储一个域属性,例如:session.setAttribute(“xxx”, “XXX”),在session中保存了一个域属性,域属性名称为xxx,域属性的值为XXX。请注意,如果多次调用该方法,并且使用相同的name,那么会覆盖上一次的值,这一特性与Map相同;
Object getAttribute(String name):用来获取session中的数据,当前在获取之前需要先去存储才行,例如:String value = (String) session.getAttribute(“xxx”);,获取名为xxx的域属性;
void removeAttribute(String name):用来移除HttpSession中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;
Enumeration getAttributeNames():获取所有域属性的名称;
4.案例:在登录中引入验证码
生成验证码Servlet:
在一个矩形框内生成随机字符
/*** 验证码*/ @WebServlet("/checkCode") public class CheckCodeServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//服务器通知浏览器不要缓存response.setHeader("pragma","no-cache");response.setHeader("cache-control","no-cache");response.setHeader("expires","0");//在内存中创建一个长80,宽30的图片,默认黑色背景//参数一:长//参数二:宽//参数三:颜色int width = 80;int height = 30;BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);//获取画笔Graphics g = image.getGraphics();//设置画笔颜色为灰色g.setColor(Color.GRAY);//填充图片g.fillRect(0,0, width,height);//产生4个随机验证码,12EyString checkCode = getCheckCode();//将验证码放入HttpSession中request.getSession().setAttribute("CHECKCODE_SERVER",checkCode);//设置画笔颜色为黄色g.setColor(Color.YELLOW);//设置字体的小大g.setFont(new Font("黑体",Font.BOLD,24));//向图片上写入验证码g.drawString(checkCode,15,25);//将内存中的图片输出到浏览器//参数一:图片对象//参数二:图片的格式,如PNG,JPG,GIF//参数三:图片输出到哪里去ImageIO.write(image,"PNG",response.getOutputStream());}/*** 产生4位随机字符串 */private String getCheckCode() {String base = "0123456789ABCDEFGabcdefg";int size = base.length();Random r = new Random();StringBuffer sb = new StringBuffer();for(int i=1;i<=4;i++){//产生0到size-1的随机值int index = r.nextInt(size);//在base字符串中获取下标为index的字符char c = base.charAt(index);//将c放入到StringBuffer中去sb.append(c);}return sb.toString();}public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request,response);} }
第一步:在login.jsp页面显示验证码
<div class="form-inline"><label for="vcode">验证码:</label><input type="text" name="verifycode" class="form-control" id="verifycode" placeholder="请输入验证码" style="width: 120px;"/><a href="javascript:refreshCode()"><img src="vcode" title="看不清点击刷新" id="vcode"/></a> </div>
第二步:定义函数,在jsp页面编写refreshCode()方法
<script type="text/javascript">function refreshCode() {//每次点击时,重新生成验证码console.log("refreshCode....")//选择器 #id名//获取到img标签 浏览器缓存,url没有变化,使用上一次缓存的内容//加一个时间戳,每一次都不一样,浏览器发现参数不一样,以为是新请求,不使用上一次缓存$("#vcode").attr("src","/checkCode?time="+new Date().getTime())}</script>
第三步:修改LoginServlet类的代码,当验证码错误时,显示“验证码错误”,若验证码不成功,不验证用户名和密码是否正确
//进行验证码验证String verify=req.getParameter("verifycode");HttpSession session=req.getSession();String code=(String)session.getAttribute("CHECKCODE_SERVER");if (code.equals(verify)){//2.获取请求参数String username = req.getParameter("user");String password = req.getParameter("password");//3.调用业务层LoginService的登录方法LoginService loginService = new LoginServiceImpl();LoginInfo loginInfo = loginService.login(username, password);if(loginInfo != null){ //登陆成功String rem=req.getParameter("rem");if(Objects.nonNull(rem)){//把用户名,密码保存到cookieCookie cookie1 = new Cookie("username", username);Cookie cookie2=new Cookie("pwd",password);//设置存活时间 7天cookie1.setMaxAge(60*60*24*7);cookie2.setMaxAge(60*60*24*7);//设置path为/ 项目下任何资源可以访问cookie1.setPath("/");cookie2.setPath("/");//保存到客户端resp.addCookie(cookie1);resp.addCookie(cookie2);}session.setAttribute("login",loginInfo);resp.sendRedirect("/index.jsp");}else{ //登录失败//转发到登录页面//把错误信息保存到request域req.setAttribute("error", "用户名或密码错误");req.getRequestDispatcher("/login.jsp").forward(req, resp);}}else{req.setAttribute("error","验证码错误");req.getRequestDispatcher("/login.jsp").forward(req,resp);}
结果:
登录成功
验证码错误