访问存在的 Servlet 返回 HTTP Status 404 Not Found.
问题
按照 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>