- 什么是Session
上一篇中,cookie被容器作为响应发送给并浏览器被其保存,归根到底cookie是保存在客户端浏览器中随以后的请求一同发送的数据,只要每次客户端有这样一些flag“会话”就得以继续;cookie对象不仅有name-value属性还可以有sid(简写)属性,也是由服务器响应后被浏览器保存在客户端,随后当客户在请求该域时sid被浏览器自动填写进首部中,但是与上一篇中不同,cookie中携带的不再时服务器从客户获取并发回的value-name数据,而是sid,这里有这样一种倾向:即name-value保存一些可以暴露的用户信息,比如用户偏好,而sid保存的服务器中对应的session对象的id,仅仅是id,这里就要讲到session了,session被容器创建后应该是作为全局变量的保存的,即容器中的组件都可以访问该“数据结构”,只要req去获取session,容器就根据客户请求中的sid返回匹配的session对象,然后session中保存artribute就可以被程序员得到。但是容器第一次给客户端
cookie时和上一篇的方式不同,只要程序员req.getsession"(),容器便创建s对象,并填充进cookie对象随后发送给客户端,客户端浏览器保存该携带sid的cookie。
注意:把session当作是全局变量,容器有一套自己的管理机制,因此作为和servlet一样级别的组件可以在部署文件中被配置。
结构目录:
- LoginServlet.java
package servlet; import java.io.IOException; import java.io.PrintWriter; 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 util.OutputSessionInfo; //第一次访问,假想为登陆页面;如果用户登陆后再次登陆,且服务器端session还没有失效,则获取sesionid及用户信息直接填表单 public class LoginServlet extends HttpServlet{ private static final long serialVersionUID = -154176561953216931L; public void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException { res.setContentType("text/html;charset=gb2312"); HttpSession session = req.getSession();//session是全局的吧?调用获取sesion时,应用创建sesion对象全局保存?那么每一次获得否会发送吗? String user = (String) session.getAttribute("user"); // String user =null; PrintWriter out = res.getWriter(); out.println("<html>"); out.println("<meta http-equiv="param" content="no-cache">"); out.println("<head><title>登陆页面</title></head>"); out.println("<body>"); OutputSessionInfo.printSessionInfo(out, session);//调用工具 out.println("<p>"); out.println("<form method=post action=loginchk>"); out.println("<table>"); out.println("<tr>"); out.println("<td>请输入用户 名</td>"); if(null==user) { out.println("<td><input type=text name=user></td>"); }else { out.println("<td><input type=text name=user value="+user+"></td>"); } out.println("</tr>"); out.println("<tr>"); out.println("<td>请输入密码</td>"); out.println("<td><input type=password name=password></td>"); out.println("</tr>"); out.println("<tr>"); out.println("<td><input type=reset value=重填></td>"); out.println("<td><input type=submit value=提交></td>"); out.println("</tr>"); out.println("</table>"); out.println("</form>"); out.println("<body>"); out.println("<html>"); out.close(); } public void doPost(HttpServletRequest req,HttpServletResponse res) throws ServletException,IOException{//传递给get doGet(req,res); } }
该程序会发送一个登陆页面给浏览器,填写表单后被交给验证程序。
- LoginChkServlet.java
package servlet; import java.io.IOException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; //第二次访问,客户端携带sessionid发送请求;理解为登陆程序,判断用户的合法性保证会话中保存的是合法的用户信息,合法则给客户端设置sessionId,携带用户信息,最后跳转到合理的页面 public class LoginChkServlet extends HttpServlet{ private static final long serialVersionUID = 7607414497209254926L; public void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException { req.setCharacterEncoding("gb2312"); String name = req.getParameter("user"); String pwd = req.getParameter("password");//获取请求参数 if(null==name || null==pwd || name.equals("") || pwd.equals("")) { res.sendRedirect("login");//重定向到登陆页面 return; }else {//重定向时,请求对象更新,但是会携带sessionid请求头部 HttpSession session = req.getSession();//从全局变量中去获取ssesion,请求对象自动根据请求头的seesionid去全局中找到该对应的对象,该对象保存了其他状态 session.setAttribute("user", name); res.sendRedirect("greet");//值得注意的是:如果不是新创建的sesion,重定向是不回发送sesionid头部的,新的会话会发送;不只是重定向,转发也是一样!因为本质都是res/req return; } } public void doPost(HttpServletRequest req,HttpServletResponse res)throws IOException { doGet(req,res); } }
表单为空则让用户重新登陆;非空则验证且容器创建session对象填充用户数据,并重定向到处理页面/程序(或假想为首页),可以查看浏览器控制台,set-cookie携带着sid被 作为响应首部的一部分发送给客户端,于是浏览器在内存中保存该数据,以后的请求中都会在请求首部中携带该sid。
- GreetServlet.java
package servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import util.OutputSessionInfo; /**真正所要做的,其实就是从服务器set-sid后会话开始,让客户端持续地发送sid,结束只有两种情形:客户端丢失了sid,即关闭浏览器或页面(当客户端被开启新回话时,将导致旧会话在服务器丢失); * 服务端丢失s对象,即客户一定时间内没有进行会话(但是请求仍携带sid,服务器找不到s对象,将新创建s)。 * * 服务器获取请求首部中的sid并判断,这里获取sid时,如果客户操作时间太长导致服务端销毁s对象,则将导致服务器端找不到与请求头部sid匹配的s对象,重新登陆; * 如果客户端强制清理了sid即不发送sid请求头,则组件获取到容器中新创建的s对象,s对象携带的属性肯定为null,需要去登陆重新建立会话; * **/ //用户合法则会话已经完整,因为s对象已创建并发送给客户,属性已保存了s对象。下面是会话阶段,即让程序变得有状态!! public class GreetServlet extends HttpServlet{ public void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException { HttpSession session = req.getSession(); String user = (String) session.getAttribute("user"); if(null==user) { res.sendRedirect("login"); }else { res.setContentType("text/html;charset=gb2312"); PrintWriter out=res.getWriter(); out.println("<html><head><title>欢迎页面</title></head>"); out.println("<body>"); OutputSessionInfo.printSessionInfo(out, session); out.println("<p>"); out.println("欢迎你,"+user+"</p>"); out.println("<a href=login>重新登录</a>"); out.println("<a href=logout>注销</a>"); out.println("</body></html>"); out.close(); } } public void doPost(HttpServletRequest req,HttpServletResponse res)throws IOException { } }
该程序会获取请求中的sid,如果服务端新创建session对象说明客户端丢失了携带sid的cookie或者服务端销毁了session对象,重新登陆;如果请求中有携带了sid的cookie,并 且容器中session持续有效,则展示输出session中的数据。
- session的部署
总结:服务器根据sid可以从容器中众多的session找到对应的与客户sid匹配的session,session在被容器管理,由程序获取session始创建,设置时间到期后销毁。应用中考虑具体情况创造性使用即可,这里只记录其本质内容。