為留言板-v1添加登錄功能,使用監聽器檢測會話的變化、維護活躍會話列表 ...
功能介紹:
為留言板-v1添加登錄功能
如何實現登錄功能:
1.在doGet()中檢查會話中是否包含了username特性,若包含了,則表示已經登錄,將重定向到留言板列表頁面。若不存在,則設置請求特性loginFailed為false(也就是說不是因為登錄不匹配而導致登錄失敗),將請求轉發到登錄頁面。
2.當用戶以post的方式提交登錄表單時,在doPost()方法中將用戶提交的登錄信息與資料庫中的登錄信息比較,若一致,就重定向到留言板列表頁面;若不一致,則設置請求特性loginFailed為true,將請求轉發到登錄頁面
如何實現註銷功能:
獲取HttpSession對象session,若包含請求參數logout,則調用session.invalidate()使當前會話無效,並重定向至登錄頁面。
使用監聽器檢測會話的變化:
使用HttpSessionListener和HttpSessionIdListener監聽器,它們會捕獲會話事件。
使用註解、編程或者部署描述符中聲明等方式註冊監聽器
重寫相應的方法:
1.當會話創建時,將調用sessionCreated(HttpSessionEvent e)方法
2.當會話無效時,將調用sessionDestoryed(HttpSessionEvent e)方法
3.當使用請求的changeSessionId()方法改變會話ID時將調用sessionIdChanged()方法
維護活躍會話列表:
在SessionRegistry類中,維護了一個靜態的Map(以會話ID為鍵,以對應的會話對象為值),當創建會話、銷毀會話、更新會話ID時,對應地在這個map中添加新會話對象、移除對應會話對象、更新會話對象。
loginServlet.java
package cn.example; import java.io.IOException; import java.util.Hashtable; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet( name ="loginServlet", urlPatterns = "/login" ) public class LoginServlet extends HttpServlet{ // 創建一個用戶資料庫 private static final Map<String, String> userDatabase = new Hashtable<String, String>(); static{ userDatabase.put("Nicholas", "password"); userDatabase.put("Sarah", "drowssap"); userDatabase.put("Mike", "wordpass"); userDatabase.put("John", "green"); } // 顯示登錄界面 @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); // 添加註銷功能 if(request.getParameter("logout") != null){ session.invalidate(); response.sendRedirect("login"); return; }else if(session.getAttribute("username") != null){ // 檢測用戶是否已經登錄(username特性是否存在),若已經登錄,就他們重定向至票據頁面 response.sendRedirect("tickets"); return; } // 未登錄,將請求特性中的loginFailed設置為false,將請求轉發到登錄界面 request.setAttribute("loginFailed", false); request.getRequestDispatcher("/WEB-INF/jsp/view/login.jsp").forward(request, response); } // 處理登錄信息 @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 檢測用戶是否已經登錄(username特性是否存在),若已經登錄,就他們重定向至票據頁面 HttpSession session = request.getSession(); if(session.getAttribute("username") != null){ response.sendRedirect("tickets"); return; } String username = request.getParameter("username"); String password = request.getParameter("password"); // 登錄失敗,設置請求特性loginFailed為true if(username == null || password == null || !LoginServlet.userDatabase.containsKey(username) || !password.equals(LoginServlet.userDatabase.get(username))){ request.setAttribute("loginFailed", true); request.getRequestDispatcher("/WEB-INF/jsp/view/login.jsp").forward(request, response); }else{ // 登錄成功,把用戶名存放在session中 session.setAttribute("username", username); request.changeSessionId(); response.sendRedirect("tickets"); } } }
SessionListener.java
package cn.example; import java.text.SimpleDateFormat; import java.util.Date; import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionIdListener; import javax.servlet.http.HttpSessionListener; @WebListener public class SessionListener implements HttpSessionListener, HttpSessionIdListener{ private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public void sessionIdChanged(HttpSessionEvent e, String oldSessionId) { SessionRegistry.updateSessionId(e.getSession(), oldSessionId); System.out.println(this.date() + ": Session ID " + oldSessionId + " changed to " + e.getSession().getId()); } @Override public void sessionCreated(HttpSessionEvent e) { SessionRegistry.addSession(e.getSession()); System.out.println(this.date() + ": Session " + e.getSession().getId() + " created." ); } private String date() { return this.formatter.format(new Date()); } @Override public void sessionDestroyed(HttpSessionEvent e) { SessionRegistry.removeSession(e.getSession()); System.out.println(this.date() + ": Session " + e.getSession().getId() + " destoryed."); } }
SessionRegistry.java
package cn.example; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Map; import javax.servlet.http.HttpSession; /* * 一個註冊表,用來保存活躍會話的引用 */ public final class SessionRegistry { private static final Map<String, HttpSession> SESSIONS = new Hashtable<String, HttpSession>(); public static void addSession(HttpSession session){ SESSIONS.put(session.getId(), session); } public static void updateSessionId(HttpSession session, String oldSessionId){ synchronized (SESSIONS) { SESSIONS.remove(oldSessionId); addSession(session); } } public static void removeSession(HttpSession session){ SESSIONS.remove(session.getId()); } public static List<HttpSession> getAllSession(){ return new ArrayList<HttpSession>(SESSIONS.values()); } public static int getNumberOfSessions(){ return SESSIONS.size(); } private SessionRegistry(){} }
SessionListSertvlet.java
package cn.example; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /* * 顯示會話 */ @WebServlet( name = "sessionListServlet", urlPatterns = "/sessions" ) public class SessionListServlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 若用戶沒有登錄,就重定向到登錄界面 if(request.getSession().getAttribute("username") == null){ response.sendRedirect("login"); return; } request.setAttribute("numberOfSessions", SessionRegistry.getNumberOfSessions()); request.setAttribute("sessionList", SessionRegistry.getAllSession()); request.getRequestDispatcher("/WEB-INF/jsp/view/sessions.jsp").forward(request, response); } }
login.jsp
<!DOCTYPE html> <html> <head> <title>留言板</title> </head> <body> <h2>Login</h2> 你需要登錄到留言板<br/> <br/> <% if((Boolean)request.getAttribute("loginFailed")){ %> <b>用戶名或密碼錯誤</b><br/><br/> <% } %> <form method="post" action="<c:url value="/login"/> "> 用戶名:<br> <input type="text" name="username"/> <br/><br/> 密碼:<br/> <input type="password" name="password" /> <br/></br/> <input type="submit" value="Log In"/> </form> </body> </html>
session.jsp
<%@ page import="java.util.List" %> <%! private static String toString(long timeInterval){ if(timeInterval < 1_000) return "less than one second"; if(timeInterval < 60_000) return (timeInterval / 1_000) + " seconds"; return "about " + (timeInterval / 60_000) + " minutes"; } %> <% int numberOfSessions = (Integer) request.getAttribute("numberOfSessions"); List<HttpSession> sessions = (List<HttpSession>) request.getAttribute("sessionList"); %> <!DOCTYPE html> <html> <head> <title>留言板/title> </head> <body> <a href="<c:url value="/login?logout"/>">Logout</a> <h2>Sessions</h2> There are a total of <%= numberOfSessions %> active sessions in this application.<br/> <br/> <% long timestamp = System.currentTimeMillis(); for(HttpSession aSession : sessions){ out.print(aSession.getId() + " - " + aSession.getAttribute("username")); if(aSession.getId().equals(session.getId())) out.print(" (you)"); out.print("- last active " + toString(timestamp - aSession.getLastAccessedTime())); out.print(" ago<br/>"); } %> </body> </html
listTickets.jsp:
<%@ page session="false" import="java.util.Map" %> <% @SuppressWarnings("unchecked") Map<Integer,Ticket> ticketDatabase = (Map<Integer, Ticket>)request.getAttribute("ticketDatabase"); %> <!DOCTYPE html> <html> <head> <title>留言板</title> </head> <body> <h2>留言板</h2> <a href="<c:url value="/login?logout"/>">Logout</a><br/> <a href=" <c:url value="/tickets"> <c:param name="action" value="create"/> </c:url> ">創建留言</a><br/><br/> <% if(ticketDatabase.size() == 0){ %><i>留言板中沒有留言。</i><% } else{ for(int id : ticketDatabase.keySet()){ String idString = Integer.toString(id); Ticket ticket = ticketDatabase.get(id); %>留言 #<%= idString %> : <a href=" <c:url value="/tickets"> <c:param name="action" value="view"/> <c:param name="ticketId" value="<%= idString %>"/> </c:url> "><%=ticket.getSubject() %></a>(用戶: <%= ticket.getCustomerName() %>) <br/> <% } } %> </body> </html>
ticketForm.jsp
<%@ page session="false" %> <!DOCTYPE html> <html> <head> <title>留言板</title> </head> <body> <a href="<c:url value="/login?logout"/>">Logout</a><br/> <h2>創建留言</h2> <form method="post" action="tickets" enctype="multipart/form-data"> <input type="hidden" name="action" value="create"/> 主題:<br/> <input type="text" name="subject"><br/><br/> 內容:<br/> <textarea name="body" rows="5" cols="30"></textarea><br/><br/> <b>附件:</b><br/> <input type="file" name="file1" /><br/><br/> <input type="submit" value="提交"/> </form> </body> </html>
viewTicket.jsp
<% String ticketId = (String) request.getAttribute("ticketId"); Ticket ticket = (Ticket) request.getAttribute("ticket"); %> <!DOCTYPE html> <html> <head> <title>留言版</title> </head> <body> <a href="<c:url value="/login?logout"/>">Logout</a><br/> <h2>留言 #<%=ticketId %>: <%= ticket.getSubject() %></h2> <i>用戶 - <%=ticket.getCustomerName() %></i> <br/><br/> <i>內容:</i><br/> <%= ticket.getBody() %> <br/><br/> <% if(ticket.getNumberOfAttachments() > 0){ %>附件:<% int i = 0; for(Attachment a:ticket.getAttachments()){ if(i++ > 0) out.print(", "); %> <a href=" <c:url value="/tickets"> <c:param name="action" value="download"/>\ <c:param name="ticketId" value="<%= ticketId %>"/> <c:param name="attachment" value="<%=a.getName() %>"/> </c:url> "><%=a.getName() %> </a><% } } %><br/> <a href="<c:url value="/tickets"/>">返回留言板主頁</a> </body> </html>