Issue
I'm creating a Java web application using JSP and Servlets, TomCat 9 and IntelliJ. The tutorial I'm following uses Eclipse, where the instructor just runs the project as Run As > Run On Server and everything works seamlessly.
In IntelliJ, things seem all messed up.
This is my project structure -
This is the Run Configuration -
I have the web.xml
setup as -
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Archetype Created Web Application</display-name>
<welcome-file-list>
<welcome-file>login.do</welcome-file>
</welcome-file-list>
</web-app>
So, any requests to localhost:8080
, or in the case of IntelliJ, http://localhost:8080/jspservlet_war_exploded/
should be redirected to login.do
, which is handled by LoginServlet
-
package app;
import javax.servlet.RequestDispatcher;
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 java.io.IOException;
import java.io.PrintWriter;
@WebServlet(urlPatterns = "/login.do")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
String pass = req.getParameter("password");
req.setAttribute("name", name);
req.setAttribute("password", pass);
RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/login.jsp");
requestDispatcher.forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
req.setAttribute("name", name);
RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/welcome.jsp");
requestDispatcher.forward(req, resp);
}
}
At first, I was testing the doGet()
method in LoginServlet
, by just manually adding the ?name=xxx&password=xxx
query string in the start page - http://localhost:8080/jspservlet_war_exploded/
. These attributes were set in the request
and then forwarded to login.jsp
, which would just display the attribute values using ${name}
and ${password}
. Things worked fine until this step.
Then, I changed the login.jsp
page to include a simple form
that has an input field to enter the user's name, and have it sent to /login.do
via the action
attribute, using the POST
method. This is where things blew up.
Here is login.jsp
-
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Login Page</title>
</head>
<body>
<h1>Welcome</h1>
<p>Time on server is <%= new Date()%></p>
<%--<p>Your name is ${name} and password is ${password}</p>--%>
<p>pageContext.request.contextPath: ${pageContext.request.contextPath}</p>
<form action="/login.do" method="post">
<label for="inp">Enter your name </label>
<input id="inp" type="text" name="name"/>
<button>Submit</button>
</form>
</body>
</html>
which results in this page -
Now, as soon as I hit "submit", the request seems to go to localhost:8080/login.do
(because that's what the action
attribute's value is), and that throws an error -
Based on the other questions I've read here, it looks like that happens because the context path (ie. root of the application) is http://localhost:8080/jspservlet_war_exploded/
, and all locations are relative to this path(?). So, the recommended way seems to be ${pageContext.request.contextPath}
.
Based on that, if I change the action
attribute to action="${pageContext.request.contextPath}/login.do"
, then things work again.
However, now I'm trying to redirect from the doPost()
method in LoginServlet
to TodoServlet
, like so -
resp.sendRedirect("/todo.do");
This again causes a 404, because the URL becomes http://localhost:8080/todo.do
, whereas it should be http://localhost:8080/jspservlet_war_exploded/todo.do
.
How do I fix things so that all resources are deployed relative to http://localhost:8080/jspservlet_war_exploded/
by default, and I can just specify the URL pattern directly in action
or resp.sendRedirect()
?
Solution
Change the deployment context in the Run/Debug configuration:
If you want the app to work with any context you should use the relative paths instead like described here.
Instead of resp.sendRedirect("/todo.do");
use resp.sendRedirect("todo.do");
or resp.sendRedirect(req.getContextPath() + "/todo.do");
Answered By - CrazyCoder