使用 JSP 迭代多重映射

发布于 11-14 22:50 字数 2224 浏览 2 评论 0 原文

我正在尝试编写一个备份仪表板来显示多服务器备份的状态。这个想法是用 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 个服务器) days 只有 42 个元素)。

您将如何解决这个问题?

I'm trying to write a backup dashboard showing the status of multiple servers backup. The idea is to show a table with JSP that has the last few days dates in the columns and server names in rows. In this poor man's table I wrote Yes/No values.

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

Each server, does its own backup and saves the status into Amazon SimpleDb and I wrote a Java method to retrieve this information of the last few days with the following signature:

/**
 * 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 is the Google Guava Multimap because I've multiple backups per day. Example output:

{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}]} 

I don't know how to consume this information in JSP. I tried with foreach:

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

And the answer was:

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

Now I'm thinking if I'm shooting myself in the foot with a too complex return value and whether I should instead return a simple ArrayList of HashMap where each HashMap contains all the needed info (date, hostname, message). If you guys think is a better approach I don't have any problems to rewrite the Java method extracting the data, but each cell will now require to loop across all the ArrayList to get the element (which could be ok because 6 servers by 7 days is only 42 elements).

How would you approach this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

泅渡 2024-11-21 22:50:24

JSTL forEach 标记不支持 Multimaps。它只能迭代标准集合/映射/数组。

当我需要在 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> 将每个键映射到 Map集合
就你而言,这意味着你有:

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>

另一个解决方案是使用 Guava 的 Table< /a>.

The JSTL forEach tag does not support Multimaps. It can only iterate over standard collections / maps / arrays.

When I need to iterate over a Multimap in a JSP, I use its asMap() view. This lets me use forEach, since it knows how to iterate over the Map interface.

It would look like the following:

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>

If you can use JSP EL 2.1, you do not need the additional getter. You can simply call asMap() inside the JSP to obtain the Map view.


All this being said, I'm not sure your use of a Multimap really does what you want here. A Multimap<String, Map<String, String>> maps each key to a collection of Map<String,String>.
In your case, it means that you have:

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>

I'm not sure that's what you want here. I think you want a Map<String, Map<String, String>>.

Another solution would be to use Guava's Table.

北座城市 2024-11-21 22:50:24

只是为了总结我所做的事情,而不是声称这是我回答我的问题的最佳解决方案。我很想知道使用 google Table 集合是否可以使事情变得更简单。

将 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");
}

使用嵌套循环显示表。< /strong> 由于我构建密钥的方式,我可以直接查找密钥,而无需在地图中搜索它们。

<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 使代码更简单、更短、更清晰,我会很高兴听到。

Just to summarize what I've done, and without claiming to be the best solution I answer to my question. I'm interested to know if using google Table collection could make things simpler or not.

Changed the return type of listMysqlBackups to a simple 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)  

Added new methods to return the day list and the server list.

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");
}

Show the table with a nested loop. I can seek the keys directly without searching them in the Map, because of the way I built the key.

<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>

I think this solution is simple, and I'm happy with it, but if you guys think that Google collection Table makes simpler, shorter and cleaner code I'd be happy to hear.

萌无敌 2024-11-21 22:50:24

我认为你应该尝试某种嵌套的 for 循环,

例如

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

I think you should try sort of nested for loop

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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文