Problematic
When you are using a mvc framework like spring mvc or struts with templating is hard to define a breadcrumb tree because some pages are common and recheable from differents ways. It means that the page can not detect exactly in which way she is.
for example :
home > product > in stock > detail product 1
home > search product > detail product 1
Solution
Don’t be affraid, there is a solution to solve this problematic. The nodes needs to be directly defined in the controllers classes. In addition of the node name, the level value is required which is represante the hierchy level in the breadcrumb.
for example : (x) = level
home(0) > product(1) > in stock(2) > detail product 1(3)
home(0) > search product(1) > detail product 1(3)
The devlopper only needs to be focused on the graph of his webflow and define all nodes for the entire breadcrumb dipatched in the the differents controllers. if a common node at different level is present then, the level of the node is the max level value for all paths. In this case : 3 = max(3,2)
The result :
A crumb element turned green when the pointer goes over it.

Code
This is the breadcrumb node element
package ch.illuminit.commons.web.breadcrumb; /** * * @author Benoît Julita */ public class Node { private String name; private String url; private int level; /** * Node constructor * @param name of the node * @param value of the node * @param level in the breadcrumb ex root 0 menu 1 sub-menu 2 etc... */ public Node(String name, String value, int level) { this.name = name; this.url = value; this.level=level; } /** * * @return */ public String getName() { return name; } /** * * @param name */ public void setName(String name) { this.name = name; } /** * * @return */ public String getValue() { return url; } /** * * @param value */ public void setValue(String value) { this.url = value; } /** * * @return */ public int getLevel() { return level; } /** * * @param level */ public void setLevel(int level) { this.level = level; } } |
This is class handle and construct the breadcrumb
package ch.illuminit.commons.web.breadcrumb; import java.util.ArrayList; import java.util.List; /** * Provides and handle the tree for the dynamic breadCrumb * @author Benoît Julita */ public class BreadCrumbTree { private List<Node> breadCrumb; private Node findNode(Node node) { for (Node n : breadCrumb) { if (n.getLevel() == node.getLevel()) { return n; } } return null; } /** * Constructor */ public BreadCrumbTree() { breadCrumb = new ArrayList<>(); } /** * Add node in the breadcrumb * @param node */ public void addNode(Node node) { Node c = findNode(node); if (c != null) { int position = breadCrumb.indexOf(c); for (int i = breadCrumb.size() - 1; i >= position; i--) { breadCrumb.remove(i); } } else { if (breadCrumb.size() > 0) { breadCrumb.get(breadCrumb.size() - 1).setValue(node.getValue()); } } breadCrumb.add(node); List<Node> nodeToRemove = new ArrayList<>(); for (int i = 0; i < breadCrumb.size()-1; i++) { if (breadCrumb.get(i).getLevel() >= breadCrumb.get(breadCrumb.size() - 1).getLevel()) { nodeToRemove.add(breadCrumb.get(i)); } } for (Node remove : nodeToRemove) { breadCrumb.remove(remove); } } /** * Return the entire breadcrumb * @return */ public List<Node> getTree() { return breadCrumb; } } |
This is the service interface that the devlopper will call
package ch.illuminit.commons.web.services; import javax.servlet.http.HttpServletRequest; /** * Node pojo for represantating the crumb element * @author Benoît Julita */ public interface BreadCrumbTreeService { /** * Add a node in the breadcrumb * @param nodeName for displaying * @param level in a tree, ex: root 0, menu 1, sub-menu 2 etc... 0 * is a root and last number ex: 3 is a leaf. * @param request */ void addNode(String nodeName, int level, HttpServletRequest request); } |
This is the service implementation that the devlopper will instantiate. with spring for example @service.
package ch.illuminit.commons.web.services.impl; import ch.illuminit.commons.web.breadcrumb.BreadCrumbTree; import ch.illuminit.commons.web.breadcrumb.Node; import ch.illuminit.commons.web.services.BreadCrumbTreeService; import javax.servlet.http.HttpServletRequest; /** * * @author Benoît Julita */ public class BreadCrumbTreeServiceImpl implements BreadCrumbTreeService { public void addNode(String nodeName, int level, HttpServletRequest request) { String referrer = request.getHeader("referer"); Node node = new Node(nodeName, referrer, level); BreadCrumbTree tree = (BreadCrumbTree) request.getSession().getAttribute("breadcrumb"); if (tree == null) { tree = new BreadCrumbTree(); request.getSession().setAttribute("breadcrumb", tree); } tree.addNode(node); } } |
The css code. I found a css example here : http://www.red-team-design.com/css3-breadcrumbs and adapt it for my own needs.
ul { margin: 0px; padding: 0px; list-style: none; } #breadcrumb{ overflow: hidden; width: 100%; } #breadcrumb li{ float: left; margin: 0 .5em 0 1em; } #breadcrumb a, #breadcrumb #current{ background: #ddd; padding-left: 8px; float: left; text-decoration: none; color: #5A554E; position: relative; } #breadcrumb a:hover{ background: #6E8D3D; color:white; } #breadcrumb a:before, #breadcrumb #current:before{ content: ""; position: absolute; top: 50%; margin-top: -1.5em; border-width: 1.5em 0 1.5em 1em; border-style: solid; border-color: #ddd #ddd #ddd transparent; left: -1em; } #breadcrumb #first:before{ border-width: 0; } #first{ border-radius: 5px 0 0 5px; } #first img{ position:relative; top:3px; } #breadcrumb a:hover:before { border-color: #6E8D3D #6E8D3D #6E8D3D transparent; } #breadcrumb a:after, #breadcrumb #current:after{ content: ""; position: absolute; top: 50%; margin-top: -1.5em; border-top: 1.5em solid transparent; border-bottom: 1.5em solid transparent; border-left: 1em solid #ddd; right: -1em; } #breadcrumb a:hover:after{ border-left-color: #6E8D3D; } |
The JSP code. Note: this code can be in a tag if you want tu reuse or share between projects
<div id="breadcrumb"> <ul id="breadcrumb"> <c:url var="home" value="/welcome"/> <c:url value="/images/site/breadcrumb-home.png" var="homeimage"/> <c:forEach var="bc" items="${breadcrumb.tree}" varStatus="status"> <c:choose> <c:when test="${status.index==0}"> <li><a id="first" href="${home}"><img src="${homeimage}"/></a></li> </c:when> <c:when test="${status.index == fn:length(breadcrumb.tree)-1 && status.index!=0}"> <li id="current">${bc.name}</li> </c:when> <c:otherwise> <li><a href="${bc.value}">${bc.name}</a></li> </c:otherwise> </c:choose> </c:forEach> </ul> </div> |
#1 by Cri on 16 janvier 2013 - 10:16
Hi,
it’s an interesting post. I would to use it with elements from a database (I have three levels). If I build the tree by using the BreadCrumbTreeServiceImpl object, could I use the jsp code in any page?
Could you post a more detailed example?
Thank you very much,
Cri
#2 by Benoît Julita on 18 janvier 2013 - 15:26
Hi cri,
if the node name is stored in the database you can modify the BreadCrumbTreeServiceImpl to add an access to your DAO and find node by name or id.
Sorry for the example, I miss to add « how to use it in the controller » so, in you controller you have to do this: (Spring example)
private BreadCrumbTreeService breadCrumbService;
@Autowired
public void setBreadCrumbService(BreadCrumbTreeService breadCrumbService) {
this.breadCrumbService = breadCrumbService;
}
@RequestMapping(value = "/welcome", method = RequestMethod.GET)
public String welcome(HttpServletRequest request) {
breadCrumbService.addNode("nodeID", 0, request);
//do what you want
return "home";
}
The JSP code shoulb be written in the template JSP (if you are using templating) and it will be display on every pages .
Best regards