JavaWeb(2):Session简介
参考书籍:《Pro Java for Web Apps》
注:演示所用 Java
版本为 Java8
,所用容器为 Tomcat8.5.51
会话用于处理维持请求和请求之间的状态。在没有使用会话时,HTTP
请求是无状态的,在浏览器打开第一个连接到服务器的套接字时开启,在服务器返回最后一个数据包时结束。而有些时候,我们希望保持状态,如用户登录或者在线编辑时,这时我们就要用到会话。
在Web
中,会话是由服务器或Web
应用程序管理的某些文件、内存片段、对象或者容器。服务器在第一次接收到请求时,会随机生成一串字符串,称为会话ID
,并返回用户浏览器中。之后所有从该用户浏览器中发出的请求都需要包含该会话ID
,服务器接收到会话ID
后可以将会话与请求关联起来。HTTP cookie
用于将会话ID
发送到服务器,但是如果用户浏览器禁止了cookie
,那么就需要将会话ID
内嵌在URL
中,很明显,这种方式使得其他人可以轻松地获得会话,因此是不安全的。不过由于如今许多网站都要求用户在访问时启用cookie
,因此我们可以不用顾虑这点。
会话也是有漏洞的。但是由于描述起来篇幅过长,因此不做赘述,如果感兴趣的话可以在 Session hijacking -Wikipedia 中查看。
大部分情况下我们可以直接使用会话,不需要添加显式配置,但是出于安全目的,我们应该进行配置。使用<$session-config$>标签进行配置,同时在<$session-config$>标签内,我们也可以使用<$cookie-config$>标签进行cookie
的配置。所有在<$session-config$>标签和<$cookie-config$>标签内的标签都是可选的。下面列出了所有的可选标签:
<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<name>JSESSIONID</name>
<domain>example.org</domain>
<path>/path</path>
<comment><! [CDATA[Keeps you logged in. See our privacy policy for more information.]]></comment>
<http-only>true</http-only>
<secure>false</secure>
<max-age>180</max-age>
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
<tracking-mode>URL</tracking-mode>
<tracking-mode>SSL</tracking-mode>
</session-config>
下面为每个标签的作用:
标签 | 作用 |
---|---|
<$session-timeout$> | 会话在无效前可以保持不活跃状态的时间,以分钟为单位,为 $0$ 表示永远不过期。 |
<$tracking-mode$> | 表示容器使用哪种技术追踪会话ID,可以配置多个值,按照配置顺序使用。URL 表示容器将在URL 中内嵌会话ID,COOKIE 表示使用cookie ,SSL 表示使用SSL 会话,但要求所有请求均是HTTPS 请求。 |
<$name$> | 可以自定义会话cookie 的名字,通常不用设置。 |
<$domain$> | 设置cookie 的Domain 特性,通常不用设置。 |
<$path$> | 设置cookie 的Path 特性,通常不用设置。 |
<$comment$> | 可以添加任意文本,用于解释cookie 。 |
<$http-only$> | 设置cookie 的HttpOnly 特性,为了提高安全性,一般都设置为 $true$ 。 |
<$secure$> | 设置cookie 的Secure 特性,如果使用的是HTTPS ,就应设置为 $true$ 。 |
<$max-age$> | 设置cookie 的Max-Age 特性,控制cookie 何时过期,以秒为单位,通常不用设置。 |
学习了如何配置会话之后,就该学习如何使用会话了。为了获取会话,我们可以调用 $HttpServletRequest.getSession(\ )$ 方法。该方法不接受或者接受一个 $boolean$ 类型的参数。无参或者传入 $true$ 时会在没有会话时创建会话,传入 $false$ 则不会创建。调用该方法后我们就得到了一个 $javax.servlet.http.HttpSession$ 类型。对于该对象,常用方法如下:
方法 | 作用 |
---|---|
$getAttribute$ | 返回会话中储存的对象。 |
$getAttributeNames$ | 返回会话中所有特性的名字的枚举。 |
$setAttribute$ | 将对象绑定到会话中。 |
$removeAttribute$ | 移除会话中的特性。 |
$getId$ | 返回会话ID 。 |
$getCreationTime$ | 返回会话对象的创建时间。 |
$getLastAccessedTime$ | 返回最后一个包含该会话ID 的请求的时间。 |
$getMaxInactiveInterval$ | 返回<$session-timeout$>中设置的时间。 |
$setMaxInactiveInterval$ | 设置最长不活跃状态时间。 |
$invalidate$ | 销毁会话并解除所有绑定到会话的数据,常用于用户注销。 |
以下为一个简单的使用会话的例子。我们首先在部署描述符中添加以下配置信息:
<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<http-only>true</http-only>
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
之后创建 $Servlet$:
@WebServlet (name = "testServlet", urlPatterns = "/test")
public class TestServlet extends HttpServlet {
private final Map<Integer, String> map = new Hashtable<>();
static {
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
if (session.getAttribute("map") == null) session.setAttribute("map", map);
request.getRequestDispatcher("/WEB-INF/jsp/view.jsp").forward(request, response);
}
}
在 $view.jsp$ 中,我们创建如下语句:
<%--@elvariable id="map" type="java.util.Map"--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<c:forEach items="${map}" var="map">
<c:out value="key: ${map.key} value: ${map.value}"/><br/>
</c:forEach>
</body>
</html>
在上例中我们使用了 $getSession$ 获取会话对象,之后使用 $getAttribute$ 查询会话特性,再使用 $setAttribute$ 设置会话特性,在 $view.jsp$ 中,我们使用 <$c:forEach$> 进行遍历,<$c:out$>标签进行输出。因为 $session$ 是jsp
中的隐式变量,所以可以直接使用。