struts 2 checkboxlistの問題


struts 2のcheckboxlistで問題に遭遇しました.
 
次はjavaオブジェクトです.
package cn.jolestar.struts;

/**
 * @author jolestar
 * 
 */
public class Language {

	private Long id;
	private String name;

	/**
	 * 
	 */
	public Language() {
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final Language other = (Language) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}

}
    
    
package cn.jolestar.struts;

import java.util.List;

/**
 * @author jolestar
 *
 */
public class Album {

	private Long id;
	private String name;
	private List<Language> languages;
	/**
	 * 
	 */
	public Album() {
	}
	public List<Language> getLanguages() {
		return languages;
	}
	public void setLanguages(List<Language> languages) {
		this.languages = languages;
	}
	
}
 
 
次はjspラベルです.
 
<s:checkboxlist  name="album.languages" list="languages" listValue="name" listKey="id" >
</s:checkboxlist>
 
 
ActionにはgetLanguages()メソッドがあり、データベース内のすべての言語を返します.私がAlbumを編集すると、checkboxlistのAlbumの既存の言語が自動的に選択されます.しかし、どうすればいいかは選択されません.仕方なくstruts 2の関連ソースを見て、やっと分かりました.
 
struts 2 checkboxlistのfreemarkerテンプレート:
<#assign itemCount = 0/>
<#if parameters.list?exists>
    <@s.iterator value="parameters.list">
        <#assign itemCount = itemCount + 1/>
        <#if parameters.listKey?exists>
            <#assign itemKey = stack.findValue(parameters.listKey)/>
        <#else>
            <#assign itemKey = stack.findValue('top')/>
        </#if>
        <#if parameters.listValue?exists>
            <#assign itemValue = stack.findString(parameters.listValue)/>
        <#else>
            <#assign itemValue = stack.findString('top')/>
        </#if>
<#assign itemKeyStr=itemKey.toString() />
<input type="checkbox" name="${parameters.name?html}" value="${itemKeyStr?html}" id="${parameters.name?html}-${itemCount}"<#rt/>
        <#if tag.contains(parameters.nameValue, itemKey)>
 checked="checked"<#rt/>
        </#if>
        <#if parameters.disabled?default(false)>
 disabled="disabled"<#rt/>
        </#if>
        <#if parameters.title?exists>
 title="${parameters.title?html}"<#rt/>
        </#if>
        <#include "/${parameters.templateDir}/simple/scripting-events.ftl" />
        <#include "/${parameters.templateDir}/simple/common-attributes.ftl" />
/>
<label for="${parameters.name?html}-${itemCount}" class="checkboxLabel">${itemValue?html}</label>
    </@s.iterator>
<#else>
   
</#if>
 
 
if tag.contains(parameters.nameValue,itemKey)このif文は、checkboxが選択されているかどうかを決定します.tag.contains()が最終的に呼び出すのはorg.apache.struts2.util.ContainUtilのこの方法:
 
 
   public static boolean contains(Object obj1, Object obj2) {
        if ((obj1 == null) || (obj2 == null)) {
            //log.debug("obj1 or obj2 are null.");
            return false;
        }

        if (obj1 instanceof Map) {
            if (((Map) obj1).containsKey(obj2)) {
                //log.debug("obj1 is a map and contains obj2");
                return true;
            }
        } else if (obj1 instanceof Collection) {
            if (((Collection) obj1).contains(obj2) || ((Collection) obj1).contains(obj2.toString())) {
                //log.debug("obj1 is a collection and contains obj2");
                return true;
            }
        } else if (obj1.getClass().isArray()) {
            for (int i = 0; i < Array.getLength(obj1); i++) {
                Object value = null;
                value = Array.get(obj1, i);

                if (value.equals(obj2)) {
                    //log.debug("obj1 is an array and contains obj2");
                    return true;
                }
            }
        } else if (obj1.toString().equals(obj2.toString())) {
            //log.debug("obj1 is an object and it's String representation equals obj2's String representation.");
            return true;
        } else if (obj1.equals(obj2)) {
            //log.debug("obj1 is an object and equals obj2");
            return true;
        }

        //log.debug("obj1 does not contain obj2: " + obj1 + ", " + obj2);
        return false;
    }
 
tag.contains(parameters.nameValue,itemKey)のパラメータparameters.nameValueはラベルの値です.ここでalbumです.languages, parameters.listはlanguages,itemKeyはループ中の現在のlanguageのidである.album.LanguagesにはLanguageオブジェクトが含まれていますが、struts 2ではitemKey--Languageのidを検索します.もちろん検索できませんので、自動的に選択できません.
 
checkboxlistのテンプレートを変更しました.
 
<#assign itemCount = 0/>
<#if parameters.list?exists>
   <@s.iterator value="parameters.list" id="it">
        <#assign itemCount = itemCount + 1/>
        <#if parameters.listKey?exists>
            <#assign itemKey = stack.findValue(parameters.listKey)/>
        <#else>
            <#assign itemKey = stack.findValue('top')/>
        </#if>
        <#if parameters.listValue?exists>
            <#assign itemValue = stack.findString(parameters.listValue)/>
        <#else>
            <#assign itemValue = stack.findString('top')/>
        </#if>
<#assign itemKeyStr=itemKey.toString() />
<input type="checkbox" name="${parameters.name?html}" value="${itemKeyStr?html}" id="${parameters.name?html}-${itemCount}"<#rt/>
        <#if tag.contains(parameters.nameValue,it)>
 checked="checked"<#rt/>
        </#if>
        <#if parameters.disabled?default(false)>
 disabled="disabled"<#rt/>
        </#if>
        <#if parameters.title?exists>
 title="${parameters.title?html}"<#rt/>
        </#if>
        <#include "/${parameters.templateDir}/simple/scripting-events.ftl" />
        <#include "/${parameters.templateDir}/simple/common-attributes.ftl" />
/>
<label for="${parameters.name?html}-${itemCount}" class="checkboxLabel">${itemValue?html}</label>
	</@s.iterator>
<#else>
   
</#if>
tag.contains(parameters.nameValue,itemKey)はtagに変更された.contains(parameters.nameValue,it)、itは現在のループのLanguageオブジェクトで、struts 2のiteratorラベルに設定されています
<@s.iterator value="parameters.list"id="it">.(注意:最新版struts 2の場合、idではなくvarを使用するべきである).
 
これでいいです.languageは、overwrite equalsメソッドとhashCodeメソッドを正しくoverwriteする必要があります.