I'm trying to make my page more efficient and so I got the question like below:
Is it possible to forward a new Jsp page with RequestDispatcher into an HTML div from the Servlet?
Like this:
someServlet.java
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException, ServletException {
// do something to send a page to the HTML div in page.jsp
}
page.jsp
<div> <!-- the forwarded page must inside here --> </div>
That's not possible. You can, instead, make an ajax call to your servlet and the servlet may return the necessary data in a format that will help the view to work. An example is by writing the response using JSON format, then handle this JSON response in JavaScript to add the necessary data in your view accordingly.
You could also return a "text/html" response where you write the content of the <div> with the necessary content to just write the HTML response directly in your view. The response used in this approach is easier to use in your view (JSP), but note that will couple your Servlet request to mere HTML responses only.
The decision is up to you.
More info:
How to use Servlets and Ajax?
Do in this way using include instead of forward in page.jsp.
<div> <!-- insert any one --> </div>
Try any one
<jsp:include page="includedPage" />
OR
<jsp:directive.include file="relative url" />
OR
<%# include file="relative url" >
OR
request.getRequestDispatcher("/WEB-INF/jsp/abc.jsp").include(request, response);
If a page is forwarded then it's the responsibility of the forward page to generate the HTML content but in case of include you can combine multiple HTML/JSP/Servlet outputs to generate the final HTML content.
Read more about JSP - The include Directive
Related
To make a request to Servlet, I need to use mapping inside XML file or add annotation for given Servlet. But why I am not required to do the same for JSP files as well? I will give examples.
How does this work?
index.html:
<html><body>
<form action="result.jsp">
<button>go</button>
</form>
</body></html>
result.jsp:
<html><body>
hello
</body></html>
Notice I didn't have to use any XML mappings nor annotations. It just "finds" it.
But how this doesn't work?
index.html:
<html><body>
<form action="com.example.MyServlet">
<button>go</button>
</form>
</body></html>
com.example.MyServlet:
public class MyServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter pw = resp.getWriter();
resp.setContentType("text/html");
pw.println("hello");
}
}
Here, I get error: The requested resource [/TestProject/com.example.MyServlet] is not available. How? How come I didn't need to use XML, nor annotations for JSP, but I had for Servlet? Shouldn't they work the same way, as JSP eventually turns to Servlet. So why is there different behavior? I know I am missing something, I just don't know what...
Why I need mapping or annotation for Servlet, but not for JSP?
As pointed out in the comment above from #SotiriosDelimanolis, that's not what actually happens. A JSP is eventually turned into a servlet and behaves like any other servlet you define on your own. And when you define a servlet you also need to add a URL mapping so that an URL path is resolved to a servlet that can respond to a request made for that URL.
The only difference is that for JSP files this mapping is done implicitly by the servlet container. For the servlets you define, you obviously need to define your own mapping because the server can't know what you want to do with the servlet in your own application.
The specifications says the following (emphasis mine):
A web component is either a servlet or a JSP page. The servlet element in a web.xml deployment descriptor is used to describe both types of web components. JSP page components are defined implicitly in the deployment descriptor through the use of an implicit .jsp extension mapping, or explicitly through the use of a jsp-group element.
and
[...] JSP page translated into an implementation class plus deployment information. The deployment information indicates support classes needed and the mapping between the original URL path to the JSP page and the URL for the JSP page implementation class for that page.
So basically, your JSP is translated into a servlet, and a mapping is created from your original JSP page location path to the servlet thus generated.
The JSP is not actually executed. What's executed is the servlet generated from the JSP. You have to realize that JSPs are provided for convenience. If you want to generate HTML from a servlet you have to do a whole bunch of out.write("<html>"); out.write("\r\n"); and so on, for your entire HTML page. It's not only very error prone, but you will go insane doing so. Thus, the option of providing an JSP combined with the things done behind the scene to make it all work.
I have a simple Maven servlet/jsp application that I deploy to a local Tomcat 9 (via Eclipse). JSP pages are stored under root folder (src\main\webapp\*.jsp) which when Maven installs a WAR, they go under the root folder (MyAppContext\*.jsp along side MyAppContext\META-INF\ and MyAppContext\WEB-INF\).
The servlets' URL patterns are annotated for each servlet, e.g. /doactionone, /doactiontwo, etc. Most servlets perform the dispatching to various JSP pages, but I do have a direct anchor link on one.
I wanted to move these JSP pages into their own respective directory, so I moved them to src\main\webapp\jsp\*.jsp folder, and when the Maven install is run, they get placed under MyAppContext\jsp\.
The only entry I have in web.xml is a welcome file that after relocating the JSP files, it points to jsp\doactionone.jsp which loads that corresponding JSP page. This page contains a simple form:
<form action="doactionone" method="post">
...
<a href="jsp/doactiontwo.jsp">
<input type="submit" />...
</form>
The submission on this page actually calls the right servlet (the one defined with doactionone URL pattern). I also have a link that takes the user to the second page (doactiontwo.jsp).
However, when I navigate to that second page via this link, which has another simple form (see below), and perform the submission (post), I see in browser's debugging that the URL request is http://localhost:8080/MyAppContext/jsp/doactiontwo which, for obvious reason, would return a 404 status (and get no hit to this servlet's doPost() (or doGet()) methods either).
<form action="doactiontwo" method="post">
...
<input type="submit" />...
</form>
If I try to modify the second servlet's URL pattern to /jsp/doactiontwo, I can hit the servlet, but when doactiontwo actually dispatches/forwards the request after processing to the first servlet (doactionone) with:
RequestDispatcher rd = request.getRequestDispatcher("doactionone.jsp");
rd.forward(request, response);
when it gets loaded, when hover over the URL on the first page that initially was pointing to the second JSP page (<a href="jsp/doactiontwo.jsp">), now actually points to:
jsp/jsp/doactiontwo.jsp
The funny part is that the source code of doactionone.jsp still shows it as jsp/doactiontwo.jsp, but hovering over it shows http://localhost:8080/MyAppContext/jsp/jsp/doactiontwo, and when clicked, it obviously results in 404 status.
Can somebody explain why, first of all, the submission on the second JSP page requires the servlet to have a pattern of /jsp/doactiontwo to work rather than /doactiontwo? And is there a way around to avoid appending /jsp to the URL pattern?
And second, why when the second servlet processes the request and dispatches/forwards it to the first page, the URL now contains two jsp/'s?
You need to change your design to allow the controllers, a.k.a. Servlets, to drive your application. In this particular case, use the URL Pattern of second Servlet (doactiontwo) in place of you link:
#WebServlet(urlPatterns = { "doactiontwo" }
public class DoActionTwoServlet extends HttpServlet { /* ... */ }
<form action="doactionone" method="post">
...
<a href="doactiontwo"> <!-- This should match your second servlet's URL pattern -->
<input type="submit" />...
</form>
Now, since the default method when anchor link is invoked is GET, you need to overwrite DoActionTwoServlet's doGet() method, and forward those requests to an actual doactiontwo.jsp:
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
RequestDispatcher rd = request.getRequestDispatcher("jsp/doactiontwo.jsp");
rd.forward(request, response);
}
I want to include header and footer template in my servlet, like this in PHP in a PHP controller :
public doSomething()
{
include "header.html";
//generate doSomething content in HTML and echo it
include "footer.html";
}
PS : It's an example, i don't do directly like this in PHP ;)
In this way, I want to avoid like this in all JSP files (the includes) :
<jsp:include page="header.html" />
<%-- Display doSomething informations -->
<jsp:include page="footer.html" />
So exactly, I want :
public void doGet( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException {
//Include the header.html
this.getServletContext().getRequestDispatcher( "/WEB-INF/Example.jsp" ).forward( request, response );
//Include the footer.html
}
Here, I want to include footer and header to do not do this into JSP.
So RP anwsert this question in the comments,, but to give this question an actual anwser i copied his into here:
"One option is read them into string and set them as request attributes and use those attributes in jsp or write those strings in to response and call request dispatcher's include method." - RP
I'm used to rails and the very handy yield functionality in erbs. I would like to be able to inject css/js script tags to the head when I'm running through many child jsp templates in the body tag. I know this is possible with Rails using yield, but I cant see a way of injecting a string higher than whats already outputted... here is my example
<head>
<!--- i want to inject script tags into here -->
</head>
<body>
<!-- running multiple child templates here -->
<!-- when the template needs a script tag, find a way of injecting it into the head -->
</body>
can I render into the head tag from further down the page, is this possible in jsp using string writers or some other way?
There are several ways to accomplish text juggling. As ERB, ruby on rails, also has a bit of Model-View-Controller separation, let's keep the same practice here:
A servlet (the controller) builds one or more data models and puts them in request attributes. Then it forwards to a JSP (the view).
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException {
List<Content> contents = new ArrayList<>();
...
request.setAttribute("contents", contents);
request.getRequestDispatcher("/contentsview.jsp")
.forward(request, response);
}
As I guess intended to do a loop on data emitting HTML and building a parallel list collected in a StringWriter, this already should solve the problem.
Now for doing (too much) work in the JSP: you can use the JspWriter also in methods, so order of evaluation is just as free.
<%!
private void printSomething() {
%><p>...</p><%
}
%>
I have a controller bound the URL: "/ruleManagement".
Inside my JSP, I have a form that forwards (on submit) to "ruleManagement/save" url. When there are errors with the input fields, I want it to return back the original form View. This is where the problem starts...
Problem 1) Now that the URL is "/ruleManagement/save", my form submit now points to "/ruleManagement/ruleManagement/save".
Problem 2) I tried using spring:url tag to generate the absolute paths for me, which usually works great. But when I put a spring:url tag inside of a tag, the spring:url tag does not get parsed correctly.
<form:form action="<spring:url value='/ruleManagement/save' ...>" method="post">
When I analyze the DOM after the page loads, my form tag looks something like:
<form action='<spring:url value="/ruleManagement/save" />' ... >
If I don't use the spring:url tag, and instead use just "/ruleManagement/save", the url generated excludes my application name in the url, which is also wrong.
How do I generate a consistent URL pattern across all Views regardless of path? If the answer is "using spring:url", how do I get that content inside a form:form tag?
Custom tags in JSP can't be used in attributes of other custom tags, so you need to store intermediate result in a request attribute (using var to redirect output of the tag to the request attribute is a common idiom supported by many tags):
<spring:url var = "action" value='/ruleManagement/save' ... />
<form:form action="${action}" method="post">
I too would love to be able to generate a consistent URL path across all Views! Is this possible with <spring:url .../>.
To answer your second question & tacking on to axtavt's answer, embed the <spring:url ... /> into the form action after adding the property htmlEscape="true"
Example: <form:form action="<spring:url value="/ruleManagement/save" htmlEscape="true" .../>" method="post">