我正在尝试编写一个备份仪表板,显示多个服务器备份的状态。我们的想法是显示一个带有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>
现在我在想,如果我用自己太复杂的返回值拍摄自己,我是否应该返回一个简单的HashMap ArrayList,其中每个HashMap包含所有需要的信息(日期,主机名,消息)。如果你们认为是一种更好的方法,我没有任何问题来重写提取数据的Java方法,但现在每个单元都需要遍历所有的ArrayList来获取元素(这可能是好的,因为6个服务器由7个天只有42个元素。)
你会如何解决这个问题?
答案 0 :(得分:9)
JSTL forEach
代码不支持Multimaps
。它只能迭代标准集合/ maps / arrays。
当我需要在JSP中迭代Multimap
时,我使用其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,则不需要额外的getter。您只需在JSP中调用asMap()
即可获得Map
视图。
所有这一切都说,我不确定你使用Multimap
真的做了你想要的。 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>>
。
另一个解决方案是使用Guava的Table。
答案 1 :(得分:1)
总结一下我所做的一切,并且没有声称是我回答问题的最佳解决方案。我很想知道使用谷歌桌面收藏是否可以使事情更简单。
将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集合表制作更简单,更简洁,更清晰的代码,我会很高兴听到。
答案 2 :(得分:-1)
我认为你应该尝试嵌套for循环
e.g。
<c:forEach items="${webs}" var="web" varStatus="webId">
<c:forEach items="${web.backups}" var="backup" varStatus="backupId">
${backup.key}
</c:forEach>
</c:forEach>