前 言
人总是要有梦想的,也许哪天就实现了呢!
如果有不正确之处,还望指正,毕竟我还是一个菜鸟!
一、会话技术
-
概述:一次会话中包含多次请求和响应
一次会话:当浏览器发送HTTP请求给服务器资源时,服务端创建会话对象后,则会话在浏览器和服务器之间完成建立,直到有一方断开为止,会话结束 功能:在一次会话的范围内(从创建到消亡的过程中)的多次http请求中,浏览器和服务器可以共享Cookie或Session中存储的数据
-
方式:
- 客户端会话技术:Cookie,创建与服务器中,数据存储于浏览器中
- 服务器端会话技术:Session,创建于服务器中,数据存储于服务器中
二、Cookie 介绍
-
概述:Cookie是一种客户端技术,Cookie存储在客户端浏览器中,用于存储用户的基本信息。
-
为什么需要Cookie技术?
假设现在我们在淘宝买东西,先是添加了一个物品到购物车,然后又添加一个物品到购物车,在这期间,你发起了多次请求,我们知道通过request域是 不能在多次请求之间共享的,而response对象也只是对浏览器响应时才需要的,那么你的购物车是如何确定这些东西都是你的,而不是别人的呢? 由于之前学习的request和response对象都无法解决这一问题,所以就诞生了cookie会话技术。Cookie会话技术允许浏览器端在一次会话中可以发起 多次请求,只要会话不断开,多少次都行。当你登入到系统的时候,建立cookie,你所发起的每次请求都会带上这个特定的cookie,所以也就保证了你所 添加的物品都是你的,而不是别人的。
-
作用:通过设置Cookie来区分不同的用户。解析:当我们第一次去会员制奶茶店时,奶茶店会给我们一张会员卡,上面有会员编号并记录有本次的积分,当我们以后再去该奶茶店的时候,只需要拿着这张会员卡就能进行积分,并且不会将自己的积分积到别人的会员卡上。这里,会员卡就是我们的Cookie,可以有效的区别每一位会员用户,即Cookie可以有效的区别每一个用户。
-
原理:当浏览器发起请求调用了创建Cookie的Servlet时,服务器会响应给浏览器该cookie对象,在本次会话中,不管浏览器发出多少次请求,在请求报文中都有该cookie信息,除非cookie失效了。
-
特点:
- cookie信息存储于客户端浏览器中,既可以持久化存储也可以暂时存在内存中。
- 浏览器对于单个cookie 的大小有限制(4KB),并且对同一个域名下的总cookie数量也有限制(20个)。
-
应用场景:
- 用于客户端用户免登录,即在不登录的情况下,完成对客户端身份的识别。
- 用于存储少量且不重要的数据信息。
三、Cookie 使用
-
一次会话中发送多个Cookie信息:
/** * 只需要在设置Cookie时多创建几个Cookie对象,并且加入到Cookie中去即可 */ Cookie c1 = new Cookie("msg", "hello"); Cookie c2 = new Cookie("name", "张三 "); response.addCookie(c1); response.addCookie(c2);
注意:如果当创建Cookie对象的时候,发送键相同值不相同的情况,那么就会覆盖之前的value。
如果在上面代码中添加
Cookie c3 = new Cookie("name", "李四");
代码,那么"李四"就会把"张三"给覆盖。 -
设置Cookie的存活时间:默认情况下,当浏览器关闭后,Cookie数据就会被销毁
/** * 方法:setMaxAge(int seconds) * 1. 正数:将Cookie数据写到硬盘的文件中,进行持久化存储,并指定cookie在硬盘中的保留时间,时间到了后,cookie文件就会自动失效 * 2. 负数:将cookie有效时间设置为负数,其作用和默认值一样,关闭浏览器,cookie就会失效 * 3. 零:删除cookie的信息 */ Cookie c = new Cookie("msg", "hello"); response.addCookie(c);
注意:当设置了Cookie存活时间后,Cookie对象就会存储于客户端磁盘中,到时间才会自动消除。
-
Cookie的共享问题:
-
同一个Tomcat下不同项目之间的cookie共享:
一般情况下,不同的项目之间是不能进行cookie共享的。但是我们都知道,tomcat的虚拟目录可以为"/",表示可以访问任意的该tomcat下的所有项目,因此,我们可以将cookie的路径设置为"/",这样就提升了该cookie的范围,就允许该tomcat下所有的web应用都可以共享该cookie。
setPath(String path) // 设置cookie的获取范围。默认情况下,设置当前的虚拟目录,如果要共享,则可以将path设置为"/"
-
同一个项目不同的Tomcat之间的cookie共享:
如果将一个项目分为几部分部署于不同的服务器,那么其域名都会不同,但都有一个共同的一级域名,你可以通过一级域名找到该web项目。所以,我们可以通过给cookie设置一级域名,就能够保证cookie在不同的服务器之间共享。例如,百度一级域名为baidu.com,而二级域名包括news.baidu.com、tieba.baidu.com,想要新闻网和贴吧网可以共享cookie,就需要将cookie的一级域名设置为
c.setDomain("baidu.com");
即可。setDomain(String path) // 如果设置一级域名相同,那么多个服务器之间cookie可以共享
-
四、Cookie 免登录案例
- 需求分析:
用户进行登录操作,如果账号或密码错误,在request域中存储一个错误信息,跳转至登录页面,在页面中显示错误信息。
如果登录成功,需要添加一个userid的cookie,时效为一个星期,然后跳转至个人信息servlet。
在个人信息servlet中,需要对userid的cookie进行校验,如果从数据库中有该对象id,则显示该用户信息,否则跳转至登录页面。
这里采用Druid连接池和JdbcTemplate来完成对数据库的操作。页面通过JSP来展示。
所需要的jar包:
commons-logging-1.2.jar
druid-1.0.9.jar
mysql-connector-java-8.0.16.jar
spring-beans-5.0.0.RELEASE.jar
spring-core-5.0.0.RELEASE.jar
spring-jdbc-5.0.0.RELEASE.jar
spring-tx-5.0.0.RELEASE.jar
-
目录结构:
-
数据库用户表的设计:
-
JSP页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>用户登录</title> </head> <body> <!-- 获取错误提示信息 --> <% String error = (String) request.getAttribute("error"); if (error == null || error.equals("")) { error = ""; } %> <form action="/cookie_war_exploded/login" method="post"> <label>账号:</label> <input type="text" name="username" /><br> <label>密码:</label> <input type="password" name="password" /><br> <span><%= error %></span> <input type="submit" value="点击登录"> </form> </body> </html>
-
DAO层:
public interface LoginDao { public User login(String username, String password); public User userInfo(String id); } public class LoginDaoImpl implements LoginDao { private JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcUtils.getDataSource()); @Override public User login(String username, String password) { String sql = "select * from user" + " where username = ? and password = ?"; try { User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username, password); return user; } catch (Exception e) { return null; } } @Override public User userInfo(String id) { String sql = "select * from user where id = ?"; try { User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), id); return user; } catch (Exception e) { return null; } } }
-
Servlet:
/** * 用户登录Servlet */ @WebServlet(value = "/login") public class LoginServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=utf-8"); LoginDao loginDao = new LoginDaoImpl(); String username = req.getParameter("username"); String password = req.getParameter("password"); User user = loginDao.login(username, password); if (user == null ) { // 登录失败 req.setAttribute("error", "账号或密码不正确!"); req.getRequestDispatcher("/login.jsp").forward(req, resp); } // 登录成功 Cookie cookie = new Cookie("userid", String.valueOf(user.getId())); cookie.setMaxAge(60 * 60 * 24 * 7); // cookie保存一个星期 resp.addCookie(cookie); // 转发到主页面 resp.sendRedirect("/cookie_war_exploded/userInfoServlet"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } } /** * 用户信息展示servlet */ @WebServlet(value = "/userInfoServlet") public class UserInfoServlet extends HttpServlet { private LoginDao loginDao = new LoginDaoImpl(); @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Cookie[] cookies = req.getCookies(); boolean isUserId = false; String userId = ""; for (Cookie cookie : cookies) { if (cookie.getName().equals("userid")) { userId = cookie.getValue(); isUserId = true; break; } } if (isUserId) { User user = loginDao.userInfo(userId); if ( user != null ) { resp.setContentType("text/html;charset=utf-8"); resp.getWriter().write(user.toString()); } } else { // 没有userId req.getRequestDispatcher("/login.jsp").forward(req, resp); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } }