I want to delay the output of a custom tag.
The reason being: I want to add a tag to the head of the document that will compile a list of styles and scripts to include in the page. The subsequent tags in the page would add to the list of elements and the list would be printed once the body of the page has been generated.
Is this possible or is there a better way to do it. (I don't want to have to know what links are going to be added during the page compilation.)
Thanks
With JSPContext pushBody() and popBody() you can get some control over the order of output.
<%
Writer body = new StringWriter();
out = pageContext.pushBody(body);
// following code will write to 'body' and not to client
%>
...
<%
out = pageContext.popBody();
// normal output again
%>
...
<% // write the captured output %>
<%= body %>
Even though it works it might be better to work around as it is very confusing.
I have asked this question on a variety of sites and didn't get the answer I was looking for (although some were creative, Thanks!) so I ended up doing quite a bit of research on my own for the "best" way to do this. This is what I came up with:
I created three custom tags so my html would look like the following:
<html:page>
<html:head>
...
</html:head>
<html:body>
...
</html:body>
</html:page>
The page tag creates a variable in the REQUEST_SCOPE called "headercontents" in the doStartTag() method that can compile a list of output that I want to place in the head of the document.
The head element simply adds all of its body contents to this variable.
The body element does nothing as of now, just has a tag file with a simple .
Any element in the body can now use the "headercontents" variable to post information to the head of the html page. (Thus linking any stylesheets or scripts that it needs in the head rather than in the body).
Then finally in the page tag's doEndTag() method it prints the contents of the "headercontents" variable then prints the contents of itself (the contents of the html:body tag).
The result is that the document can load and rearrange itself as needed. This is still a rudimentary version but I'll perfect it and post the source code sometime in the future.
Related
I have a form in JSP. I have to populate it based on the request object (from the servlet). How do I use Java Script for accessing request object attributes or if you can suggest me any other better way to populate form dynamically?
You need to realize that Java/JSP is merely a HTML/CSS/JS code producer. So all you need to do is to just let JSP print the Java variable as if it is a JavaScript variable and that the generated HTML/JS code output is syntactically valid.
Provided that the Java variable is available in the EL scope by ${foo}, here are several examples how to print it:
<script>var foo = '${foo}';</script>
<script>someFunction('${foo}');</script>
<div onclick="someFunction('${foo}')">...</div>
Imagine that the Java variable has the value "bar", then JSP will ultimately generate this HTML which you can verify by rightclick, View Source in the webbrowser:
<script>var foo = 'bar';</script>
<script>someFunction('bar');</script>
<div onclick="someFunction('bar')">...</div>
Do note that those singlequotes are thus mandatory in order to represent a string typed variable in JS. If you have used var foo = ${foo}; instead, then it would print var foo = bar;, which may end up in "bar is undefined" errors in when you attempt to access it further down in JS code (you can see JS errors in JS console of browser's web developer toolset which you can open by pressing F12 in Chrome/FireFox23+/IE9+). Also note that if the variable represents a number or a boolean, which doesn't need to be quoted, then it will just work fine.
If the variable happens to originate from user-controlled input, then keep in mind to take into account XSS attack holes and JS escaping. Near the bottom of our EL wiki page you can find an example how to create a custom EL function which escapes a Java variable for safe usage in JS.
If the variable is a bit more complex, e.g. a Java bean, or a list thereof, or a map, then you can use one of the many available JSON libraries to convert the Java object to a JSON string. Here's an example assuming Gson.
String someObjectAsJson = new Gson().toJson(someObject);
Note that this way you don't need to print it as a quoted string anymore.
<script>var foo = ${someObjectAsJson};</script>
See also:
Our JSP wiki page - see the chapter "JavaScript".
How to escape JavaScript in JSP?
Call Servlet and invoke Java code from JavaScript along with parameters
How to use Servlets and Ajax?
If you're pre-populating the form fields based on parameters in the HTTP request, then why not simply do this on the server side in your JSP... rather than on the client side with JavaScript? In the JSP it would look vaguely like this:
<input type="text" name="myFormField1" value="<%= request.getParameter("value1"); %>"/>
On the client side, JavaScript doesn't really have the concept of a "request object". You pretty much have to parse the query string yourself manually to get at the CGI parameters. I suspect that isn't what you're actually wanting to do.
Passing JSON from JSP to Javascript.
I came here looking for this, #BalusC's answer helped to an extent but didn't solve the problem to the core. After digging deep into <script> tag, I came across this solution.
<script id="jsonData" type="application/json">${jsonFromJava}</script>
and in the JS:
var fetchedJson = JSON.parse(document.getElementById('jsonData').textContent);
In JSP file:
<head>
...
<%# page import="com.common.Constants" %>
...
</head>
<script type="text/javascript">
var constant = "<%=Constants.CONSTANT%>"
</script>
This constant variable will be then available to .js files that are declared after the above code.
Constants.java is a java file containing a static constant named CONSTANT.
The scenario that I had was, I needed one constant from a property file, so instead of constructing a property file for javascript, I did this.
In JSP page :
<c:set var="list_size" value="${list1.size() }"></c:set>
Access this value in Javascipt page using :
var list_size = parseInt($('#list_size').val());
I added javascript page in my project externally.
I hope you get my problem.
out.println("<li class='has-sub'><a href='#'>" + k1.getKName() + "</a>\n");
I have a JSP and inside this java code. The result is a navigation on the left side with several categories and subcategories. So this is one category element. As you can see, I didn't put anything in the href. What I want to do is, that when I click on this category, I will get the articles of this category in the content space on the right side.
So, what do I have to do with servlets or JSPs in order to give a result to the content space. I can't just call a servlet there of course, because that means that I get the result of the servlet inside the href obviously.
I am sorry if this is a silly question, but I really don't know how to solve this :(
Further to previous comments you do not need web services. You can do this using ajax and a normal Servlet. You might want to look at using JQuery to help with the Ajax part. Here's some JQuery documentation around the load() function which will:
Load data from the server and place the returned HTML into the matched
element.
https://api.jquery.com/load/
Your link will look something like (if k1 is a bean in some scope then you can use EL rather than scriptlets):
<a href='javascript:loadData(${k1.id});'>${k1.name}</a>
Your Javascript will look something like:
function loadData(id){
var url = "/pathToMyServlet?id=" + id;
$( "#result" ).load( url );
}
which will call your Servlet and insert the HTML returned to an element on your page with the ID 'result'.
Your Servlet then needs to generate the data and forward to a simple JSP which returns the results (and only the results) i.e. it does not need to be a fully formed HTML page but should only contain the table of results or whatever.
And stop using scriptlets:
How to avoid Java code in JSP files?
I have to write an HTML report from a java class which contains the source code of web pages. So the problem is that as soon as the source of a web page is encountered it is thought of by the browser as being the the end of html tags on the main report page and so the output is not renderd correctly. An example is shown below :
<html>
<body>
<li>
<pre>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
The page was not found on this server.
</body>
</html>
</pre>
</li>
</body>
</html>
I want that everything inside the pre tags must be taken as normal text and not html markup. I tried replacing < with < , > with > , & with & etc.. but it doesnt seem to work. Any tips on how to make this possible?
EDIT :
This is what i tried (a is the part inside pre tags)
File aFile = new File(filename);
try {
BufferedWriter out = new BufferedWriter(new FileWriter(aFile,aFile.exists()));
a.replaceAll("<","<");a.replaceAll(">",">");a.replaceAll("\"","&;quot;");a.replaceAll("&","&");
out.write(a + "\r\n");
out.close();
}
EDIT 2:
So this correct solution involved a=a.replaceAll(...), but another thing to note is that if i replace < with > and later on i replace & with & (like i do in the above example), It will againn mess my output(< will become <). So the order must also be changed(replcae & first and then <).
In Java, String objects are immutable. That means a.replaceAll doesn’t change a but returns a new String object in which the replacement took place.
So to fix this, you need to work with the returned object instead:
a = a.replaceAll("&","&").replaceAll("<","<");
And you actually only need to replace the & and < for your specific application.
do:
a = a.replaceAll("<","<");
instead of :
a.replaceAll("<","<");
and same for others...
As replaceAll method doesn't change the string, it rather returns a new one
Well.. replaceAll may work.. However, I'll always prefer to use StingEscapeUtils as ..
a = StringEscapeUtils.escapeHtml4(a)
The sequence you post in the comment:
a.replaceAll("<","<");
a.replaceAll(">",">");
a.replaceAll("\"","&;quot;");
a.replaceAll("&","&");
won't work, since the replaceAll() method doesn't change the String it is called on. It can't, Strings are immutable in Java.
Also, as #Rishabh points out, your last replace call will mess up the previous replaces, so you need to change the order.
You need to do
a = a.replaceAll("&","&");
a = ...
Or, just do them all without saving the intermediate result:
a = a.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll("\"","&;quot;");
Also, you should probably use the replace() method instead of replaceAll(), there is no need to use regexes in this case.
Replace this line:
a.replaceAll("<","<");a.replaceAll(">",">");a.replaceAll("\"","&;quot;");a.replaceAll("&","&");
As this:
a = a.replaceAll("<","<").replaceAll(">",">").replaceAll("\"","&;quot;").replaceAll("&","&");
I have a custom tag that has no body at all. I'm trying to programmatically replace the empty body with, for simplicity's sake,
[<c:out value="SUCCESS!"/>]
The goal is to see "[SUCCESS!]" displayed by the JSP which uses the tag, but all I see is "[]" and if I look at the generated source code, I can see that the c:out statement is written on the page between the brackets, but not interpreted.
Is there a common way to achieve this ? The final goal will be to use other custom tags instead of the "c:out" tag. The tags/content will come from a database.
I tried different techniques with SimpleTagSupport and BodyTagSupport but none of those were successfull. In fact I'm not sure if it is technically possible to do it, since, the tag has already been interpreted at that time.. But then how should this be done ?
Server tags (like your custom tag or JSTL tags) get transformed to Java code when the JSP is translated into a servlet. For example, the following JSP code:
<c:out value="FooBar" />
gets translated to something like this inside the servlet:
....
OutTag outTag = (OutTag) tagHandlerPool.get(OutTag.class);
outTag.setPageContext(pageContext);
outTag.setParent(null);
outTag.setValue(new String("FooBar"));
int evalOut = outTag.doStartTag();
....
In your custom tags you can call other Java classes/methods and can write HTML code (not JSP code) to the response.
The [<c:out value="SUCCESS!"/>] is not interpreted because at this level it's just a string that gets written directly to the response.
So according to my JSP reference book, as well as every other reference I can find on the web, I'm supposed to be able to do something like:
<%# tag dynamic-attributes="dynamicAttributesVar" %>
and then when someone uses an attribute that I didn't define in an attribute directive, I should be able to access that attribute from the "dynamicAttributesVar" map:
<%= dynamicAttributesVar.get("someUnexpectedAttribute") %>
However, that doesn't work, at all; I just get a "dynamicAttributesVar cannot be resolved" error when I try.
Now, I did discover (by looking at the generated Java class for the tag) that I can "hack" a working dynamic attributes variable by doing:
<% Map dynamicAttributesVar = _jspx_dynamic_attrs; %>
Now, that hack doesn't work unless I also use the dynamic-attributes parameter on my tag directive, so it seems that the parameter is doing something.
But what I want to know is, how can I make it do what it does for every other JSP user out there?
Just trying to get a badge for answering a four year old question.
I have this problem as well and came across some help at O'Reilly to use JSTL instead of scriptlets.
The original poster could have used this code to get all keys/values:
<c:forEach items="${dynamicAttributesVar}" var="a">
${a.key}="${a.value}"
</c:forEach>
This would get a specific value:
<c:out value="${dynamicAttributesVar['someUnexpectedAttribute']}"/>
Isn't "dynamicAttributesVar" the name of the key in the page context that the dynamic attributes are put into? So you could do
<c:out value="${dynamicAttributesVar.someUnexpectedAttributes}"/>
or if you must use scriptlets:
Map dynamicAttributes = (Map) pageContext.getAttribute("dynamicAttributesVar")
(Disclaimer: I haven't tried it, I've just used dynamic attributes in tags with direct Java implementations... but it seems reasonable)