I can not render a nested parent child tree structure in jsp page. Due to stackover flow error which is caused by
<code><jsp:include page=""/></code>
My DB:
Id || Name || Parentid ||
1 || animal|| 0 ||
2 || Dog || 1 || etc.
Model class:
public class Node {
private int id;
private String name;
private int parentId;
private List<Node> children;
public Node() {
}
public Node(String name, int parentId, List<Node> children) {
this.name = name;
this.parentId = parentId;
this.children = children;
}
DAO Class:
#Override
public List<Node> nodelist() {
String sql = "select * from tree";
List<Node> listNode = jdbcTemplate.query(sql, new RowMapper<Node>() {
#Override
public Node mapRow(ResultSet rs, int rowNum) throws SQLException {
Node node = new Node();
node.setId(rs.getInt("id"));
node.setName(rs.getString("name"));
node.setParentId(rs.getInt("parent_id"));
return node;
}
});
return listNode;
}
In the controller i bind the object as below:
List<Node> rootNodes;
#Autowired
TreeDao treeDao;
#RequestMapping(value = "/node", method = RequestMethod.GET)
public ModelAndView getallnodes(ModelAndView model) throws IOException {
//menuObj = menuDao.listCategory();
List<Node> listnode = treeDao.nodelist();
getInfiniteTree(listnode);
model.addObject("rootNodes",rootNodes);
model.setViewName("tree");
return model;
}
public List<Node> getInfiniteTree(List<Node> nodes) {
return findRootNodes(nodes);
}
private List<Node> findRootNodes(List<Node> nodes) {
rootNodes = new ArrayList<Node>();
for (Node node : nodes) {
if (node.getParentId() == 0) {
rootNodes.add(node);
findChildNodes(node, nodes);
}
}
System.out.println("rootnodes "+rootNodes);
Gson gson = new Gson();
System.out.println(gson.toJson(rootNodes));
//I got the correct json format data here.
//Collections.sort(rootNodes);
return rootNodes;
}
private void findChildNodes(Node parentNode, List<Node> nodes) {
List<Node> children = new ArrayList<Node>();
parentNode.setChildren(children);
for (Node node : nodes) {
if (node.getParentId() == parentNode.getId()) {
children.add(node);
findChildNodes(node, nodes);
}
}
//Collections.sort(children);
}
In another java swing project i test the similar code and got follwing String result:
nodes [Node{id=1, name=供应链部, parentId=0, sort=3, children=[Node{id=5, name=物流部, parentId=1, sort=1, children=[]}, Node{id=6, name=采购部, parentId=1, sort=2, children=[]}]}, Node{id=2, name=技术部, parentId=0, sort=1, children=[Node{id=7, name=开发部, parentId=2, sort=2, children=[Node{id=12, name=后端部, parentId=7, sort=2, children=[]}, Node{id=13, name=前端部, parentId=7, sort=2, children=[Node{id=14, name=diee, parentId=13, sort=2, children=[]}, Node{id=15, name=diee, parentId=13, sort=2, children=[]}]}]}, Node{id=8, name=测试部, parentId=2, sort=1, children=[]}, Node{id=9, name=运维部, parentId=2, sort=3, children=[]}]}, Node{id=3, name=行政部, parentId=0, sort=2, children=[Node{id=10, name=招聘部, parentId=3, sort=1, children=[]}, Node{id=11, name=人事部, parentId=3, sort=2, children=[]}]}, Node{id=4, name=公关部, parentId=0, sort=4, children=[]}]
The problem is i can not display it using jsp recursion, i tried below code:
tree.jsp :
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<c:set var="menuitem" value="${rootNodes}" scope="request" />
<jsp:include page="menuitem.jsp" />
</body>
</html>
menuitem.jsp :
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<ul>
<c:forEach var ="menuitems" items="${menuitem}">
<li>${menuitems.name}</li>
<ul>
<c:if test="${fn:length(menuitems.children) gt 0}">
<li class="droprightMenu">
<c:out value="Has children"></c:out>
<c:forEach var="menuitemc" items="${menuitems.children}">
<c:set var="menuitem" value="${menuitemc}" scope="request" />
<%--<jsp:include page="menuitem.jsp" />--%>
</c:forEach>
</li>
</c:if>
</ul>
</c:forEach>
</ul>
It is not including page through infinite children and as I am a new in JSP recursion please ignore my faults. I stuck here for couple of days.
Exception:
Don't know how to iterate over supplied "items" in <forEach>
org.apache.jasper.JasperException: An exception occurred processing JSP page /WEB-INF/views/menuitem.jsp at line 14
11:
12:
13: <ul>
14: <c:forEach var ="menuitems" items="${menuitem}">
15: <li>${menuitems.name}</li>
16: <ul>
17: <c:if test="${fn:length(menuitems.children) gt 0}">
menuitem.jsp
<c:forEach var="menuitem" items="${menuitem.children}">
<li><i class="fa fa-circle-o"></i> <span>${menuitem.name} </span></li>
<c:set var="menuitem" value="${menuitem}" scope="request" />
<jsp:include page="/WEB-INF/views/menuitem.jsp" />
</c:forEach>
I think the problem lies in here. Try renameing var="menuitem" to var="childmenuitem.
I believe that you currently keep passing the same object to your submenu, causing an infinite loop.
Finally I solved it in this way:
tree.jsp:
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<c:set var="menuitem" value="${rootNodes}" scope="request" />
<jsp:include page="menuitem.jsp" />
</body>
</html>
And in menuitem.jsp :
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<ul>
<c:forEach var ="menuitems" items="${menuitem}">
<li>${menuitems.name}</li>
<ul>
<c:if test="${fn:length(menuitems.children) gt 0}">
<li class="droprightMenu">
<c:out value="Has children"></c:out>
<%--<c:forEach var="menuitemc" items="${menuitems.children}">--%>
<c:set var="menuitem" value="${menuitems.children}" scope="request" />
<jsp:include page="menuitem.jsp" />
<%--</c:forEach>--%>
</li>
</c:if>
</ul>
</c:forEach>
</ul>
Hope it will help somebody.
In the servlet:
List<myItem> yourObjectToReturn = search.parserContent();
request.setAttribute("yourObjectToReturn",yourObjectToReturn);
the array yourObjectToReturn consists 3 variable(id, txtfile, sentence) which you can see from
the myItem class
public class myItem{
String sentence;
int id;
String txtfile;
// public myItem(){
// }
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public String getTxtfile(){
return txtfile;
}
public void setTxtfile(String txtfile){
this.txtfile = txtfile;
}
public String getSentence(){
return sentence;
}
public void setSentence(String sentence){
this.sentence = sentence;
}
}
how to display the id, txtfile, sentence in the JSP separately? How to pass the arraylist from servlet to JSP .
the JSP : how to edit my JSP. I got error of my JSP:
type safety: unchecked cast from objectto arraylist
<%# page import="java.io.*" %>
<%# page import="java.net.*" %>
<%# page import="java.util.*" %>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<% List<myItem> myList = (ArrayList<myItem>) request.getAttribute("yourObjectToReturn"); %>
The search Result SENTENCE IS: <%=myList %> --%>
</body>
</html>
Don't use scriptlets in your jsp page.
Include the JSTL standard taglib via:
<%# taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>
Then in your JSP use the iteration tag:
<c:forEach items="${requestScope.yourObjectToReturn}" var="current">
<c:if test="${current.sentence== 'secret' }">
<h1>seeeeeeeeeecret revealed</h1>
</c:if>
</c:forEach>
Where:
${requestScope.yourObjectToReturn} is your collection object.
And (during each iteration):
${current} is your actual element.
For further reference look http://docs.oracle.com/javaee/5/tutorial/doc/bnahq.html
And to avoid weird errors: don't forget to import myItem class (Should really be MyItem, thou...)
EDIT: Before digging deep into JSTL, I suggest you to take a reading of this other question. Particularly focus on the selected answer, it provides great insights.
To retrieve the Id and Txtfile from the List you need to iterate with using for example a for loop like:
...
for (int i=0; i < myList.size(); i++) {
%>
<%=myList.get(i).getId()%>
<%=myList.get(i).getTxtfile())%>
<%}%>
You can use for loop and html together as follows:
<%
#SupressWarnings("unchecked")
List<mtItem> myList
for (MyItem myitem : myList)
{
%>
The search result is <%=myitem%>
<%
}
%>
I am studying PetClinic sample of Spring MVC.
1) I am not sure when is Vets class called? Answered in comments , link to location of the class that call it.
2) Is that used by vetList.jsp?
3) Why is it returning XML?
Vets.java
package org.springframework.samples.petclinic.model;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Simple domain object representing a list of veterinarians. Mostly here to be used for the 'vets' {#link
* org.springframework.web.servlet.view.xml.MarshallingView}.
*
* #author Arjen Poutsma
*/
#XmlRootElement
public class Vets {
private List<Vet> vets;
#XmlElement
public List<Vet> getVetList() {
if (vets == null) {
vets = new ArrayList<Vet>();
}
return vets;
}
}
Thats just to demonstrate a xml response no specific reason. I think it is used here.
<!DOCTYPE html>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%# taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib prefix="datatables" uri="http://github.com/dandelion/datatables" %>
<html lang="en">
<jsp:include page="../fragments/staticFiles.jsp"/>
<body>
<div class="container">
<jsp:include page="../fragments/bodyHeader.jsp"/>
<h2>Veterinarians</h2>
<datatables:table id="vets" data="${vets.vetList}" row="vet" theme="bootstrap2" cssClass="table table-striped" pageable="false" info="false">
<datatables:column title="Name">
<c:out value="${vet.firstName} ${vet.lastName}"></c:out>
</datatables:column>
<datatables:column title="Specialties">
<c:forEach var="specialty" items="${vet.specialties}">
<c:out value="${specialty.name}"/>
</c:forEach>
<c:if test="${vet.nrOfSpecialties == 0}">none</c:if>
</datatables:column>
</datatables:table>
<table class="table-buttons">
<tr>
<td>
View as XML
</td>
<td>
Subscribe to Atom feed
</td>
</tr>
</table>
<jsp:include page="../fragments/footer.jsp"/>
</div>
</body>
</html>
I have set an attribute in session in the UserAction class that will be retrieved in a JSP. The retrieved attribute from the session will control how the page will be displayed. The intention is to make certain portions of the JSP turn on/off depending on the type of user (0 = guest, 1 = admin, 2 = user) after logging in.
Action Class:
public class UserAction extends ActionSupport implements SessionAware {
private static final long serialVersionUID = 1L;
private Map<String, Object> session;
private String userId;
private String userPassword;
private String userEmail;
private int userType;
private Date registeredDate;
#Override
public String execute() {
UserManager um = new UserManager();
String registeredPassword = um.getCurrentUserDetail("user_password",
getUserId());
if (getUserPassword().equals(registeredPassword)) {
String currentUserId = um.getCurrentUserDetail("user_id", userId);
int currentUserType = um.getCurrentUserType(userId);
session.put("currentUserId", (String) currentUserId);
session.put("currentUserType", (Integer) currentUserType);
System.out.println("You have successfully logged in!");
return SUCCESS;
}
System.out.println("Your login has failed!");
return ERROR;
}
#Override
public void setSession(Map<String, Object> session) {
this.session = session;
}
// getters and setters
}
index.jsp:
<%# taglib prefix="s" uri="/struts-tags"%>
<%# page import="com.mypackage.model.UserAction"%>
<html>
<head>
<title>My Site - Home</title>
<%# include file="css/style.css"%>
<%# include file="css/style2.css"%>
<s:set var="type" value="0" />
<s:if test='#session.containsKey("currentUserType")'>
<s:set var="type" value='#session["currentUserType"]' />
</s:if>
</head>
<body>
<div id="wrapper">
<div id="inner">
<div id="header">
<s:if test="type==0">
<%# include file="templates/guest-header.jsp"%>
</s:if>
<s:else>
<%# include file="templates/logged-header.jsp"%>
</s:else>
</div>
<dl id="browse">
<s:if test="type==1 || type==2">
<%# include file="templates/logged-acct.jsp"%>
</s:if>
<dt>NAVIGATE WEBSITE</dt>
<s:if test="type==0">
<%# include file="templates/guest-nav.jsp"%>
</s:if>
<s:elseif test="type==1">
<%# include file="templates/admin-nav.jsp"%>
</s:elseif>
<s:elseif test="type==2">
<%# include file="templates/user-nav.jsp"%>
</s:elseif>
<dt>SEARCH MOVIE</dt>
<dd class="searchform">
<%# include file="templates/search-box.jsp"%>
</dd>
</dl>
<div id="body">
<div class="inner">
<%# include file="templates/content.jsp"%>
</div>
<!-- end .inner -->
</div>
<!-- end body -->
<div class="clear"></div>
<%# include file="templates/copyright.jsp"%>
</div>
<!-- end inner -->
</div>
<!-- end wrapper -->
<%# include file="templates/footer.jsp"%>
</body>
</html>
However, it does not seem to enter any of the if-conditions. At the very least, I believe the guest view should be displaying, since type has been initially set to 0 by <s:set var="type" value="0" />.
(Kindly forgive the design for now, I have been made aware there is an elegant approach with this using <s:include> instead of <%# include %>, but I am only beginning Struts 2. I often make improvements/optimizations after I make it work.)
You've forgot the pound sign # in your testing.
It should be like this.
<s:if test="#type==0">
<%# include file="templates/guest-header.jsp"%>
</s:if>
<s:else>
<%# include file="templates/logged-header.jsp"%>
</s:else>
Reference on how to access a variable in struts
I am new to Struts2. I want to compare JSTL's c tag and Struts2 s tag which one is easy to use... My code as below
ListDepartmentNameAction.java
package actions;
import java.util.List;
import org.apache.log4j.Logger;
import org.hibernate.mapping.Array;
import com.opensymphony.xwork2.ActionSupport;
import service.ListDepNameService;
public class ListDepartmentNameAction extends ActionSupport{
private static Logger log = Logger.getLogger(ListDepartmentNameAction.class);
ListDepNameService listDepNameService;
private List<String> allDNlist ;
public String execute() {
allDNlist = listDepNameService.ListAllDepName();
for (String ss : allDNlist) {
System.out.println(ss);
}
log.info(allDNlist);
return "success";
}
public ListDepNameService getListDepNameService() {
return listDepNameService;
}
public void setListDepNameService(ListDepNameService listDepNameService) {
this.listDepNameService = listDepNameService;
}
public List<String> getAllDNlist() {
return allDNlist;
}
public void setAllDNlist(List<String> allDNlist) {
this.allDNlist = allDNlist;
}
}
query.jsp
<%# page language="java" import="java.util.*" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%# taglib prefix="s" uri="/struts-tags" %>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<s:head />
<h1 align="center" id="h1"></h1>
<body>
<s:form action="listDepName" id="form" method="post">
<input name="Button" type="submit" id="listsubmit" value="List all Department Name"
onclick="javascirpt:abc(this)"/>
</s:form>
<select>
<c:forEach items="${allDNlist}" var="item">
<option value="abc" >${item}</option>
</c:forEach>
</select>
<s:if test="%{allDNlist==null}">456</s:if>
<s:else><s:select name="xxx" list="allDNlist" /></s:else> <!-- 1st -->
<s:select name="xyz" list="allDNlist" /> <!-- 2nd -->
</body>
</html>
"allDNlist" can get value from action class,therefore, JSTL c tag work properly.
I don't understand why the "1st" struts2 select tag work fine, but "2nd" select s tag doesn't work, and got message like this
HTTP Status 500 - tag 'select', field 'list', name 'xyz': The requested list key 'allDNlist' could not be resolved as a collection/array/map/enumeration/iterator type. Example: people or people.{name} - [unknown location]
even I comment() the "2nd" select s tag, I still got same error message as above, only remove it.
EDIT:
I reproduced your whole code and it is perfectly working.
Note that you don't close </head> tag, i reproduced that too and it works the same...
It should be
<head>
<s:head/>
</head>
You should declare your ListDepNameService listDepNameService; as private too (you already have the accessors), and check what type of List is returned.
I tested the code with
allDNlist = new ArrayList<String>();
allDNlist.add("Valore 1 ");
allDNlist.add("Valore 2 ");
allDNlist.add("Valore 3 ");
in execute() method, this is the only difference.
Please try this instead the service call, and let me know...
I had the similar type of collection error while populating the drop down with <s:select: tag. after research i figured out that "i did not initialize my instance variable List" in your case make private List<String> allDNlist = new ArrayList<String>(); should solve the problem.