Итерация мультикарты с JSP - PullRequest
5 голосов
/ 10 июня 2011

Я пытаюсь написать панель резервного копирования , показывающую состояние резервного копирования нескольких серверов. Идея состоит в том, чтобы показать таблицу с JSP, которая имеет даты последних нескольких дней в столбцах и имена серверов в строках. В таблице этого бедняка я написал значения Да / Нет.

+------------+------------+------------+------------+
+ Host Name  | 2011-06-10 | 2011-06-09 | 2011-06-08 |
+------------+------------+------------+------------+
| web01      |     Y      |      Y     |     N      |
+------------+------------+------------+------------+
| web02      |     Y      |      Y     |     Y      |
+------------+------------+------------+------------+

Каждый сервер делает свое собственное резервное копирование и сохраняет состояние в Amazon SimpleDb, и я написал метод Java для получения этой информации за последние несколько дней со следующей подписью:

/**
 * List MySQL backups of the last howManyDays days. It starts from today 
 * included at index 0 and goes back in the past until we have a list of 
 * howManyDays days, even if some day doesn't have any data. Return a list of 
 * dates, each of which contains a list of backup jobs executed by servers in 
 * that day.
 * 
 * @param howManyDays
 *         how many days of backup to show
 * @return a Map where each key is the date in ISO format (2011-06-10) and each
 *         element is a backupJob which is represented by a Map where the key is 
 *         the server name (ex. web01, web01) and the value is "Y" if all was 
 *         fine, otherwise it contains the error message.
 */
public Multimap<String, Map<String, String>> listMysqlBackups(int howManyDays);

Multimap - это Google Guava Multimap, потому что у меня несколько резервных копий в день. Пример вывода:

{2011-06-10=[{web06=Y}, {web05=Y}], 2011-06-08=[{web05=Y}, {web06=Y}], 
 2011-06-09=[{web05=Y}, {web06=Y}], 2011-06-07=[{web05=Y}, {web06=Y}]} 

Я не знаю, как использовать эту информацию в JSP. Я пробовал с foreach:

<c:forEach items="${backups}" var="backup" varStatus="backupId">
    ${backup.key}
</c:forEach>

И ответ был:

javax.servlet.ServletException: javax.servlet.jsp.JspTagException: Don't know 
how to iterate over supplied "items" in <forEach>

Теперь я думаю, если я застрелюсь в ногу со слишком сложным возвращаемым значением и должен ли я вместо этого вернуть простой ArrayList из HashMap, где каждый HashMap содержит всю необходимую информацию (дата, имя хоста, сообщение). Если вы, ребята, думаете, что это лучший подход, у меня нет проблем переписать Java-метод, извлекающий данные, но теперь каждая ячейка будет нуждаться в цикле по всему ArrayList, чтобы получить элемент (что может быть хорошо, потому что 6 серверов на 7 дней всего 42 элемента).

Как бы вы подошли к этой проблеме?

Ответы [ 3 ]

9 голосов
/ 10 июня 2011

Тег JSTL forEach не поддерживает Multimaps.Он может перебирать только стандартные коллекции / карты / массивы.

Когда мне нужно перебрать Multimap в JSP, я использую его asMap() представление.Это позволяет мне использовать forEach, так как он знает, как перебирать интерфейс Map.

Это будет выглядеть следующим образом:

public Multimap<String, Map<String, String>> listMysqlBackups(int howManyDays) {
    // ...
}

public Map<String, Collection<Map<String, String>>> getListMysqlBackupsAsMap() {
    return listMysqlBackups(this.numberOfDays).asMap();
}


<c:forEach var="backup" items="${bean.listMysqlBackupsAsMap}">
    <c:set var="dateISO" value="${backup.key}/>
    <c:set var="backupJobs" value="${backup.value}/> <!-- a Collection<Map<String,String>> -->
    <c:forEach var="backupJob" items="${backupJobs}">
        <!-- do something with each backup job (Map<String, String>) for the current date -->
    </c:forEach>
</c:forEach>

Если вы можете использовать JSP EL 2.1Вам не нужен дополнительный геттер.Вы можете просто позвонить asMap() внутри JSP, чтобы получить представление Map.


Несмотря на это, я не уверен, что использование Multimap действительно делает то, что вы хотите здесь,A Multimap<String, Map<String, String>> сопоставляет каждый ключ с коллекцией из Map<String,String>.В вашем случае это означает, что у вас есть:

2011-06-09
    --> Collection
        --> Map<String, String>
        --> Map<String, String>
        --> Map<String, String>
2011-06-10
    --> Collection
        --> Map<String, String>
        --> Map<String, String>
        --> Map<String, String>

Я не уверен, что это то, что вы хотите здесь.Я думаю, что вы хотите Map<String, Map<String, String>>.

Другое решение было бы использовать Table .

от Guava.
1 голос
/ 10 июня 2011

Просто, чтобы подвести итог тому, что я сделал, и не претендовать на лучшее решение, я отвечу на свой вопрос.Мне интересно знать, может ли использование коллекции таблиц Google сделать вещи проще или нет.

Изменен тип возвращаемого списка listMysqlBackups на простой HashMap.

/**
 * List the MySQL backups of the last howManyDays days. It starts from today and 
 * goes back in the past until we have a list of howManyDays days, even if some 
 * day doesn't have any data. Return a Map with each index as the ISO date 
 * underscore the server name. Key example: 2011-06-11_web01
 * 
 * @param howManyDays
 *         how many days of backup to show
 * @return a Map where each key is the date in ISO format and each element is
 *         a backupJob which is represented by a Map where the key is the server
 *         name (ex. web01, web01) and the value is "Y" if all was fine, 
 *         otherwise it contains the error message.
 */
public Map<String, String> listMysqlBackups(int howManyDays)  

Добавлены новые методы для возврата списка дней и списка серверов.

public static List<String> listDatesFromToday(int howManyDays) {
    List<String> dates = new ArrayList<String>();
    String currentDay = DateHelper.getCurrentDateAsIso();
    while (howManyDays > dates.size()) {
        dates.add(currentDay);
        currentDay = DateHelper.previousDay(currentDay);
    }
    return dates;
}

public static List<String> listHosts() {
    return ImmutableList.of("web05", "web06");
}

Показать таблицу с вложенным циклом. Я могу искать ключи напрямую без поискаих на карте, из-за способа, которым я построил ключ.

<table class="dataTable">
    <tr>
    <th></th>
    <c:forEach items="${days}" var="day">
    <th>${day}${host}</th>
    </c:forEach>
    </tr>
<c:forEach items="${hosts}" var="host">
    <tr>
    <th>${host}</th>
    <c:forEach items="${days}" var="day">
    <c:set var="key" value="${day}_${host}"/>
    <td> ${backups[key]}  </td>
    </c:forEach>
    </tr>
</c:forEach>
</table>

Я думаю, что это простое решение, и я доволен им, но если вы, ребята, думаете, что Google Collection Table делает проще,более короткий и понятный код, который я был бы рад услышать.

0 голосов
/ 10 июня 2011

Я думаю, что вы должны попробовать что-то вроде вложенного цикла

например

<c:forEach items="${webs}" var="web" varStatus="webId">
    <c:forEach items="${web.backups}" var="backup" varStatus="backupId">
        ${backup.key}
    </c:forEach>
</c:forEach>
...