I'm working on a legacy Tomcat server that is no longer supported by the software developer that provided it. web.xml doesn't tell me what version of JSP I'm working with, but all the .class files are Java 1.5.
I have a customer who is upset, because the system has html boxes that are auto-populated by Java, and it fills it straight the the (unordered) results of an XML database query. I'm trying to sneak a bit of code into the JSP for the Selector to sort the list of fields before they are populated, but it doesn't work and I don't understand why.
The (abridged) relevant code:
<%# page import="src.explorer.ObjectStateFactory"%>
<%# page language="java" %>
<%# taglib uri="/WEB-INF/c.tld" prefix="c" %>
<jsp:useBean id="ExplorerViewContext" scope="session" type="src.explorer.ExplorerViewContext"/>
...
<c:forEach var="nc" items="${ExplorerViewContext.networkControllers}">
<c:choose>
<c:when test="${nc.name == ExplorerViewContext.networkControllerSelection.name}">
<option value="<c:out value="${selectAction}${nc.objectKey}"/>" selected><c:out value="${nc.name}"/></option>
</c:when>
<c:otherwise>
<option value="<c:out value="${selectAction}${nc.objectKey}"/>"><c:out value="${nc.name}"/></option>
</c:otherwise>
</c:choose>
</c:forEach>
</select>
The relevant code with my additions:
<%# page import="src.explorer.ObjectStateFactory"%>
<%# page import="java.util.*"%>
<%# page language="java" %>
<%# taglib uri="/WEB-INF/c.tld" prefix="c" %>
<jsp:useBean id="ExplorerViewContext" scope="session" type="src.explorer.ExplorerViewContext"/>
...
<%
final Comparator<src.explorer.XmldbObjectState> NC_ORDER = new Comparator<src.explorer.XmldbObjectState>(){
public int compare(src.explorer.XmldbObjectState nc1, src.explorer.XmldbObjectState nc2){
return nc1.getName().compareTo(nc2.getName());
}
};
List myList = ExplorerViewContext.getNetworkControllers();
java.util.Collections.sort(myList,NC_ORDER);
%>
<c:forEach var="nc" items="${myList}">
<c:choose>
<c:when test="${nc.name == ExplorerViewContext.networkControllerSelection.name}">
<option value="<c:out value="${selectAction}${nc.objectKey}"/>" selected><c:out value="${nc.name}"/></option>
</c:when>
<c:otherwise>
<option value="<c:out value="${selectAction}${nc.objectKey}"/>"><c:out value="${nc.name}"/></option>
</c:otherwise>
</c:choose>
</c:forEach>
</select>
Basically, I'm trying to grab the list and sort it before it gets sent to the HTML. The problem is, myList always comes up empty, and I don't understand why. I'm guessing that ExplorerViewContext.networkControllers in the original code is calling the getNetwrokControllers() method on an instance of ExplorerViewContext, yes? Why can't I do the same thing in a scriptlet and reformat the output a little before serving it?
You should not add scriptlet code to code that is already using JSTL only. The better thing to do would be to edit the bean class src.explorer.ExplorerViewContext to sort the insides for you automatically.
In any case, the reason ${myList} does nothing in the JSTL is that variables created in scriptlets (i.e. between <% and %>) do not exist for JSTL. To get a variable to exist in JSTL you have to create it in JSTL, or set it in the page context, or it has to be in the session or the request. Generally you put it in the session or request in a servlet.
In this case, your list is in the bean, so it would be better to just edit the bean class to sort the list. But you could set the variable into the page context here so that JSTL can use it:
<%
...
List myList = ExplorerViewContext.getNetworkControllers();
java.util.Collections.sort(myList,NC_ORDER);
pageContext.setAttribute("myList", myList); //set in pageContext so JSTL can see it
%>
<c:forEach var="nc" items="${myList}">
As far as the code being "legacy" adding scriptlets to it would make it even more legacy. The fact is, this code is more modern than the modifications you were trying to add. But only slightly so, since using <jsp:useBean> is an obsolete way of using beans.
Related
In have this transfer from a servlet to the jsp. Since the AllPost is a list and I go through it with for, I do not know whether it's a short way close to what I give here.
Meanwhile I solved the issue inside the class, i.e. before the value coming to the servlet & jsp, as below.
So, at this point I do not know whether it makes sense to try further.
Thank you in advance!
<c:forEach items="${AllPost}" var ="p">
<tr>
<%! int len = Integer.valueOf(${p.detail.length()}); %>
<%
if(len<25){
${p.detail}.concat("....");
}
%>
<td>${p.detail.substring(0,25)}...</td>
The 2nd option code from routine class:
ResultSet rs = DB.getPreparedStatement(SQL).executeQuery();
while(rs.next()){
News n = new News(rs.getInt(1),...);
if(Integer.valueOf(rs.getString(1.length())<25){
String sz = n.getDetail().concat(".........................");
n.setDetail(sz);
}
<%! int len = Integer.valueOf(${p.detail.length()}); %>
Here you're mixing EL and scriptlets, it's not possible to use both. Not only that, you're using JSTL in your code as well, but still resorting to scriptlets? In almost all cases, if you're using JSTL & EL, you don't need to use any scriptlets. Scriptlets is an oldschool way of using JSPs.
Your code for the first option should look something like this (without scriptlets):
<c:forEach items="${AllPost}" var ="p">
<tr>
<c:if test="${fn:length(p.detail) lt 25}">
<td>${p.detail}...</td>
</c:if>
<c:if test="${fn:length(p.detail) gt 25}">
<td>${fn:substring(p.detail, 0, 25)}...</td>
</c:if>
</tr>
</c:forEach>
make sure to include this at the top of the page for jstl functions (if you haven't already)
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
I'm creating a JSP .tag file that will handle this use case:
<my:safeParam paramName="param1" defaultValue="testvalue"/>
Where the behavior will be to take a request parameter, escape its value for "safe" usage, and place that escaped value back on some scope (e.g. request) under the same name as the parameter (although it could be another name).
I have an implementation that works, but I've got scriptlet in there because I couldn't find a way to use variable variable names in just JSTL. But I'm no JSTL wizard, so I thought I'd see if there's a syntax/approach I'm missing. Here's the working safeParam.tag file:
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%# attribute name="paramName" required="true" %>
<%# attribute name="defaultValue" %>
<%
String name = (String) pageContext.getAttribute("paramName");
%>
<c:if test="${not empty defaultValue}">
<%
request.setAttribute(name, pageContext.getAttribute("defaultValue"));
%>
</c:if>
<c:if test="${not empty param[paramName]}">
<c:set var="escaped" value="${fn:escapeXml(param[paramName])}"/>
<%
request.setAttribute(name, pageContext.getAttribute("escaped"));
%>
</c:if>
(I sure wish EL was escaped automatically.)
<c:if test="${empty paramName}">
${defaultValue}
</c:if>
<c:if test="${not empty paramName}">
<c:out value="${paramName}" escapeXml="true"/>
</c:if>
I probably won't use this approach because it reduces the conciseness I was seeking with this custom tag, but just to document it as an option... (I'm not sure if this is what Frank Yeung is getting at.)
I could make the tag simply output the default-or-escaped parameter value, then make the user of the tag wrap that in a <c:set>.
Tag:
<c:choose>
<c:when test="${empty param[paramName]}">
${defaultValue}
</c:when>
<c:otherwise>
<c:out value="${param[paramName]}"/>
</c:otherwise>
</c:choose>
JSP:
<c:set var="myVariable">
<my:safeParam paramName="folder" defaultValue="homeFolder"/>
</c:set>
But really my goal has been to do everything inside the tag.
I am implementing paging support using custom tag. I decided to use JSP-based tag because there is more formatting than any heavy logic. But this is not the main story. The trouble is that JSTL forEach simply doesn't work at my .tag file and throws java.lang.NoSuchFieldError: deferredExpression .Even this code is throwing exception when I'm using my tag at JSP:
<%#tag description="paging support for employee" pageEncoding="UTF-8"%>
<%#taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<div>
<div>
<c:forEach var="i" begin="1" end="20" step="1" varStatus ="status">
<c:out value="${i}" />
</c:forEach>
</div>
</div>
Also in my previous project i met this exception while was mixing together struts tags and forEach tag in a single JSP. I couldn't find out what was it, but handled it through replacing forEach by similar struts tag iterate. But this time I need exactly forEach because of it's attribute "step". Any ideas ?
I am trying (and learning) to build a java web framework, and in the process of developing its' code generator based on the content of the database. In the view making process, I stumble in a difficulty, which I don't know how to solve it.
Firstly, I want all the pages to be created using the following index.jsp :
<body>
<%# include file="header.jsp" %>
<hr/>
<%# include file="body.jsp" %>
<hr/>
<%# include file="footer.jsp" %>
</body>
And, in the body.jsp, I want it to be like this :
<jsp:include page="${application_modul}" %>
Where application_modul is an attribute defined in its' controller this way :
request.setAttribute("application_modul","user_account\\view_user_account.jsp");
It can find the file correctly, but the processed jsp is not what I expected. Here :
<c:forEach items="[application.models.UserAccountModel#18a49e0, application.models.UserAccountModel#1f82982]" var="item" varStatus="status" >
<tr>
....
You can see the items attribute of jstl forEach, got its variable name (toString())...
Any Idea what the problem is????
I hope I describe my problem correctly
Many thanks!
PS :
I already create a quick fix for this, but not what I want it though. In the generated view_user_account.jsp, I do it like this :
<body>
<%# include file="header.jsp" %>
<hr/>
<c:forEach items="${row}" var="item" varStatus="status" >
<tr>
....
<hr/>
<%# include file="footer.jsp" %>
</body>
You can see that I create the whole file here...
EDITED:
PS : ${row} is an ArrayList populated with data from certain table
So, to summarize your problem in a single sentence, JSTL tags are not been parsed and they end up plain in generated HTML output?
You need to declare JSTL taglib in top of the JSP page where you're using JSTL tags to get them to run. For the JSTL core taglib, that'll be
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
I am not sure but, Try this...
index.jsp
<jsp:param name="parameterName" value="{parameterValue | <%= expression %>}" />
I have a 2d array stored in a java bean and I'm trying to iterate through its contents to print a corresponding table on a JSP page. The array is a bean data member which I'm accessing through the EL code ${board.cells}. I tried to do this with a c:forEach tag, but it's only printing a single cell. I know the array contents are valid, as I can see them when I index them directly by ${board.cells[0][0]}
Here's my loop code, embedded in the JSP.
<c:forEach items="${board.cells}" var="row">
<tr>
<c:forEach items="${row}" var="cell">
<td><img src=${cell} align="" alt="cell"></td>
</c:forEach>
</tr>
</c:forEach>
Any help is much appreciated!
As per the comments, JSTL core tags are simply not been interpreted/parsed. They are been sent plain to the HTML response. You need to declare the JSTL core taglib in top of your JSP to get them to run.
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
See also:
Our JSTL wiki page