nested Java collection to list items per person per day in a calendar grid using JSTL?

Tags: , ,



I am developing an employee scheduler Java web applicatyion where an employee can specify days they will be out of the office for things such as vacation, business travel, etc…I have a simple mechanism for adding/editing/deleting these records. But I am struggling with the JSTL and which collector I should be passing to the jsp for the forEach looping.

Ultimately I need to display a table on a jsp page that looks omething like this:

October 2010
Employee Sun Mon Tue Wed Thu Fri Sat Sun Mon Tue Wed Thu ...
                              1   2   3   4   5   6   7  ...  
  Abate   *   *   *   *   *  [E]
  Adams   *   *   *   *   *          [E]     [E]
  Benson  *   *   *   *   *      [E]             [E]

Where [E] would be a list of items or events against that employee for that particular day

And this is a sample list of events from a sql call:

EVENT_ID BADGE  EVENT_TYPE_ID EVENT_TYPE_NAME  EVENT_S_DATE 
1        134311 5610          Business Travel  2010-10-08
2        101379 7646          Floating Holiday 2010-10-11
3        005396 3600          Vacation         2010-10-12
4        134311 1318          Military         2010-10-12
5        134311 0575          Sick Time        2010-10-12
6        101379 6652          Unpaid           2010-10-18
7        111243 0575          Sick Time        2010-10-29 

My first approach was to use nested hashmaps and key it with the day but I had difficulty reference the value in the map using JSTL because of the issues with using numbers for keys (My key was the cell number offset by the start day, October starts on day 5 or Friday).

EL access a map value by Integer key

JSTL and hashmap not working.

I foresee me making a bunch of loops in the servlet that populates some type of container to accomplish this.

I’m looking for at least something like “Oh, nest a List in a Map and stuff that in another map” to get me started.

Answer

Ok, I finally figured out the nested collection and loop myself, so I’ll answer my own question. Both the servlet and view code probably could use some improving, but it works.

Servlet:

ArrayList eventListPerDayPerBadge = new ArrayList();
ArrayList eventListPerDay = new ArrayList();
HashMap eventMapByDay = new HashMap();
HashMap eventMapByDayByBadge = new HashMap();

int lastDay = 0;
int eventDay = 1;
String lastBadge = "0";
String currentBadge = "currentBadge";
Event event = null;

Iterator eventList = employeeEvents.iterator();
while (eventList.hasNext()) {

    event = (Event) eventList.next();
    eventDay = DateUtil.toCalendar(event.getEvent_s_date()).get(Calendar.DATE);

    currentBadge = event.getBadge();

    if (eventDay == lastDay) {
        eventListPerDay.add(event);
        if (currentBadge.equals(lastBadge)) {
            eventListPerDayPerBadge.add(event);
        }
        else {
            HashMap tempMap = new HashMap();
            if (eventMapByDayByBadge.get(lastBadge) != null) {
                tempMap = (HashMap) eventMapByDayByBadge.get(lastBadge);
            }
            tempMap.put(new Long(eventDay), eventListPerDayPerBadge);
            eventMapByDayByBadge.put(lastBadge, tempMap);
            eventListPerDayPerBadge = new ArrayList();
            eventListPerDayPerBadge.add(event);
        }
        eventMapByDay.put(new Long(eventDay), eventListPerDay);
    }
    else {
        if (!"0".equals(lastBadge)) {
            HashMap tempMap = new HashMap();

            if (eventMapByDayByBadge.get(lastBadge) != null) {
                tempMap = (HashMap) eventMapByDayByBadge.get(lastBadge);
            }
            tempMap.put(new Long(lastDay), eventListPerDayPerBadge);
            eventMapByDayByBadge.put(lastBadge, tempMap);
            eventMapByDay.put(new Long(lastDay), eventListPerDay);
        }

        eventListPerDayPerBadge = new ArrayList();
        eventListPerDayPerBadge.add(event);

        eventListPerDay = new ArrayList();
        eventListPerDay.add (event);

    }

    lastDay = eventDay;
    lastBadge = currentBadge;
}


// Get the last record into the maps    
HashMap tempMap = new HashMap();
if (eventMapByDayByBadge.get(lastBadge) != null) {
    tempMap = (HashMap) eventMapByDayByBadge.get(lastBadge);
}
tempMap.put(new Long(eventDay), eventListPerDayPerBadge);
eventMapByDayByBadge.put(lastBadge, tempMap);
eventMapByDay.put(new Long(eventDay), eventListPerDay);

request.setAttribute("eventMapByDayByBadge", eventMapByDayByBadge);
request.setAttribute("eventMapByDay", eventMapByDay);

View (not all Attributes used in the view are shown in the servlet):

<table align="center" border="1" cellpadding="3" cellspacing="0" width="100%">
  <tbody>
  <!-- Header ROW -->
     <tr>
        <th>Employee</th>
        <c:forEach var="week" begin="1" end="${iTotalweeks}" varStatus="status">
        <th class="optionYellow">Sun</th>
        <th>Mon</th>
        <th>Tue</th>
        <th>Wed</th>
        <th>Thu</th>
        <th>Fri</th>
        <th class="optionYellow">Sat</th>
        </c:forEach>
     </tr>
  <!-- Week Day Number ROW -->
     <tr>
        <td align="center" height="35" class="dsb">*&nbsp;</td>
        <c:forEach var="week" begin="1" end="${iTotalweeks}" varStatus="status">

           <c:forEach var="cell" begin="${1+7*(week-1)}" end="${7+7*(week-1)}"
              step="1" varStatus="status">
              <c:set var="dayNo" value="${cell-weekStartDay+1}" />
                 <c:choose>
                 <c:when test="${weekStartDay>cell || (cell-weekStartDay+1)>days}">
                    <td align="center" height="35" class="<c:out value="${weekendCellMap[cell]}" />">*&nbsp;</td>
                 </c:when>
                 <c:otherwise>
                    <td class="<c:out value="${holidayColorMap[dayNo]}" />"><span class="calDayNo"> <c:out value="${dayNo}" /></span>
                       <span class="calDayName"> <c:out value="${holidayNameMap[dayNo]}" /></span>
                    </td>
                 </c:otherwise>
                 </c:choose>
           </c:forEach>

        </c:forEach>
     </tr>

  <!-- Employee ROW -->
     <c:forEach var="employee" items="${employeeList}">
     <c:set var="map" value="${eventMapByDayByBadge[employee.badge]}" />
     <tr>
        <td align="center" height="35" NOWRAP><c:out value="${employee.lname}" />, <c:out value="${employee.firstName}" /><br>
           (<c:out value="${employee.badge}" />)
        </td>
        <c:forEach var="week" begin="1" end="${iTotalweeks}" varStatus="status">

           <c:forEach var="cell" begin="${1+7*(week-1)}" end="${7+7*(week-1)}"
              step="1" varStatus="status">
              <c:set var="dayNo" value="${cell-weekStartDay+1}" />
           <c:choose>
              <c:when test="${weekStartDay>cell || (cell-weekStartDay+1)>days}">
                 <td align="center" height="35" class="<c:out value="${weekendCellMap[cell]}" />">*&nbsp;</td>
              </c:when>
              <c:otherwise>
                 <td align="center" height="35" class="<c:out value="${holidayColorMap[dayNo]}" />"><span>&nbsp;
                    <c:forEach var="event" items="${map[dayNo]}">
                       <c:out value="${event.event_type_name}" />
                    </c:forEach></span></td>
              </c:otherwise>
              </c:choose>
           </c:forEach>

        </c:forEach>
     </tr>
     </c:forEach>

  </tbody>
</table>

Example output from the view

Sample Output



Source: stackoverflow