I want to create JSP templates, i. e. JSP files that contain e.g. a dropdown or input field, to keep the styling of the elements in one place.
Now these templates should be used in different UseCases. For this I would like to pass the corresponding attributes by parameter. My model is always in the requestScope. Here I include a template:
<jsp:include page="/WEB-INF/jspf/edit_element/select.jsp">
<jsp:param name="field" value="country"/>
<jsp:param name="selected" value="${model.selectedCountry}"/>
<jsp:param name="itemList" value="${model.countries}"/>
</jsp:include>
Here my model contains an array of strings (countries like USA,Mexico,..) and a selected country.
Here is my dropdown template:
<div >
<form:select path="${param.field}" cssClass="combobox">
<%-- First element--%>
<form:option value=""><fmt:message key="empty_choice"/></form:option>
<c:forEach items="${param.itemList}" var="item" varStatus="rowCounter" >
<%-- parse String[] --%>
<c:if test="${fn:startsWith(item, '[')}">
<c:set var="item">${fn:replace(item, "[", "")}</c:set>
</c:if>
<c:if test="${fn:endsWith(item, ']')}">
<c:set var="item">${fn:replace(item, "]", "")}</c:set>
</c:if>
<%-- Choose if selected statement is needed--%>
<c:choose>
<c:when test="${item eq param.selected}">
<form:option value="${rowCounter.index}" selected="selected">${item}</form:option>
</c:when>
<c:otherwise>
<form:option value="${rowCounter.index}">${item}</form:option>
</c:otherwise>
</c:choose>
</c:forEach>
</form:select>
</div>
As you can see I have the problem that JSP always converts all parameters to a string. I tried to parse this string back again afterwards. Thus, removing the parenthesis from the first and last item. The problem is on the one hand that it is not very elegant and also complicated cases can occur, so that the parsing becomes a challenge. On the other hand the comparison <c:when test="${item eq param.selected}"> always returns false as result, although the strings are the same.
Is there an elegant way to handle a generic Template? I also tried to give the template a string as a parameter, which then determines which attribute of the model should be accessed. Something like this (unfortunately doesn't work):
<jsp:include page="/WEB-INF/jspf/edit_element/select.jsp">
<jsp:param name="field" value="country"/>
<jsp:param name="selected" value="selectedCountries"/>
<jsp:param name="itemList" value="countries"/>
</jsp:include>
In my template I would like to use the string and access my model:
<c:set var="attribute" value="${param.selected}" scope="request"/>
${model.attribute} => Here the passed string should specify which attribute to access.
Thanks for any answer!
EDIT: Thank you very much for your answer @obourgain. The integration worked great and it was exactly the tool I was looking for. However, I am not allowed to use scriptlet expressions due to security concerns. Is there another way to include attributes? I had already seen (in this tutorial) that you can also define the attributes using inheritance of tag classes and tag library descriptors or even better catch exceptions etc.. However, the question arises how I should design the HTML and CSS templating in this way. Is the HTML code simply defined between the Java statements?
CodePudding user response:
I recommend to use JSP 2.0 tag files syntax. This syntax helps you to create a new tag very easily.
Create the tag file as /WEB-INF/tags/select.tag
:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ tag description="Your custom tag" %>
<%@ attribute name="field" %>
<%@ attribute name="selected" %>
<%@ attribute name="itemList" type="java.util.List" %>
<select name="${field}">
<c:forEach var="item" items="${itemList}" >
<option>${item}</option>
</c:forEach>
</select>
In your template:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
<tags:select field="countries" itemList="${countries}" selected="${selectedCountries}" />