Session详解之web服务开发

来源:互联网 发布:js代码怎么用 编辑:程序博客网 时间:2024/04/28 20:00

  1.先了解一下java中session的简单用法:

  import javax.servlet.http.HttpSession; 需要引入servlet-api.jar

  HttpSession session = request.getSession();

  session.setAttribute("变量名", 值对象);

  session.getAttribute("变量名"); 此时取出来的是Object, 一般需要强转

  session.removeAttribute("变量名");

  session.invalidate(); 删除所有session中保存的键

  上一次我们已经实现了一个简单的web服务器版本,能够实现一些基本功能,但是在最后也提到了这个版本由于不支持session并不能实现真正的动态交互,这一次我们就来完成这一功能。

  2.介绍Session实现原理

  凡是搞过web开发的都知道,多数情况下浏览器请求服务器使用的是http请求,而http请求是无状态的,也就是说每次请求服务器都会新建连接,当得到响应后连接就关闭了,虽然http1.1支持持久连接(keep-alive),但是其最用主要是避免每次重建连接,而非解决用户在线状态等业务上的需求。而如果服务器想知道客户端的状态或是识别客户端,那么就不能像长连接那样通过连接本身实现,而是要通过每次请求时的数据来判断。

  流程图如下



  3.关于session的生命周期

  以下情况,Session结束生命周期,Servlet容器将Session所占资源释放:

  1.客户端关闭浏览器

  2.Session过期

  3.服务器端调用了HttpSession的invalidate()方法。

  "一个浏览器就是一个新session,关了浏览器session就结束了" session 是在服务器端建立的,浏览器访问服务器会有一个sessionid,浏览器端通过sessionid定位服务器端的session,session的创建 和销毁由服务器端控制。当浏览器关闭后,session还存在在服务器端,只不过你新开的浏览器去访问服务器会创建另一个session,这个时候的 sessionid已经不一样了。也就不能访问上一次的哪个session里面的内容了。

  "session的创建和销毁由服务器端控制",服务器端才有session,客户端只是通过sessionid来匹配session. 那服务器端session如何建的呢?

  普通html不会创建,jsp默认是创建的,只要你访问任何一个jsp就会创建(不过只创建一次),你关闭浏览器重新访问又会创建一个,这些创建的session由服务器自己控制销毁,你也可以在服务器端代码中销毁。 什么情况下需要用上这种服务器端的session方式?

  默认情况下,jsp被访问就会创建session(最开始是空的没有数据的),你的应用中的代码只是往session里面put数据。网上说可以 通过 <%@ page session="false"%>来不让jsp自动创session.我自己测试了一下(用sessionlistener),根本不起作用, session照样创建成功。 最后说一下,只有服务器端才有session.客户端被存到本地的是cookie.不过安全性低。所以不能放重要的数据。

  =====================================================================

  =======

  sesion其实简单: 先 request.getsession(),当已有一个session与前request相关时就返回对这个 session的引用,当没有时就生成一个.一个session在server通过一个sessionid来标识的。也就是说在一个server是不会有 两个相同sessionid的session.

  4.案例详解

  ** * session数据 * @author guojing * @date 2014-3-17 *

  public class HttpSession {

  Map String, Object map = new HashMapString, Object ();

  Date lastVisitTime = new Date(); 最后访问时间

  ** * session数据 * @author guojing * @date 2014-3-17 *

  public class HttpSession {

  Map map = new HashMap();

  Date lastVisitTime = new Date(); 最后访问时间

  public void addAttribute(String name, Object value) {

  map.put(name, value);

  }

  public Object getAttribute(String name) {

  return map.get(name);

  }

  public Map getAllAttribute() {

  return map;

  }

  public Set getAllNames() {

  return map.keySet();

  }

  public boolean containsName(String name) {

  return map.containsKey(name);

  }

  public Map getMap() {

  return map;

  }

  public void setMap(Map map) {

  this.map = map;

  }

  public Date getLastVisitTime() {

  return lastVisitTime;

  }

  public void setLastVisitTime(Date lastVisitTime) {

  this.lastVisitTime = lastVisitTime;

  }

  }** * 全局数据和会话相关数据,单例 * @author guojing * @date 2014-3-17 *

  public class ApplicationContext {

  private Map appMap = new HashMap();

  ApplicationContext全局数据 ** * 这里自己也有点搞不清sessionMap是不是有必要考虑线程安全,还请指教 *

  private ConcurrentMap sessionMap = new ConcurrentHashMap();

  session数据

  private ApplicationContext(){ }

  ** * 内部类实现单例 *

  private static class ApplicationContextHolder {

  private static ApplicationContext instance = new ApplicationContext();

  }

  TAG:

  public static ApplicationContext getApplicationContext() {

  return ApplicationContextHolder.instance; }

  public void addAttribute(String name, Object value) {

  ApplicationContextHolder.instance.appMap.pu

  public static ApplicationContext getApplicationContext() {

  return ApplicationContextHolder.instance;

  }

  public void addAttribute(String name, Object value) {

  ApplicationContextHolder.instance.appMap.put(name, value);

  } public Object getAttribute(String name) {

  return ApplicationContextHolder.instance.appMap.get(name);

  } public Map getAllAttribute() {

  return ApplicationContextHolder.instance.appMap;

  } public Set getAllNames() {

  return ApplicationContextHolder.instance.appMap.keySet();

  } public boolean containsName(String name) {

  return ApplicationContextHolder.instance.appMap.containsKey(name);

  } public void addSession(String sessionId) {

  HttpSession httpSession = new HttpSession();

  httpSession.setLastVisitTime(new Date());

  ApplicationContextHolder.instance.sessionMap.put(sessionId, httpSession);

  } ** * 获取session *

  public HttpSession getSession(HttpExchange httpExchange) {

  String sessionId = getSessionId(httpExchange);

  if (StringUtil.isEmpty(sessionId)) {

  return null;

  }

  HttpSession httpSession = ApplicationContextHolder.instance.sessionMap.get(sessionId);

  if (null == httpSession) {

  httpSession = new HttpSession();

  ApplicationContextHolder.instance.sessionMap.put(sessionId, httpSession);

  } return {

  httpSession;

  } ** * 获取sessionId *

  public String getSessionId(HttpExchange httpExchange) {

  String cookies = httpExchange.getRequestHeaders().getFirst("Cookie");

  String sessionId = "";

  if (StringUtil.isEmpty(cookies)) {

  cookies = httpExchange.getResponseHeaders().getFirst("Set-Cookie");

  } if (StringUtil.isEmpty(cookies)) {

  return null;

  }

  String[] cookiearry = cookies.split(";");

  for(String cookie : cookiearry){

  cookie = cookie.replaceAll(" ", "");

  if (cookie.startsWith("EH_SESSION=")) {

  sessionId = cookie.replace("EH_SESSION=", "").replace(";", "");

  } } return sessionId;

  } ** * 获取所有session *

  public ConcurrentMapString, HttpSession getAllSession() {

  return ApplicationContextHolder.instance.sessionMap;

  } ** * 设置session最后访问时间 * public void setSessionLastTime(String sessionI

  public ConcurrentMap getAllSession() {

  return ApplicationContextHolder.instance.sessionMap;

  }

  ** * 设置session最后访问时间 *

  public void setSessionLastTime(

  String sessionId) {

  HttpSession httpSession = ApplicationContextHolder.instance.sessionMap.get(sessionId);

  httpSession.setLastVisitTime(new Date()); }}View Code

  可以看出这两部分代码十分简单,下边看一下handle中如何处理session:

  public void handle(HttpExchange httpExchange) throws IOException {

  try {

  String path = httpExchange.getRequestURI().getPath();

  log.info("Receive a request,Request path:" + path); 设置sessionId

  String sessionId = ApplicationContext.getApplicationContext() .getSessionId(httpExchange);

  if (StringUtil.isEmpty(sessionId)) {

  sessionId = StringUtil.creatSession();

  ApplicationContext.getApplicationContext().addSession(sessionId);

  } .....其他代码省略

  }

  catch (Exception e) {

  httpExchange.close();

  log.error("响应请求失败:", e);

  }

  }

  ** * 调用对应Controller处理业务 * @throws UnsupportedEncodingException * private ResultInfo invokController(HttpExchange httpExchange) throws UnsupportedEncodingException { 获取参数

  Map map = analysisParms(httpExchange); IndexController controller = new IndexController();

  设置session HttpSession httpSession = ApplicationContext.getApplicationContext().getSession(

  httpExchange); log.info(httpSession);

  map.put("session", httpSession);

  return controller.process(map); }

  View Code

  最后看一下定时任务的实现:

  ** * 定时清理过期session * @author guojing * @date 2014-3-17 *public class

  SessionCleanTask extends TimerTask { private final Log log = LogFactory.getLog(SessionCleanTask. class );

  @Override public void run() { log.info( 清理session...... );

  ConcurrentMap String, HttpSes

  SessionCleanTask extends TimerTask { private final Log log = LogFactory.getLog(SessionCleanTask.class);

  @Override public void run() { log.info("清理session......");

  ConcurrentMap sessionMap = ApplicationContext.getApplicationContext() .getAllSession();

  Iterator<map.entry> it = sessionMap.entrySet().iterator();

  while (it.hasNext()) { ConcurrentMap.Entry entry= (Entry) it.next();

  HttpSession httpSession= entry.getValue();

  Date nowDate = new Date(); int diff = (int) ((nowDate.getTime() - httpSession.getLastVisitTime().getTime())100060);

  if (

  diff > Constants.SESSION_TIMEOUT) { it.remove(); }

  }

  log.info("清理session结束");

  }

  }

  View Code

  此次改动的代码就这么多。

  本次实现的功能应该说是点睛之笔,session的实现从根本上提供了动态交互的支持,现在我们能够实现登陆之类的功能的。但是正如上边提到的,现在整个项目还很死板,我们目前只能使用一个controller,想要实现多个则需要根据请求参数进行判断,那么下一版本我们就来处理这一问题,我们将通过注解配置多个controller,并通过反射来进行加载。

  5、最后来测试代码

  下边我们来测试一下是否有效。由于目前controller是写死的,只有一个IndexController可用,那么我们就将就着用这个来测试吧,我们先来改一下其process方法的代码:

  public ResultInfo process(Map map){

  ResultInfo result =new ResultInfo(); 这里我们判断请求中是否有name参数,如果有则放入session,没有则从session中取出name放入map

  HttpSession session = (HttpSession) map.get("session");

  if (map.get("name") != null) {

  Object name = map.get("name");

  session.addAttribute("name", name);

  } else {

  Object name = session.getAttribute("name");

  if (name != null) {

  map.put("name", name);

  }

  }

  result.setView("index");

  result.setResultMap(map);

  return result;

  }

(文章来源:http://www.mfqyw.com/)

0 0