Servlet实践-留言版-v2

功能介绍:

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

 

posted @ 2017-12-12 23:44  Aristole  阅读(394)  评论(0编辑  收藏  举报