本文共 2827 字,大约阅读时间需要 9 分钟。
管理用户状态—— 由发表在
博客系统由多个功能(页面)组成:
在创建文章时,除了标题和内容,还需要知道是谁创建的这篇文章,当然我们不能够在表单中添加一个输入框让用户输入自己是谁——因为用户的身份很有可能被伪造。一个办法是在每一个页面被访问之前,我们要求用户输入在网站注册时输入的用户名/密码进行验证,如果验证通过才可以访问对应的页面。正好可以完成这样的功能,可是这样实在是太麻烦了,没访问一个页面都需要用户进行输入。
我们知道HTTP协议本身是无状态的,也就是说任何完全一致的请求都将会得到完全相同的返回。但是我们可以认为的在HTTP请求中定义状态。
是由客户端保存的小型文本文件,其内容为一系列的键值对,在浏览器访问同一个域名的不同页面时,会在HTTP请求中附上Cookie。
Cookie可以保存在内存中(关闭浏览器即消失),也可以保存在硬盘中(到达过期时间后消失)。另外,Cookie也是一个比较古老的东西,与JavaScript同样由网景公司发明,现已被标准化为RFC2109。
我们正是通过Cookie的这些特性来实现用户状态的保存的,每当用户访问一个网站时,服务器程序会分配给它一个唯一的id,这个id就是设置在Cookie中的,以打开浏览器第一次访问为例,因为是打开浏览器后第一次访问,所以请求头中不会有任何网站相关的Cookie存在,这时服务器会随机分配的一个字符串作为用户的id并放在Cookie中:
Set-Cookie:JSESSIONID=9074327855952DA4A296B67685523812; Path=/; HttpOnly
这里没有指定Cookie的过期时间(Expire),那么当浏览器关闭后,Cookie自动失效,从获取网站的Cookie到浏览器关闭的这个周期,被称为一个会话——Session。那么在这个会话中,在同一浏览器中任何一次对tianmaying.com
的访问,都会带上这个名字为JSESSIONID
(Servlet默认的名字)的Cookie值(在服务器上随机生成的字符串,服务器并会将其保存下来)。
可以简单地这样理解,服务端建立了一个Map<String, Object>
,对于每一个请求都可以拿到Cookie中保存的JSESSIONID
值,那么服务器程序可以往这个Map
里写入任何对象:
map.put(JSESSIONID,);
那么在这一次会话中,不管是怎样的请求,都可以访问到这个Map
中的对象。而服务器保存的这个Map
,也被称为)。Session是一种服务器端保存用户状态的技术,它最常见的实现方式是在Cookie中加入一个字段存储Session ID;但同时Cookie并不是实现Session的唯一手段,在URL中通过参数来保存Session ID同样也是可行的。
在注册用户后,用户需要登录网站来确认自己的身份,登录的方式就是在HTML表单中填入用户名和密码并提交给服务器进行验证。在浏览器的一次Session会话中,Cookie中的JSESSIONID
保持不变,所以登录成功(服务器端通过验证)后,我们可以在服务端Session中放入当前的用户对象,这样以后访问任何URL,在对应的JSP/Servlet中都能轻易的拿到它。以下是一个多用户访问的Web应用示意图:
可以看到,每一个用户都有一个自己的Session。而在JSP/Servlet中,通过API可以很容易的获取到当前用户的Session并将状态信息放入其中。
以用户登录为例:
@WebServlet("/account/login")public class LoginController extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String password = req.getParameter("password"); User user = Data.getByUsername(username); if (user == null || !user.getPassword().equals(password)) { //登录不成功,返回错误信息 } else { req.getSession().setAttribute("user", user); //返回登录成功信息 } }}
获取Session的API是req.getSession()
,接下来通过getAttribute()
和setAttribute()
方法就可以像一个Map
一样获取/设置Session的属性值。这里我们将User
对象放入了Session,名字为user
。
在渲染页面时,很多时候需要获取当前用户的信息,例如导航栏的显示:
在JSP Scriptlet中可以通过session
对象来获取Session的属性值,如果使用EL表达式,那么需要使用${sessionScope}
得到Session对象,下面以导航栏为例:
${sessionScope.user != null}
作为判断条件表示当前用户已经登录;href="userPosts?username=${sessionScope.user.username}"
则是利用当前用户的属性值渲染链接。
更多文章请访问