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表示使用cookieSSL表示使用SSL会话,但要求所有请求均是HTTPS请求。
<$name$> 可以自定义会话cookie的名字,通常不用设置。
<$domain$> 设置cookieDomain特性,通常不用设置。
<$path$> 设置cookiePath特性,通常不用设置。
<$comment$> 可以添加任意文本,用于解释cookie
<$http-only$> 设置cookieHttpOnly特性,为了提高安全性,一般都设置为 $true$ 。
<$secure$> 设置cookieSecure特性,如果使用的是HTTPS,就应设置为 $true$ 。
<$max-age$> 设置cookieMax-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中的隐式变量,所以可以直接使用。