在Struts中我們經常這樣循環的打印Message
<logic:messagesPresent message="true">
? <html:messages id="msg" message="true">
??? <div class="success">
????? <bean:write name="msg"/>
??? </div><br/>
? </html:messages>
</logic:messagesPresent>
查閱struts tag的文檔我們看到了關于messagesPresent的message屬性注釋如下
message
|
By default the tag will retrieve the request scope bean it will iterate over from the Globals.ERROR_KEY constant string, but if this attribute is set to 'true' the request scope bean will be retrieved from the Globals.MESSAGE_KEY constant string. Also if this is set to 'true', any value assigned to the name attribute will be ignored
|
也就是說在將message設置為true時,會去request中尋找Globals.MESSAGE_KEY所代表的bean,然而我們在具體的Action使用ActionMessages類的時候往往是這樣的
ActionMessages messages = getErrors(request);
messages.add(ActionMessages.GLOBAL_MESSAGE , new ActionMessage(key , value0));
saveMessages(request,messages);
而往往困擾人的就在于為什么要給messages中放入名稱為"ActionMessages.GLOBAL_MESSAGE"的ActionMessage對象,而且還需要再次的調用saveErrors(request,messages)方法?
首先要說明的是你為ActionMessage起任何的名稱都沒有關系,因為ActionMessages本身維持著一個HashMap,而參數property就是這個HashMap中的key值,如果不存在則會建立相應的key,并將需要保存的ActionMessage對象存入到這個key所對應的List中。
??? public void add(String property, ActionMessage message) {
??????? ActionMessageItem item = (ActionMessageItem) messages.get(property);
??????? List list = null;
??????? if (item == null) {
??????????? list = new ArrayList();
??????????? item = new ActionMessageItem(list, iCount++, property);
??????????? messages.put(property, item);
??????? } else {
??????????? list = item.getList();
??????? }
??????? list.add(message);
??? }
至于為什么一定要調用saveMessages(request,messages)?看看它具體的實現邏輯就清楚了
??? protected void saveMessages(
??????? HttpServletRequest request,
??????? ActionMessages messages) {
??????? // Remove any messages attribute if none are required
??????? if ((messages == null) || messages.isEmpty()) {
??????????? request.removeAttribute(Globals.MESSAGE_KEY);
??????????? return;
??????? }
??????? // Save the messages we need
??????? request.setAttribute(Globals.MESSAGE_KEY, messages);
??? }
再對比前面介紹的messagesPresent標簽的使用,是不是就清楚了呢?原來它是將ActionMessages對象保存在request中,并且名稱是Globals.ERROR_KEY!從而為tag的順利解析鋪平了道路。當然按理你可以選擇將這樣的對象放置在任何的scope中,但Action只是提供了request , session兩種Scope(不過page , application不經常使用,可以理解,但不提供相應的結構就不太好了)
至于messagesPresent標簽是如何在scope中尋找ActionMessages對象
org.apache.struts.taglib.logic.MessagesPresentTag
??? protected boolean condition(boolean desired) throws JspException {
??????? ActionMessages am = null;
??????? String key = name;
??????? if (message != null && "true".equalsIgnoreCase(message)){
?????????? key = Globals.MESSAGE_KEY;
??????? }
??????? try {
??????????? am = TagUtils.getInstance().getActionMessages(pageContext, key);
???????????
??????? } catch (JspException e) {
??????????? TagUtils.getInstance().saveException(pageContext, e);
??????????? throw e;
??????? }
??????? Iterator iterator = (property == null) ? am.get() : am.get(property);
??????? return (iterator.hasNext() == desired);
??? }
org.apache.struts.taglib.TagUtils
?? public ActionErrors getActionErrors(PageContext pageContext, String paramName)
??????????? throws JspException {
??????? ActionErrors errors = new ActionErrors();
??????? Object value = pageContext.findAttribute(paramName);
??????? if (value != null) {
??????????? try {
??????????????? if (value instanceof String) {
??????????????????? errors.add(
??????????????????????????? ActionMessages.GLOBAL_MESSAGE,
??????????????????????????? new ActionMessage((String) value));
??????????????? } else if (value instanceof String[]) {
??????????????????? String keys[] = (String[]) value;
??????????????????? for (int i = 0; i < keys.length; i++) {
??????????????????????? errors.add(
??????????????????????????????? ActionMessages.GLOBAL_MESSAGE,
??????????????????????????????? new ActionMessage(keys[i]));
??????????????????? }
??????????????? } else if (value instanceof ActionErrors) {
??????????????????? errors = (ActionErrors) value;
??????????????? } else {
??????????????????? throw new JspException(
??????????????????????????? messages.getMessage(
??????????????????????????????????? "actionErrors.errors",
??????????????????????????????????? value.getClass().getName()));
??????????????? }
??????????? } catch (JspException e) {
??????????????? throw e;
??????????? } catch (Exception e) {
??????????????? log.debug(e, e);
??????????? }
??????? }
??????? return errors;
??? }
PageContext中的findAttribute會幫你在scope中尋找名稱為Globals.MESSAGE_KEY的ActionMessage對象。
注意
雖然Struts已經聲明:不推薦使用ActionErrors & ActionError對象,但在一些遺留的系統中,依然還是可以看到其影子,所以如果你的系統不幸屬于這樣的兩種混合系統,有以下的幾種方法可以參考
1。兩次調用messagesPresent,如下
<!-- Print ActionErrors Object -->
<logic:messagesPresent>
? <html:messages id="msg" message="true">
??? <div class="success">
????? <bean:write name="msg"/>
??? </div><br/>
? </html:messages>
</logic:messagesPresent>
<!-- Print ActionMessages Object -->
<logic:messagesPresent message="true">
? <html:messages id="msg" message="true">
??? <div class="success">
????? <bean:write name="msg"/>
??? </div><br/>
? </html:messages>
</logic:messagesPresent>
2.分別使用<html:messages> <html:errors>標簽,當然在老系統中需要調用Action的saveErrors方法,而在新的應用中要調用saveMessages方法。
3.更換所有的ActionErrors為ActionMessages,并將所有調用saveErrors的地方更換成saveMessages,并將<html:errors>標簽相應的更換成<html:messages message="true"> - 推薦!
?