概念:
****首先在WEB应用中,我们把同一个浏览器与WEB服务器的一次一系列的各种交互活动称之为"会话"
在很多WEB应用中,我们都需要对用户的会话进行跟踪,需要记录用户的状态,比如商城中用户将商品添加到购物车,商城必须能识别哪些会话是属于同一个用户,既是哪些客户端添加了哪些商品,不能出现,A用户的客户端添加的商品跑到B用户客户端的购物车里头!
在Servlet技术中,有两种机制可以实现这种对会话的跟踪:**
①Cookie机制:放在客户端
②Session机制:放在服务器端
Cookie技术是客户端的解决方案,当用户使用浏览器访问一个支持Cookie的网站的时候,一个cookie的运行过程分为以下四步:
当客户端浏览器接收到来自服务器的响应之后,浏览器会将这些信息存放在一个统一的位置,对于Windows操作系统而言,IE浏览器的Cookie 放在:[系统盘]:\Users\用户名\Cookies目录中;
通常,我们可以从很多网站的登录界面中看到****“****请记住我”****这样的选项,如果你勾选了它之后再登录,那么在下一次访问该网站的时候就不需要进行重复而繁琐的登录动作了,而这个功能就是通过Cookie实现的。
****其实本质上cookies就是http的一个扩展。有两个http头部是专门负责设置以及发送cookie的,它们分别是Set-Cookie以及Cookie。其中如果包含Set-Cookie这个头部时,意思就是指示客户端建立一个cookie,并且在后续的http请求中自动发送这个cookie到服务器端,直到这个cookie过期。如果cookie的生存时间是整个会话期间的话,那么浏览器会将cookie保存在内存中,浏览器关闭时就会自动清除这个cookie。另外一种情况就是保存在客户端的硬盘中,浏览器关闭的话,该cookie也不会被清除,下次打开浏览器访问对应网站时,这个cookie就会自动再次发送到服务器端。
****Java中把Cookie封装成了javax.servlet.http.Cookie类。每个Cookie都是该Cookie类的对象。服务器通过操作Cookie类对象对客户端Cookie进行操作。通过response.addCookie(Cookie cookie)向客户端设置Cookie,通过request.getCookie()获取客户端提交的所有Cookie(以Cookie[]数组形式返回)。
Cookie对象里的属性(每个属性都有set和get方法)
①String name:该Cookie的名称。Cookie一旦创建,名称便不可更改。
② Object value:该Cookie的值。
③int maxAge:该Cookie失效的时间,单位秒。
(如果为正数,则该Cookie在>maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1。)
④boolean secure:该Cookie是否仅被使用安全协议传输。默认为false。
⑤String path:该Cookie的使用路径。
**如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/”。
⑥String domain:可以访问该Cookie的域名。
**如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”。
****JAVA与JAVASCRIPT操作Cookie示例,实现登陆网站有效期:
1.java操作cookie:
CookUtils.java 工具类-指定浏览器创建cookie文件的方法
public static void createCookie(String username,HttpServletRequest req, HttpServletResponse resp,int second) {
Cookie userCookie =new Cookie("userKey", username);
Cookie ssidCookie = new Cookie("ssid",md5Encrypt(username));
userCookie.setMaxAge(second);
ssidCookie.setMaxAge(second);
resp.addCookie(userCookie);
resp.addCookie(ssidCookie);
}
UserController.java 控制类中,创建Cookie的有效期,使用了switch(expiresdays)开关条件语句。
private void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
String expiredays = req.getParameter("expiredays");
Cookie[] cookies = req.getCookies(); // 获取cookie
boolean login = false; // 设置登录的标记,true,已登录,false 还没有登录
String account = null; // 登录账号
String ssid = null; // 这是一个标记,该标记也为用户名,通过cookie拿到的一个判 断用户该不该成功登录的标志,即就是,已有 cookie的值为该用户名,则表明用户已登陆过,并且没过期。
if (cookies != null && cookies.length > 0) {
for (Cookie cook : cookies) {
if (cook.getName().equals("userKey")) {
account = cook.getValue();
}
if (cook.getName().equals("ssid")) { //用户第一次登陆,保存用户名到一个 cookie中,该cookie键为ssid
ssid = cook.getValue();
}
}
}
if (account != null && ssid != null) {
login =ssid.equals(CookieUtils.md5Encrypt(username));
}
if (!login) { // login初始:false 取反,即表示没登录是真的:用户还没有登录
// 用户第一次访问过来
User user = userService.login(username, password);// 通过访问数据库,来判断用户的用户名和密码对不对
if (user != null) { // 对的,登录成功
expiredays = expiredays == null ? "" : expiredays;
switch (expiredays) {
case "7": // 选择类记信我一周
// 创建一个cookie对象,设置有效时间为7天
CookieUtils.createCookie(username, req, resp, 7*24*60*60);
break;
case "30":
CookieUtils.createCookie(username, req, resp, 30*24*60*60);
break;
case "6000":
CookieUtils.createCookie(username, req, resp, Integer.MAX_VALUE);
break;
default:
// 创建一个cookie对象,设置cookie对象的实效时间为-1,关闭浏览器,cookie就失效
CookieUtils.createCookie(username, req, resp, -1);
break;
}
// 登陆成功了,准许客户,进入main.jsp页面
req.getRequestDispatcher("/main.jsp").forward(req, resp);
} else {
req.setAttribute("note", "用户名或者密码是错误的!"); // 错误的话,又回到登陆页
req.getRequestDispatcher("/index.jsp").forward(req, resp);
}
} else {//若已登陆过,则直接进入main.jsp
req.getRequestDispatcher("/main.jsp").forward(req, resp);
}
}
2.javaScript操作Cookie(cookie对象是键值对,key:value)
如果是结合java创建cookie,那么javascript只需获取cookie的方法,getCookie()
<script type="text/javascript">
function getCookie(c_name) {
if (document.cookie.length > 0) {
var c_start = document.cookie.indexOf(c_name + "=");
c_start = c_start + c_name.length + 1;
var c_end = document.cookie.indexOf(";", c_start);
if (c_end == -1)
c_end = document.cookie.length;
return unescape(document.cookie.substring(c_start, c_end));
}
}
window.onload = function() {
//alert();
var form = document.getElementById("loginform");
var useranme = document.getElementById("username");
if ( getCookie("userKey")!="" && getCookie("userKey")!=null && getCookie("ssid") != "" && getCookie("ssid") != null) {
useranme.value = getCookie("userKey"); //如果带username键的cookie存在,则提交表单
form.submit(); //提交到login.udo,login.udo是控制层的类中的一个方法,该方会判断cookiek 中的用户是否存在,存在再又判断数据库中的用
}
}
</script>
</head>
<body>
<form id="loginform" action="${pageContext.request.contextPath}/login.udo"
method="post">
用户名:<input type="text" name="username" id="username" value=""/> <br />
<br /> 用户密码:<input type="password" name="password" /><br/>
<input type="text" value="" name="checkCode"><img alt="验证码" src="${pageContext.request.contextPath}/drawCheckCode.udo"></img>
<br /><br />
<input type="submit" value="登录" /><br /> 记住我一周<input
type="radio" name="expiredays" value="7" />记住我一月<input type="radio"
name="expiredays" value="30" />记住我到永久<input type="radio"
name="expiredays" value="6000" />
</form>
</body>
session 机制,session对象,是系统自动创建,不用我们创建。
sessionID会保存在Cookie文件中,除了使用Cookie,Web应用程序中还经常使用Session来记录客户端状态。Session是服务器端使用的一种记录客户端状态的机制,它是通过服务器来保持状态的,使用上比Cookie简单一些,相应的也增加了服务器的存储压力。
要使用Session,第一步当然是创建Session了。那么Session在何时创建呢?而在Java中,当客户端第一次访问Servlet或jsp页面的时候自动创建(是否一定会创建了,不一定),通过调用HttpServletRequest的getSession方法可以获得session对象。
在创建了Session的同时,服务器会为该Session生成唯一的Session id,而这个Session id在随后的请求中会被用来重新获得已经创建的Session;在Session被创建之后,就可以调用Session相关的方法往Session中增加内容了,而这些内容只会保存在服务器中,发到客户端的只有Sessionid(放在Cookie文件里);当客户端再次发送请求的时候,会将这个sessionid带上,服务器接受到请求之后就会依据Sessionid找到相应的Session,从而再次使用之。(默认情况下session也要依赖cookie机制来实现).
session相当于程序在服务器上建立的一份客户档案,会给客户自动分配一个编号id,客户来访的时候只需要提供自己的id,就可以查询对应客户档案内容
javax.servlet.http.HttpSession是session对应的类。每个来访者对应一个Session对象,所有该客户的状态信息都保存在这个Session对象里。Session对象是在客户端第一次请求服务器的时候创建的。Session也是一种key-value的属性对,通过getAttribute(Stringkey)和setAttribute(String key,Objectvalue)方法读写客户状态信息。Servlet里通过request.getSession()方法获取该客户的Session,jsp页面中,session是九大隐含对象之一,可直接创建一个session,也可以HttpSession创建。
session对象不同于cookie对象:
Servlet中必须使用request来编程式获取HttpSession对象,而JSP中内置了Session隐藏对象,可以直接使用。如果使用声明了<%@page session="false" %>,则Session隐藏对象不可用。*
******当多个客户端执行程序时,服务器会保存多个客户端的Session。获取Session的时候也不需要声明获取谁的Session。Session机制决定了当前客户只会获取到自己的Session,而不会获取到别人的Session。各客户的Session也彼此独立,互不可见。
*****Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。
*****由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。
Tomcat中Session的默认超时时间为20分钟。通过setMaxInactiveInterval(int seconds)修改超时时间。也可以修改web.xml改变Session的默认超时时间。例如修改为60分钟:
在server.xml中定义context时采用如下定义(单位为秒):
1.示例:
jsp页面中,session是九大隐含对象之一,可直接创建一个session,也可以HttpSession创建
<%
/* HttpSession session1=request.getSession();
session1.setAttribute("user","admin");
out.println("取出session对象:"+session.getAttribute("users")); */
session.setAttribute("users","admin"); //若在<%@ page session="fasle">注明了session=false,则直接创建session对象失败
out.println("取出session对象:"+session.getAttribute("users"));//打开火狐浏览器,web开发者工具--网络--消息头可以看到cookie中有JSESSIONID: C285A6ECB080FDA033FFC10F6339F7D9
%>
*****URL地址重写:
URL地址重写是对客户端(手机有的浏览器不支持--好老的手机吧),Cookie的解决方案(正常情况下Seesion要依靠Cookie来识别的)****。URL地址重写的原理是将该用户Session的id信息重写到URL地址中。服务器能够解析重写后的URL获取Session的id。这样即使客户端不支持Cookie,也可以使用Session来记录用户状态。HttpServletResponse类提供了encodeURL(Stringurl)实现URL地址重写,例如:
该方法会自动判断客户端是否支持Cookie。如果客户端支持Cookie,会将URL原封不动地输出来。如果客户端不支持Cookie,则会将用户Session的id重写到URL中。重写后的输出可能是这样的:
**即在文件名的后面,在URL参数的前面添加了字符串“;jsessionid=XXX”。其中XXX为Session的id。分析一下可以知道,增添的jsessionid字符串既不会影响请求的文件名,也不会影响提交的地址栏参数。用户单击这个链接的时候会把Session的id通过URL提交到服务器上,服务器通过解析URL地址获得Session的id。
如果是页面重定向(Redirection),URL地址重写可以这样写:
由于大部分的手机浏览器都不支持Cookie,程序都会采用URL地址重写来跟踪用户会话。索性禁止Session使用Cookie,统一使用URL地址重写会更好一些。Java Web规范支持通过配置的方式禁用Cookie。下面举例说一下怎样通过配置禁止使用Cookie。
打开项目根目录下的META-INF文件夹(跟WEB-INF文件夹同级,如果没有则创建),打开context.xml(如果没有则创建),编辑内容如下: /META-INF/context.xml:
部署后TOMCAT便不会自动生成名JSESSIONID的Cookie,Session也不会以Cookie为识别标志,而仅仅以重写后的URL地址为识别标志了。
注意:该配置只是禁止Session使用Cookie作为识别标志,并不能阻止其他的Cookie读写。也就是说服务器不会自动维护名为JSESSIONID的Cookie了,但是程序中仍然可以读写其他的Cookie。
*******测试:
先清除浏览器的cookie数据,则:http://localhost:8080/mvcproject/
开发者工具----网络---消息头(header),Cookies中没有了JSESSIONID:'''字样了。
示例:见网盘--可运行的web项目--MVC基础入门项目-javaCookieLoing..
实现用户登录否的判断!并且没登录的情况下,不能直接进入main.jsp等其它页面。
原理:UserController.java---login()----如果登陆成功,保存user.getUsername()到session空间里,再到main.jsp中,判断用户是否已存在,不存在,则回到index.jsp中。
index.jsp main.jsp UserController.java CookieUtils.java
session实现简易购物车。
网盘--可运行的web项目--MVC基础入门项目-javaCookieLoing..mvcproject项目:
WebContent--shoping--productlist.jsp,productdetails.jsp,shoppingcart.jsp
java-src-....controller....ShopController.java
1. productlist.jsp,列出所有商品超链接,让用户选择,
<body>
<a href="<%=request.getContextPath()%>/shopping.pdo?pname='立顿Lipton 奶茶 香浓原味奶茶1'">立顿Lipton 奶茶 香浓原味奶茶1</a>
<br/><br/>
<a href="<%=request.getContextPath()%>/shopping.pdo?pname='立顿Lipton 奶茶 香浓原味奶茶2'">立顿Lipton 奶茶 香浓原味奶茶2</a>
<br/><br/>
<a href="<%=request.getContextPath()%>/shopping.pdo?pname='立顿Lipton 奶茶 香浓原味奶茶3'">立顿Lipton 奶茶 香浓原味奶茶3</a>
<br/><br/>
<a href="<%=request.getContextPath()%>/shopping.pdo?pname='立顿Lipton 奶茶 香浓原味奶茶4'">立顿Lipton 奶茶 香浓原味奶茶4</a>
</body>
2.ShopController.java中的shopping()获取参数?pname='';保存到request空间中(该空间只在页面转送中有效,除非每个页面都写setxxx方法才整个会话有效)再转送到productdetails.jsp中,该页面显示产口详情。
private void shopping(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// System.out.println("shopping!");
String pname = req.getParameter("pname");
req.setAttribute("pname", pname);
req.getRequestDispatcher("/shopping/productdetails.jsp").forward(req, resp);
}
3.productdetails.jsp 显示产品详情,并加入了购物车---ShopController.java---addCart()方法处理。
<%
String pname=(String) request.getAttribute("pname");
out.println(pname);
%>
<br/><br/>
拿到其它....该产品的信息.略。。。
<br/><br/>
<a style="display:block;width:100px;height:35px;line-height:35px;background:red;text-decoration:none;color:#fff;" href="<%=request.getContextPath()%>/addCart.pdo?pname=<%=pname %>">加入购物车</a>
</body>
4.addCart(),添加物品到车中(shoppingcart.jsp页面),
private void addCart(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String pname = req.getParameter("pname");
//添加购物车
HttpSession session =req.getSession(true); //如果session空间是空的时候,也创建一个session空间
List products =(List<String>) session.getAttribute("car");
if(products==null) {
products =new ArrayList<>();
}
products.add(pname);
session.setAttribute("car", products);
resp.setCharacterEncoding("UTF-8");
resp.sendRedirect(req.getContextPath()+"/shopping/shoppingcart.jsp");//重定向,即request不携带数据,也可由session传数据,只要不关闭浏览器就行。
}
5.shoppingcart.jsp 购物车,该页面会显示所有物品。
<body>
<%
List<String> products=(List<String>) session.getAttribute("car");
out.println("你的购车里面有如下产品: "+"<br/>");
for(String s:products){
out.println(s.toString()+"<br/><br/>");
}
%>
</body>
用户登录,权限控制(过滤器),保存登录状态,在线用户情况
项目名:mvcproject
数据库:jdbc_01
表:t_users, t_online
- 数据库连接池设置与工具:
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<c3p0-config>
<named-config name="mysql">
<!-- 连接myslq数据库的基本必须的信息的配置 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc_01</property>
<property name="user">root</property>
<property name="password">xiong</property>
<!-- 若数据库中的连接数量不足的时候,向数据库申请的连接数量 -->
<property name="acquireIncrement">5</property>
<!-- 初始化数据库连接池时连接的数量 -->
<property name="initialPoolSize">10</property>
<!-- 数据库连接池中的最小的数据库连接数 -->
<property name="minPoolSize">5</property>
<!-- 数据库连接池中的最大的数据库连接数 -->
<property name="maxPoolSize">100</property>
<!-- C3P0数据库连接池可以维护的Statement数量 -->
<property name="maxStatements">2</property>
<!-- 每个连接同时可以使用Statement的数量 -->
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
JdbcUtils.java
/**
* jdbc工具类
* @author Administrator
*
*/
public class JdbcUtils {
//数据库连接池,C3P0
private static DataSource dataSource = null;
static { // 静态代码块只会被执行一次
dataSource = new ComboPooledDataSource("mysql");
}
/**
* 获取到数据库mysql的数据连接对象conn
* @return
*/
public static Connection getConnection() {
Connection conn = null;
try {
conn = dataSource.getConnection();
return conn;
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* 是通用的关闭数据库连接对象的方法
* @param conn
*/
public static void closeConn(Connection conn) {
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void rollbackTransation(Connection conn) {
if(conn!=null) {
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
- 模型
User.java 与online.java
public class User {
/**
* 用户编号
*/
private int id;
/**
* 用户名称
*/
private String username;
/**
* 用户密码
*/
private String password;
/**
* 用户电话
*/
private String phoneNo;
/**
* 用户地址
*/
private String address;
/**
* 用户注册日期
*/
private Date regDate;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhoneNo() {
return phoneNo;
}
public void setPhoneNo(String phoneNo) {
this.phoneNo = phoneNo;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Date getRegDate() {
return regDate;
}
public void setRegDate(Date regDate) {
this.regDate = regDate;
}
public User() {
super();
}
public User(int id, String username, String password, String phoneNo, String address, Date regDate) {
super();
this.id = id;
this.username = username;
this.password = password;
this.phoneNo = phoneNo;
this.address = address;
this.regDate = regDate;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", pasword=" + password + ", phoneNo=" + phoneNo
+ ", address=" + address + ", regDate=" + regDate + "]";
}
}
/**
* 用户统计在线人
* @author Administrator
*
*/
public class Online {
private String ssid;
private String username;
private String page;
private String ip;
private Date time;
public String getSsid() {
return ssid;
}
public void setSsid(String ssid) {
this.ssid = ssid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public Online() {
super();
}
public Online(String ssid, String username, String page, String ip, Date time) {
super();
this.ssid = ssid;
this.username = username;
this.page = page;
this.ip = ip;
this.time = time;
}
@Override
public String toString() {
return "Online [ssid=" + ssid + ", username=" + username + ", page=" + page + ", ip=" + ip + ", time=" + time
+ "]";
}
}