前面了解了HTTP的无状态性
为了解决无状态的问题,有两种技术:Cookie和Session
学习了Cookie,现在来了解Session
无状态是指:服务器不会保存客户端-服务器会话的临时数据,每一次会话都是独立的
这会造成每次购物操作都需要重新登录,解决办法有两个:Cookie与Session
Cookie存储在客户端,Session存储在服务器
可以看到,当服务器给客户端创建了Cookie后,如果想要保持上下文的相关信息,就都需要在Request中带上Cookie
这就造成了一个很大的局限:Cookie如果很多,就会增加客户端与服务器的传输数据,而且由于浏览器会对Cookie做一定的限制,就不能保持太多的信息
为了解决这个局限,建立在Cookie上的Session就出现了
Session的作用就是在服务端保持数据,然后传递给客户端一个叫JSESSIONID 的Cookie,客户端仅需带着这个JSESSIONID 就可以获得保持的数据
在JavaWeb中,使用Session调用的是HttpSession接口的方法
既然是接口及抽象方法,那么具体是谁实现的呢?
HttpSession的具体实现是由服务器来完成的
比如tomcat,在tomcat的src中java\org\apache\catalina\session下的类StandardSession实现了HttpSession
(这个关系到Tomcat源码,就不往下深究了)
这些API各有什么作用?
API | 作用 |
---|---|
Object getAttribute(String); | 获取Session属性 |
Enumeration getAttributeNames(); | 获取Session所有的属性名 |
long getCreationTime() | 获取Session被创建时间 |
String getId() | 获取Session的id |
long getLastAccessedTime() | 返回Session最后活跃的时间 |
ServletContext getServletContext(); | 获取ServletContext对象 |
void setMaxInactiveInterval(int var1); | 设置Session超时时间 |
int getMaxInactiveInterval() | 获取Session超时时间 |
void setAttribute(String var1, Object var2); | 设置Session属性 |
void removeAttribute(String var1); | 移除Session属性 |
void invalidate(); | 销毁该Session |
boolean isNew(); | 判断该Session是否为新的 |
Session是一个域对象,类似与Servletcontext,可以用来保存数据、保存会话临时数据
编写一个存入数据的Servlet:
package Session;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class SessionTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//得到Session
HttpSession httpSession = req.getSession();
//存入数据
httpSession.setAttribute("name","zhangsan");
}
}
编写一个得到数据的Servlet:
package Session;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
public class SessionTest1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
String name = (String) session.getAttribute("name");
PrintWriter writer = resp.getWriter();
writer.write(name);
}
}
在web.xml中关联这两个Servlet
访问:http://localhost:8080/sessionTest
服务器给了客户端一个JSESSIONID
访问:http://localhost:8080/sessionTest1
还记得前面这个图,Web服务器直接调用静态页面,并不会经过Servlet容器
活跃时间,前面有一个API是getLastAccessedTime,获得Session最后一次活跃时间,也就是说服务器会更新客户端访问Session的时间
超时时间,随着客户的创建,Session会越来越多,通过超时时间来约束Session,Session的默认超时时间是30分钟
修改方式:
(1)在Tomcat下的web.xml中修改,会使所有使用该Tomcat的Web工程都改变(这个web.xml类似于所有工程配置的父类)
(2)在自己的工程的web.xml中设置,仅会影响自己的工程
(3)通过API设置:setMaxInactiveInterval(int var1),这里的单位是秒
注意:Session和Cookie所说的超时是不一样的,Session的超时时间是指空闲时间,多久没有访问该Session;而Cookie是超时时间是当Cookie创建时开始计算,不管有没有访问Cookie
钝化:当服务器正常关闭,还存活着的Session,会序列化到磁盘上,而不再占用内存空间,以文件(“SESSIONS.ser”)的形式存储在tomcat的work目录下(IDEA打开的存放在IDEA设置的本地地址)
虽然记事本打开乱码了,但是大致看的出确实是我们的Session
活化:Session 被钝化后,服务器再次调用Session对象时,将 Session对象由磁盘中加载到内存中使用
注意:
启动后:
如果想要设置钝化
(1)在tomcat里面 conf/context.xml 里面配置,对所有的运行在这个服务器的项目生效
(2)在conf/Catalina/localhost/context.xml 配置 ,对 localhost生效
(3)在自己的web工程项目中的 META-INF/context.xml,只对当前的工程生效
一个Context就是一个工程
配置:
<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="D:"/>
</Manager>
</Context>
maxIdleSwap代表空闲时间,一分钟没使用Session就钝化
directory表示钝化文件存储位置
使用Session时,服务器会自动创建一个Cookie,并设置Cookie属性为:
JSESSIONID=E7B846EA2368DAD4BDF71E1274AA42F2
可以看出Session是基于Cookie实现的,Session的真实数据存储在服务器,客户端凭借JSESSIONID可以使用该Session数据
该Cookie是服务器自己创建的,所有的属性都是默认值,maxAge值默认是-1,该Cookie仅当前浏览器使用,不可被持久化
如果浏览器禁用了Cookie,怎么使用Session?
HttpServletResponse类提供了两个URL地址重写的方法:
encodeURL(String url)
encodeRedirectURL(String url)
随便使用一个:在SessionTest中加上URL重写
String url = "/sessionTest1";
resp.sendRedirect(resp.encodeURL(url));
输入地址:http://localhost:8080/sessionTest
自动跳到sessionTest1,且在URL中带上参数JSESSIONID
URL重写方法会自动判断该浏览器是否支持Cookie,如果不支持Cookie,重写后的URL地址会带上jsessionid
既然Session受限与Cookie的默认属性,那么我们自定义一个Cookie,在将Session存储进Cookie中不就可以了?
Cookie cookie = new Cookie("JSESSIONID",session.getId());
当然,也可以暴力点,直接把Tomcat中的Session设置改了
修改Tomcat的配置文件server.xml
一个contenxt就是一个会话
在< Host>节点下增加< Context>节点,并设置path,docBase,debug和reloadable属性和一些session配置
<Context path="" docBase="webapp" debug="0" reloadable="false" sessionCookiePath="/" sessionCookieName=""/>
Tomcat配置
一般我们将WEB应用打包成WAR格式,然后拷贝到TOMCAT的WEBAPP目录下进行发布
在正常情况下,TOMCAT将自动解压WAR文件并生成对应的目录,而且会在内存中动态创建该WEB应用对应的CONTEXT路径。比如我们的WAR文件是JavaWeb.war,那么解压后的目录就是JavaWeb目录,在内存中动态创建的Context路径就是/JavaWeb。
在开发阶段这样的默认行为是可以接受的,但是在正式部署的情况下,我们通常需要修改应用的Context路径以适应我们的需要
如果我们想让用户仅仅输入域名来访问我们的JavaWeb应用,我们就需要修改Tomcat的Context设置
可以在conf/server.xml下增加一个context结点
<Context path="/javaweb" docBase="D:/JavaProject/JavaWeb" debug="0" reloadable="true">
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>