上一次咱們已經實現了一個簡單的web服務器版本,可以實現一些基本功能,可是在最後也提到了這個版本因爲不支持session並不能實現真正的動態交互,這一次咱們就來完成這一功能。 html
/** * session數據 * @author guojing * @date 2014-3-17 */ public class HttpSession { Map<String, Object> map = new HashMap<String, Object>(); 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<String, Object> getAllAttribute() { return map; } public Set<String> getAllNames() { return map.keySet(); } public boolean containsName(String name) { return map.containsKey(name); } public Map<String, Object> getMap() { return map; } public void setMap(Map<String, Object> 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<String, Object> appMap = new HashMap<String, Object>(); // ApplicationContext全局數據 /** * 這裏本身也有點搞不清sessionMap是否是有必要考慮線程安全,還請指教 */ private ConcurrentMap<String, HttpSession> sessionMap = new ConcurrentHashMap<String, HttpSession>(); // session數據 private ApplicationContext(){ } /** * 內部類實現單例 */ private static class ApplicationContextHolder { private static ApplicationContext instance = new ApplicationContext(); } 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<String, Object> getAllAttribute() { return ApplicationContextHolder.instance.appMap; } public Set<String> 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 ConcurrentMap<String, HttpSession> getAllSession() { return ApplicationContextHolder.instance.sessionMap; } /** * 設置session最後訪問時間 */ public void setSessionLastTime(String sessionId) { HttpSession httpSession = ApplicationContextHolder.instance.sessionMap.get(sessionId); httpSession.setLastVisitTime(new Date()); } }能夠看出這兩部分代碼十分簡單,下邊看一下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<String, Object> 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); }最後看一下定時任務的實現:
/** * 定時清理過時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, HttpSession> sessionMap = ApplicationContext.getApplicationContext() .getAllSession(); Iterator<Map.Entry<String, HttpSession>> it = sessionMap.entrySet().iterator(); while (it.hasNext()) { ConcurrentMap.Entry<String, HttpSession> entry= (Entry<String, HttpSession>) it.next(); HttpSession httpSession= entry.getValue(); Date nowDate = new Date(); int diff = (int) ((nowDate.getTime() - httpSession.getLastVisitTime().getTime())/1000/60); if (diff > Constants.SESSION_TIMEOUT) { it.remove(); } } log.info("清理session結束"); } }這次改動的代碼就這麼多。
public ResultInfo process(Map<String, Object> 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://localhost:8899/page/index.page,請求結果以下(我那高大上的logo就不截了^_^):
說明session已經起做用了,你還能夠等sesion清理後看下是否還有效。ApplicationContext測試方法同樣。 java