问题

按照 jsp+servlet实现简单登录页面功能Demo_qq_37306786的博客-CSDN博客,基于简单的 jsp 页面和 servelet 做一个登录 demo。

登录页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面 demo</title>
<style type="text/css">
    *{margin: 0;padding: 0;}
    form{margin: 0 auto;padding:15px; width: 300px;height:300px;text-align: center;}
    #submit{padding: 10px}
    #submit input{width: 50px;height: 24px;}
</style>
</head>
<body>
<div class="wrapper">
        <form action="<%=request.getContextPath()%>/loginDemo" method="post">
            <label>用户名:</label>
                <input type="text" name="userName" value="${param.userName}"/><br><br>
            <label>密码:</label>
                <input type="password" name="password"/><br>
                
            <font color="red">
                <%
                    if(request.getAttribute("message")!= null){
                        out.print(request.getAttribute("message"));
                    }
                %>
            </font>
            
            <div id="submit">
                <input type="submit" value="登录"/>
            </div>
        </form>
    
    </div>
</body>
</html>

登录成功页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录成功</title>
</head>
<body>
<%
    out.println("Hello World!");

%>    
    Hello: <br/>
    <font color="green" size="22">
        <%
            out.print(request.getParameter("userName")+"<br>");
        %>
    </font>
    <a href="<%=request.getContextPath()%>/login.jsp">重新登录</a>
</body>
</html>

登录 servlet

package com.seasidecrab.test;

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;

/**
 * Servlet implementation class LoginServlet
 */
@WebServlet("/loginDemo")
public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public LoginServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        String userName = request.getParameter("userName");
        String password = request.getParameter("password");
        System.err.println(userName + ":" + password);
        String myName = "jason";
        String myPsd = "123456";
        String errMsg = null;
        if (!myName.equals(userName)) {
            errMsg = "用户名不正确";
        } else if (!myPsd.equals(password)) {
            errMsg = "密码不正确";
        } else {
            response.sendRedirect(request.getContextPath() + "/index.jsp?userName=" + userName);
        }
        if (errMsg != null) {
            request.setAttribute("message", errMsg);
            request.getRequestDispatcher(request.getContextPath() + "/login.jsp").forward(request, response);
        }

//        String userName = request.getParameter("userName");
//        String password = request.getParameter("password");
//        System.err.println(userName + ";" + password);
//        String myUser = "Dong";
//        String myPwd = "5432100";
//        if (userName.equals(myUser) && password.equals(myPwd)) {
//            response.sendRedirect(request.getContextPath() + "/index.jsp?userName=" + userName);
//        } else {
//            request.setAttribute("message", "账密错误,请重新登录<br>");
//            request.getRequestDispatcher("/login.jsp").forward(request, response);
//        }

    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

注释部分为作者 demo 里的代码,测试(账号密码有错和无错都)可以正常返回。我修改的部分,主要加了对账户或者密码是否正确的分别判断。但此时当账号或者密码错误时,页面不是返回登录页面并显示错误信息,而是返回了 404 Not Found 页面。

解决

对比自己的代码和原作者的代码,主要区别在 getRequestDispatcher 方法实参上:

request.getRequestDispatcher(request.getContextPath() + "/login.jsp").forward(request, response);
request.getRequestDispatcher("/login.jsp").forward(request, response);

我自己修改的代码,可能是参考了上面账号密码正确跳转的例子:

response.sendRedirect(request.getContextPath() + "/index.jsp?userName=" + userName);

惯性地认为 getRequestDispatcher 的 path 参数也需要要 contextPath,其实不然。

检查了 sendRedirect 和 getRequestDispatcher 两个方法的定义说明,两者的实参都可以为相对地址,但两者的相对地址参照对象不同。sendRedirect 的相对地址相对的是 servlet 容器的根目录;getRequestDispatcher 的相对地址相对的是当前 context 上下文的根目录。

也就是说,sendRedirect 如果传参相对地址,则需要拼接上 contextPath;而 getRequestDispatcher 直接传当前目录下的地址。

所以,对 getRequestDispatcher 的 path 参数,去除不能要的 contextPath 即可:

request.getRequestDispatcher("/login.jsp").forward(request, response);

特别的

因为新版本使用了 webServlet 注解,可以直接传递 url-pattern 的值到 servlet 中,所以省略了形如以下内容的对 servlet 的配置和映射:

  <servlet>
      <servlet-name>LoginServlet</servlet-name>
      <servlet-class>com.seasidecrab.test.LoginServlet</servlet-class>
  </servlet>
  <servlet-mapping>
      <servlet-name>LoginServlet</servlet-name>
      <url-pattern>/loginDemo</url-pattern>
  </servlet-mapping>