【问题标题】:Struts2: Updating the values of a "List Of Objects" inside a MapStruts2:更新地图内“对象列表”的值
【发布时间】:2013-02-21 16:06:31
【问题描述】:

有一个对象ObjectA 有一个ObjectB 列表。在ObjectB 中有一个TreeMap。这个TreeMap 有一个String 作为键和一个List 另一个对象ObjectC 作为值。这个TreeMap 和内部的list 已使用s:iterators:textfield 显示在jsp 上,并且它正在正确显示。即 s:textfield 中的“值”是正确的。现在,修改文本字段时出现问题。我们如何在动作类的 ObjectC 中捕获修改后的值?使用此处给出的代码,键(“Key1”)进入操作,但值为 null。

Java 代码

public class ObjectA implements Serializable {
private Integer attr1;
private List<ObjectB> objB;
//...getters and setters....
public class ObjectB implements Serializable {
private Integer attr11;
private TreeMap<String,List<ObjectC>> allPlainFields;
// ...getters and setters....
public class ObjectC implements Serializable {
private Integer attr111;
public String attr112;
// ...getters and setters....

JSP 代码

<s:iterator value="objA.objB" var="currentObjB" status="currentGroupStatus">

  <s:iterator value="#currentObjB.allPlainFields" var="parentMap" status="headerStatus">
     <s:iterator value="#parentMap.value" var="fieldList" status="fieldStatus">

       <s:textfield  name="objA.objB[%{#currentGroupStatus.index}].allPlainFields['%{#parentMap.key}'][%{#fieldStatus.index}].attr112"/>


</s:iterator>                       

 </s:iterator> 

呈现的 HTML: &lt;input type="text" id="review-act1_objA_objB_0__allPlainFields_'Key1'__6__attr112" value="Correct Value" name="objA.objB[0].allPlainFields['Key1'][0].attr112"&gt;

eclipse“变量”视图中的对象结构展示

objA    Object A  (id=955)  
objB    ArrayList<E>  (id=966)  
    elementData Object[10]  (id=967)    
        [0] ObjectB  (id=968)   
            allPlainFields  TreeMap<K,V>  (id=972)  
                comparator  null    
                descendingMap   null    
                entrySet    TreeMap$EntrySet  (id=979)  
                keySet  null    
                modCount    1   
                navigableKeySet null    
                root    TreeMap$Entry<K,V>  (id=980)    
                size    1   
                values  null    

        [1] ObjectB  (id=969)   
        [2] ObjectB  (id=970)   
        [3] ObjectB  (id=971)   
        [4] null    
        [5] null    
        [6] null    
        [7] null    
        [8] null    
        [9] null    
    modCount    4   
    size    4   

****在 Eclipse“变量”视图中,allPlainFields 的值为**:** {Key1=}

编辑(2013 年 2 月 27 日)

试过这个,但没有用。这些值出现在 jsp 上,但在提交时,它们不会起作用:

Action 类中:

private TreeMap<String,ObjectCList> testTreeMap = new TreeMap<String,ObjectCList>();
//get,set and setting two keys in map "mykey1" and "mykey2"

ObjectCList类中:

private ArrayList<ObjectC> paramMdlList;
 //default constructor, get, set

JSP:

<s:form id="test-map" method="post">
<s:iterator value="testTreeMap" var="pMap" status="hStatus">
     <li><label><s:property value="%{#pMap.key}" /></label> 
        <s:iterator value="%{#pMap.value.paramMdlList}" var="pList" status="innerStatus">
            <s:textfield name="testTreeMap['%{#pMap.key}'].paramMdlList[%{#innerStatus.index}].attr111"/>
            <s:textfield name="testTreeMap['%{#pMap.key}'].paramMdlList[%{#innerStatus.index}].attr112"/> 

        </s:iterator>


    </li>

</s:iterator>
<s:submit value=" " type='button' id="btnh1" action="saveTreeMap">
            <span>Save TreeMap</span>
</s:submit>
</s:form>

提交表单时,会调用actionupdateTreeMap 方法。地图打印如上here

public String updateTreeMap(){

    for (Map.Entry<String, ObjectCList> entry : testTreeMap.entrySet())
    {
        System.out.println(entry.getKey() + "/" + entry.getValue());
    }

    return SUCCESS;

}

什么是“印刷”: 我的钥匙1/ 我的钥匙2/ 即空值

下面的屏幕显示来自 jsp 的值

【问题讨论】:

  • @Roman,另一个链接是列表中的地图。这个用于列表内的地图内的列表。从逻辑上讲,这应该以类似的方式工作,但令人惊讶的是它不是。
  • 你收到第一个问题的答案了吗?每次更改结构时,我们都应该复制彼此的代码?为什么要多次问同一个问题。通过回答问题赚取声望,然后将其用于赏金。
  • @Roman,是的,我确实收到了第一个问题的答案,我也接受了。看起来里面的另一个级别的集合不起作用。它看起来像同一个问题,但事实并非如此。你之前有遇到过这样的问题吗?
  • 我不明白,就我而言,我从来没有,从来没有使用过这样的表达方式,不必要的复杂性会导致错误和数月、数年的工作。

标签: java collections struts2 treemap ognl


【解决方案1】:

根据您的最新更新。如果您使用TreeMap Struts2 无法正确确定其中的元素类型。将testTreeMap 的声明从TreeMap 更改为Map

private Map<String,ObjectCList> testTreeMap = new TreeMap<String,ObjectCList>();

或者用com.opensymphony.xwork2.util.Element注解testTreeMap来告诉Struts2 map里面的元素是什么类型。

@Element(value = ObjectCList.class)
private TreeMap<String,ObjectCList> testTreeMap = new TreeMap<String,ObjectCList>();

【讨论】:

  • 如果没有 Andrea Ligios 的努力,不可能如此接近解决方案!谢谢安德里亚!
  • 只是出于好奇,这个元素符号是否适用于guava TreeBasedTable?这就是它开始的地方,早期的TreeBasedTable 被替换为列表映射。 TreeBasedTable 没有暴露默认构造函数,而是有一个 .create 方法。例如:@Element(value = TreeBasedTable.class) Table&lt;Integer,String,ObjectC&gt; tableRepresentation = TreeBasedTable.create();
【解决方案2】:

我变得好奇并做了其他实验。

我发现Lists 在Lists 中,Maps 在Maps 中(以及所有的插值)都没有声明为接口(@98​​7654325@,Map),或者声明为它们的实现(ArrayListHashMapTreeMap)由XWork Converter 正确处理。

所有的测试用例都失败了。

也许是我的错,如果是这样,我们真的需要一些 OGNL 专家,因为在整个网络上都没有谈论这个。

然后我尝试了我非常确定可行的方法:以纯 OOP 的方式将这些信息封装在 自定义对象 中。

它成功了:)

代替

private ArrayList<ArrayList<String>> outerObjects;

你可以在你的Action

中使用
private ArrayList<OuterObject> outerObjects; 

/* GETTERS AND SETTERS */
public ArrayList<OuterObject> getOuterObjects() {
    return outerObjects;
}
public void setOuterObjects(ArrayList<OuterObject> outerObjects) {
    this.outerObjects = outerObjects;
}

OuterObject定义:

/* ELSEWHERE IN YOUR PROJECT... */
public class OuterObject{
    private ArrayList<InnerObject> innerObjects;

    /* GETTERS AND SETTERS */
    public ArrayList<InnerObject> getInnerObjects() {
        return innerObjects;
    }
    public void setInnerObjects(ArrayList<InnerObject> innerObjects) {
        this.innerObjects = innerObjects;
    }       
}

InnerObject定义:

public class InnerObject{
    String innerField;

    /* GETTERS AND SETTERS */       
    public String getInnerField() {         
        return innerField;
    }
    public void setInnerField(String innerField) {
        this.innerField = innerField;
    }

}

Action 的可选 execute() 方法来测试预设值:

        InnerObject innerObj1 = new InnerObject();
        innerObj1.setInnerField("Inner Value 1");

        ArrayList<InnerObject> innerObjArrayList = new ArrayList<InnerObject>();
        innerObjArrayList.add(innerObj1);

        OuterObject outerObj1 = new OuterObject();      
        outerObj1.setInnerObjects(innerObjArrayList);

        outerObjects = new ArrayList<OuterObject>();
        outerObjects.add(outerObj1);

JSP

    <s:form>
        <s:textfield name="outerObjects[0].innerObjects[0].innerField" />
        <s:submit/>
    </s:form>

(迭代时,只需将[%{#stat.index}] 用于Lists 和['%{#stat.index}'] 用于Maps)

相同的解决方案适用于每一种可迭代结构(可能除了需要调用.create() 方法的Guava 东西)。

当然,这并不是在所有情况下都方便,在您的示例中,您已经有一个巨大的结构这几乎会使它翻倍,但是它可以工作,它是 OOP,您的 OGNL 会更清晰(因为名称),但似乎是唯一的方法。

注意:类必须是真正的独立类,而不是Inner Classes,这是OGNL 无法自动装配对象的另一种情况。

希望有帮助


编辑

那么你所需要的,只是多一层:

改变这个:

private TreeMap<String,List<ObjectC>> allPlainFields;

到这里

private TreeMap<String,ObjectX> allPlainFields;

并创建一个ObjectX,其中包含一个私有字段List&lt;ObjectC&gt;

它会起作用的。

【讨论】:

  • 会试一试。但是,当我将 s:textfield 更改为 &lt;s:textfield name="objA.objA[%{#currentGroupStatus.index}].allPlainFields.get('%{#parentMap.key}').get(%{#fieldStatus.index}).attr112"/&gt; 时,我在日志中收到一条错误消息: Unexpected Exception catched setting 'objA.objB[0].allPlainFields.get('Key1').get( 0).attr112' on 'class com.vm.action.Act1: Error setting expression 'objA.objB[0].allPlainFields.get('Key1').get(0).attr112' with value ['testval', ]。请注意添加“,”和 testval 旁边的空格。这是迄今为止我得到的最接近的;OGNL 尝试了一些东西 :)
  • Vicky,我已经接近了很多次(例如 List> 和 ArrayList> 之间存在差异;显然,在第一种情况下,OGNL 有问题尝试“猜测”接口的正确实现...顺便说一句,考虑一下,您的结构不会“几乎翻倍”,您只需要再增加一个级别。我现在正在用它更新答案。跨度>
  • @Andrea,我已经根据您的第一个响应添加了一个额外的层,我认为,这应该没关系(?)这是我在地图上使用 2 个不同映射得到的 2 个不同错误级别:场景1:在'class com.hm.action.Act1上设置'rqPGPrmMdl.rqGrp[1].pFWrap.allPFields['DefaultHeader'].paramMdlList[7].pValue'出现意外异常:错误设置表达式'rqPGPrmMdl.rqGrp[1].pFWrap.allPFields['DefaultHeader'].paramMdlList[7].pValue' with value '[Ljava.lang.String;@3b9b2222'ognl.NoSuchPropertyException: java.lang.String.paramMdlList
  • 场景 2:在 'class com.hm.action.Act1 上捕获了意外异常设置 'rqPGPrmMdl.rqGrp[1].pFWrap.allPFields.get('DefaultHeader').paramMdlList[5].pValue':错误设置表达式 'rqPGPrmMdl.rqGrp[1].pFWrap.allPFields.get('DefaultHeader').paramMdlList[5].pValue' 的值为 '[Ljava.lang.String;@3c67312' ognl.OgnlException: source is null for getProperty(null, "paramMdlList")
  • @AndreaLigios :Aleksandr M 给出的最后一步奏效了。但是,如果没有您的努力,就不可能如此接近解决方案!非常感谢!在 SO 上有什么可以感谢您所付出的巨大努力吗?
猜你喜欢
  • 2016-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-11
  • 2015-01-09
  • 2018-01-28
相关资源
最近更新 更多