1. 程式人生 > >Servlet實踐-留言版-v2

Servlet實踐-留言版-v2

doget() warn rdp nic 提交 out sub ref pan

功能介紹:

  為留言板-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>

Servlet實踐-留言版-v2