Tuesday, August 25, 2009

JSTL Conditional Tags

I have started using the JSTL tags lately and found them extremely useful. An interesting feature of the JSTL is that you can extend the existing tags to implement your own feaures. Recently I needed a functionality to determine whether a particular date was before or later than the current date. Since I had to display different data based on the comparison result, I needed to use a structure similar to c:choose, c:when and c:otherwise tags.

The when portion of the jsp page would look like this:

<d:dateChoose>
<d:whenFuture year="${year}" month="${month}" >
<input type=text value='<c:out value="${}"/>'>
</d:whenFuture>
</d:dateChoose>

The tag would accept two arguments: year, and month. The tag should construct an instance of the Calendar class and make comparison to the current date.

First of all, you need to extend the ChooseTag, so that it would be in your package.

import org.apache.taglibs.standard.tag.common.core.ChooseTag;
public class DateChoose extends ChooseTag {
public DateChoose() {
super();
}
}

As you can see, you don't have to write any extra code for this class.

For the when tag handler, you need to extend the WhenTagSupport class. You have to implement the condition () method inherited from the abstract ConditionalTagSupport class.

import java.util.Calendar;
import javax.servlet.jsp.JspTagException;

import org.apache.taglibs.standard.tag.common.core.WhenTagSupport;
public class DateWhen extends WhenTagSupport {

private String year, month;

protected boolean condition() throws JspTagException {
Calendar cNow = Calendar.getInstance();
Calendar c = Calendar.getInstance();
int y = Integer.parseInt(year);
int m = Integer.parseInt(month);
c.set(y, m, 1);
return c.after(cNow);
}
... setMonth...method
... setYear... method

}


Here we construct a calendar object and compare it to the current date.

For the tag handler to be able to accept jstl variables and find their values, I added 2 extra methods:

private String findAttr(String attr){

String strAttr =parseVar(attr);
Object objValue =null;

if(strAttr != null){
objValue = pageContext.findAttribute(strAttr);
}
if(objValue != null)
return objValue.toString();
else
return null;
}

private String parseVar(String var){
String jstlVar=null;

if(var !=null && var.startsWith("$"))
jstlVar = var.substring(var.indexOf("{")+1, var.indexOf("}"));

return jstlVar;
}

The setYear method would go like this:

public void setYear(String year) {
String value = findAttr(year);
this.year = (value !=null)?value:year;
}

The setMonth method would be similar to the above.

Now, the good news is that we don't have to write our own handler for the <otherwise> part.
We can use the standard c:otherwise tag, so the final jsp code would look like this:

<d:dateChoose>
<d:whenFuture year="${year}" month="${month}" >
<input type=text value='<c:out value="${text}"/>'>
</d:whenFuture>
<c:otherwise>
<c:out value="${text}"/>
</c:otherwise>
</d:dateChoose>

Thursday, March 26, 2009

Generic JSTL Code That Displays Database Results

The following generic JSTL code displays database query results in a table irrespective of how many columns the ResultSet has. The table heading will contain column names.

<table width='90%'>
<tr>
<c:forEach var="columnName" items="${queryResults.columnNames}">
<th><c:out value="${columnName}"/></th>
</c:forEach>
</tr>
<c:forEach var="row" items="${queryResults.rows}">
<tr>
<c:forEach var="columnName" items="${queryResults.columnNames}">
<td><c:out value="${row[columnName]}"/></td>
</c:forEach>
</tr>
</c:forEach>
</table>


The queryResults variable holds the ResultSet.