How to get current jsp file path in war? - java

Due to lot of forward request, it is hard to identify the current showing jsp file. Is it possible to get the current jsp file path in war? How to achieve?
For an example:
URL: http://localhost:8080/controller/action
File Path: /view/dev/test.jsp
<%= getServletContext().getRealPath("/") %>
The above statement doesn't work, it show C:\Projects\test\build\web\ instead of C:\Projects\test\build\web\view\dev\test.jsp

This will be implementation dependent, but since many implementation use Jasper, it may well be more portable than you think. Of course, portability may not be an issue.
But the simple case is that you take the full qualified class name of "this" from within the JSP, and from that you can derive the path name. Each JSP is compiled in to a Servlet, and they each need their own unique class.
For example, in Glassfish, which uses Jasper from Tomcat/Apache:
I have a simple jsp, root.jsp:
<html>
<body>
<% out.println(this.getClass()); %>
</body>
</html>
It is in the root level of the WAR. When I run it, I get this:
class org.apache.jsp.root_jsp
When I created the directory d, and copied the root.jsp in to it, and executed it, I got:
class org.apache.jsp.d.root_jsp
So, you can see, that the class name for /root.jsp is org.apache.jsp.root_jsp. And for /d/root.jsp, it's org.apache.jsp.d.root_jsp.
If you remove org.apache.jsp from the class name, convert any remaining "." to "/", and the "_" to a "." you will get:
/root.jsp
/d/root.jsp
Which effectively gets you what you want.
If you overwrite a JSP at runtime, then it'll start sticking _1 and _2 to the end, so you'll have to account for that.
But play around with this, and it should work for you, and get you where you're going.
Just keep in mind, it's not portable, it clearly works in anything with Jasper (Tomcat, TomEE, Jetty, Glassfish), but I can't say about WebLogic or WebSphere.
But, it might. The container has to map the JSP file to a class somehow, and this is an intuitive way of doing it.
So, try it and see if you can get it to work with your container.

Related

Where is the "jsp" taglib TLD?

In a special case, I need to make the same as <jsp:useBean in Java class.
It sounds like using org.apache.commons.beanutils.BeanUtils.cloneBean(Object bean) will do the work.
But what is driving me crazy is that I can't find the TLD associated to <jsp: tags, nor the class used by <jsp:useBean.
Even <short-name>jsp</short-name> on Google gives me nothing.
The JSP specs I found makes me believe that it's not a tag like the others and that the code behind <jsp:useBean is in Java's core.
Am I right? Have I missed something?
There's no TLD for <jsp: elements in the JSP page. These elements are part of the JSP language. With this language you can create JSP pages but if you need to use custom TLDs like JSTL then you should use taglib directive.
What is interesting in JSP: it's called now Jakarta Server Pages. You can read more about this in the article What is JSP? Introduction to Jakarta Server Pages.
One of the original Java web technologies, JSP is still widely used with servlets and JSTL. Here's how to use Jakarta Server Pages to build dynamic web pages that connect to the Java back end.
<jsp:useBean> is an action tag and not part of a tag library, cf. https://en.wikipedia.org/wiki/Jakarta_Server_Pages#Syntax, scroll down to "Additional Tags".
The code probably was part of J2EE back in the day or is in the servlet containers. Today it apparently is an eclipse project: https://projects.eclipse.org/projects/ee4j.jsp.
<jsp:useBean> is actually "a JSP server markup tag" "the server knows in a JSP specification server", the "tags" you are thinking of are standard tag library c: f: are resources that use a TLD Tag Library Descriptor (stored in a jar package to be loaded as a resource) and are from the original "custom tag" API system.
Custom tags do not need to be in a .jar, unjared they must be put in /webapplication/WEB-INF/tags/ often associated with non programmatic tags that operate like an include markup file. jar packaged tags are in a folder structure /webapplication*/META-INF/tags/* any tags wherever they reside require to be named to their full path in an XML markup like .tld file in the top directory of the package.
If your needs are simple for the bean, then you can just add code directly to your JSP. To see what I mean, look at the Servlet that was generated from your JSP. Every JSP is translated to a Servlet. For example, consider the following JSP.
<jsp:useBean id="myList" class="java.util.ArrayList"/>
${myList.add("My first element")}
<%myList.add("My second element");%>
${myList}
The translation(in Tomcat's work folder) is
java.util.ArrayList myList = null;
myList = (java.util.ArrayList) _jspx_page_context.getAttribute("myList", jakarta.servlet.jsp.PageContext.PAGE_SCOPE);
if (myList == null){
myList = new java.util.ArrayList();
_jspx_page_context.setAttribute("myList", myList, jakarta.servlet.jsp.PageContext.PAGE_SCOPE);
}
out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${myList.add(\"My first element\")}", java.lang.String.class, (jakarta.servlet.jsp.PageContext)_jspx_page_context, null));
myList.add("My second element");
out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${myList}", java.lang.String.class, (jakarta.servlet.jsp.PageContext)_jspx_page_context, null));
The useBean action tag just creates a scripting variable and sets a scoped variable. You can do that without any special tag. The following JSP does the same thing.
<%# page import="java.util.ArrayList"%>
<%
ArrayList myList2 = new ArrayList();
myList2.add("one");
pageContext.setAttribute("myList2", myList2);
%>
${myList2}
<%=myList2%>

Is it possible to call methods in one JSP from another while using dynamic include?

I need to call in a JSP a method that is defined in another JSP that should be included dynamically (include page ) not statically (include file), but I get a jsp compilation error "method is undefined". It works fine when I use <%#include file=""%>.
The reason I need this is that our JSP ends up getting too big and we get this error: "The code of method _jspService(HttpServletRequest, HttpServletResponse) is exceeding the 65535 bytes limit" (whence the need to include other jsps dynamically), therefore we're splitting some of its funcionality into smaller JSPs.
Foo.jsp
<%#page language="java"%>
<%!
public String getSomeID(String param) throws Exception {
return "someId";
}
%>
Bar.jsp
<jsp:include page="Foo.jsp"></jsp:include>
String id = getSomeID(param);
I'm aware that the better option here is to use a preprocessing servlet. We'll probably do that. But, for now, I merely wish to know if it is possible to call methods from another jsp while including it dynamically.
You can't reference the code from your Foo.jsp in Bar.jsp
if you are doing that with jsp:include.
Both pages in that cases are compiled into independent servlets behind the scene. Let's call them Foo_Servlet and Bar_Servlet.
What actually happens in that case is the following: Bar_Servlet while handling the request passes control and original request to Foo_Servlet.
Once Foo_Servlet completes the response of execution of Foo_Servlet (and not original jsp code) is combined with a response of Bar_Servlet.

Passing JSP data to Java class and vice versa on button click

I am fairly new in JSP and I am trying to figure out how to pass data entered in the form on a JSP page to the java class and send this data back to the JSP page on click.
My index.jsp looks a bit like this:
<%# page import="mypackage.*" %>
<% myClass c = new myClass();
c.setString("String"); %>
<p>This is a test: <%= c.getString(); %></p>
The above code will output "String". I can access my class with no problems if I set the value on page load. I tried using servlets after some research. I modified my form to add the servlet "testServlet" on form action:
<form method="POST" action="testServlet">
Then on the doPost() method in testServlet I added in this:
String myString = request.getParameter("myString"); //myString is also the name of my textbox
System.out.println("Entered string: " + myString);
However, I am clearly missing a crucial part of the flow of how this should work and I am most probably wrong with this one as well as all the form does after I press submit is redirect to testServlet so I get the error that the resource is not available since it isn't a JSP/html page.
So my questions are, how exactly can I pass data from JSP to java and vice versa? Also, is there a possible way to do this without servlets? And what are good tutorials/examples for studying JSP and its behavior such as passing data? Please help.
After some more research, I am now able to transfer data set on index to detail using jsp:useBean however, as I've read in all the forums I've visited, servlets should be used to handle this but this really confused me more as a beginner so I really want to figure out what I'm missing here.
I've made sure that the servlet is registered on web.xml and I didn't change anything in there.
Update: I've tried re-creating the project from scratch and somehow managed to make the servlet work. As it turns out, I was missing something on the doGet() method. But now my question stands, is there a way to process the form without using servlets or page import in the JSP file? I was shown a sample code that didn't use servlets or page imports. I did take notice at tag.
use the java beans with getters and setters for there class member variables.

What does this expression language ${pageContext.request.contextPath} exactly do in JSP EL?

I have a web app, where I have different navigation anchor tags such as Home, Profile and etc.
What I want:
When I press anchor tags like home or profile. I just want to ensure that current user gets its information in that Tags/JSP Page.
Sample Example that I am trying:
Profile
The pageContext is an implicit object available in JSPs. The EL documentation says
The context for the JSP page. Provides access to various objects including:
servletContext: ...
session: ...
request: ...
response: ...
Thus this expression will get the current HttpServletRequest object and get the context path for the current request and append /JSPAddress.jsp to it to create a link (that will work even if the context-path this resource is accessed at changes).
The primary purpose of this expression would be to keep your links 'relative' to the application context and insulate them from changes to the application path.
For example, if your JSP (named thisJSP.jsp) is accessed at http://myhost.com/myWebApp/thisJSP.jsp, thecontext path will be myWebApp. Thus, the link href generated will be /myWebApp/JSPAddress.jsp.
If someday, you decide to deploy the JSP on another server with the context-path of corpWebApp, the href generated for the link will automatically change to /corpWebApp/JSPAddress.jsp without any work on your part.
Include <%# page isELIgnored="false"%> on top of your jsp page.
use request.getContextPath() instead of ${pageContext.request.contextPath} in JSP expression language.
<%
String contextPath = request.getContextPath();
%>
out.println(contextPath);
output: willPrintMyProjectcontextPath
For my project's setup, "${pageContext.request.contextPath}"= refers to "src/main/webapp". Another way to tell is by right clicking on your project in Eclipse and then going to Properties:

How do I pass a parameter to a JSP via a cross-context JSTL import?

I've come across a few other questions that describe a similar, but not identical situation, to mine. This question, for instance, shows pretty much the same problem, except that I'm not using portlets - I'm just using boring ol' JSP+JSTL+EL+etc.
I have two application contexts, and I'd like to import a JSP from one to the other. I know how do that:
<c:import context="/" url="/WEB-INF/jsp/foo.jsp"/>
However, I also want to pass a parameter to the imported foo.jsp. But this code:
<c:import context="/" url="/WEB-INF/jsp/foo.jsp">
<c:param name="someAttr" value="someValue"/>
</c:import>
does not seem to properly send the parameter to foo.jsp; if foo.jsp is something like*
<% System.out.println("foo.jsp sees that someAttr is: "
+ pageContext.findAttribute("someAttr")); %>
then this gets printed out:
foo.jsp sees that someAttr is: null
whereas I want to see this:
foo.jsp sees that someAttr is: someValue
so, obviously, someAttr can't be found in foo.jsp.
How do I fix this?
*(yes, I know, scriplets==bad, this is just for debugging this one problem)
You're setting it as a request parameter, so you should also be getting it as request parameter.
Since you seem to dislike scriptlets as well, here's an EL solution:
${param.someAttr}
Note that <c:import> doesn't add any extra advantages above <jsp:include> in this particular case. It's useful whenever you want to import files from a different context or an entirely different domain, but this doesn't seem to be the case now. The following should also just have worked:
<jsp:include page="/WEB-INF/jsp/foo.jsp">
<jsp:param name="someAttr" value="someValue" />
</jsp:include>
This way the included page has access to the same PageContext and HttpServletRequest as the main JSP. This may end up to be more useful.

Categories

Resources