2011-06-10 92 views
5

我正在嘗試編寫一個備份儀表板,顯示多個服務器備份的狀態。這個想法是顯示一個JSP表,其中最後幾天的日期在列中,而服務器名稱在行中。在這個窮人的桌子上,我寫了Yes/No values。使用JSP迭代Multimap

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

每個服務器,做自己的備份和保存狀態到亞馬遜的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個元素)。

你會如何解決這個問題?

回答

8

該標籤不支持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,你不需要額外的吸氣劑。您可以簡單地在JSP中調用asMap()以獲取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>>

另一種解決方案是使用Guava的Table

+1

用於使用表格來表示表格。 – Ray 2011-06-10 11:05:24

+0

如果我按照我所說的日期+主機名(我甚至不需要下劃線)使用這些鍵,我可以下載一個簡單的Map 並且已經足夠了,而且我不需要循環獲取元素。表看起來也很有趣,但是JSP forEach是否可以使用它?否則會增加複雜性,而目的是降低複雜性。 – stivlo 2011-06-10 11:49:43

+0

我接受你的回答,提供有用的和詳細的解釋,儘管我決定使用我的解決方案解釋如下,因爲只有一個HashMap比較簡單,而不必遍歷三個層次。感謝您的幫助。 – stivlo 2011-06-25 11:28:58

-1

我認爲你應該嘗試一些嵌套for循環

例如,

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

嗯,是的,但問題是,我甚至無法編碼Multimap上的外循環,因爲JSP forEach不知道如何迭代它,如上面顯示的錯誤消息。 – stivlo 2011-06-10 05:10:18

+0

你可以嘗試任何其他地圖像'HashMap'而不是'MultiMap' – 2011-06-10 05:15:51

+0

不與以下結構,因爲我有每個鍵的多個值,所以要麼我改變數據結構,例如用我說明的ArrayList,或者我不能使用HashMap或者我會覆蓋密鑰的值。或者我可以使用帶有組合鍵日期+下劃線+主機名的HashMap。 – stivlo 2011-06-10 05:48:13

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> 

我覺得這個辦法很簡單,我很喜歡它,但是,如果你們認爲谷歌收集表,使更簡單,更短和更清潔的代碼,我很樂意聽到的。