【问题标题】:Adding a custom event listener into java bean for setters将自定义事件侦听器添加到 java bean 中以供 setter
【发布时间】:2012-09-28 16:54:42
【问题描述】:

我有一个 bean,它有很多属性,其中一半是 n 对 n 关系。我还添加了额外的瞬态 'isEdited' 布尔值,以确保用户进行了一些更改,这样我就可以减少所有实体的数据库获取。我当前的问题有时我需要序列化我的 bean 并希望将属性与真实实例进行比较。我尝试的第一个解决方案是来自 apache commons-lang => EqualsBuilder.reflectEqual(); 方法,它对我来说效果不佳,因为一些继承的项目没有以正确的方式实现 equals 方法,我无法编辑它们.我知道我可以添加 ajax 侦听器来更新已编辑的属性,或者我可以更新每个 setter 方法或新的 equals 实现。但我正在寻找更实用和通用的方法,以便将来也可以使用此实现。

所以我想要什么:(假设我有一个简单的 bean):

public class Foo {

    private String prop1;

    private String prop2;

    /**
     * @return the prop1
     */
    public String getProp1() {
        return prop1;
    }

    /**
     * @param prop1 the prop1 to set
     */
    public void setProp1(String prop1) {
        this.prop1 = prop1;
    }

    /**
     * @return the prop2
     */
    public String getProp2() {
        return prop2;
    }

    /**
     * @param prop2 the prop2 to set
     */
    public void setProp2(String prop2) {
        this.prop2 = prop2;
    }



}

我的 bean 将实现一个 EventListener 接口,这个监听器将处理所有的 setter。如果调用任何 setter 方法(在初始化之后),则编辑的属性将设置为 true。

所以我的问题是添加动作/事件侦听器来处理设置器的正确方法是什么?

EDIT** 我试过PropertyChangeListener,但没有得到任何事件输出。如果我添加每个设置器 pcs.firePropertyChange(); 方法,那么我可以通过这些方法直接设置 isEdited 是没有意义的。

【问题讨论】:

    标签: java jsf-2 javabeans addeventlistener


    【解决方案1】:

    你不能有一个Map<String,Boolean> 并用每个setter 更新它吗?以prop1为例:

    public void setProp1(String prop1) { 
        if(!prop1.equals(this.prop1))
            updateMap.put("prop1", true);
        this.prop1 = prop1;
    }
    

    这样,在保存实体时,您将拥有包含该“元数据”的地图。

    编辑: 有一个严重的缺陷,因为如果用户设置一个值,然后返回到原来的地图将保持真实。您可以通过使用另一个地图(或克隆您的对象)与原始值来比较两者来避免这种情况:

    public void setProp1(String prop1) { 
        if(!prop1.equals(this.prop1) && !prop1.equals(ORIGINAL_VALUE))
            updateMap.put("prop1", true);
        else
            updateMap.put("prop1", false);
        this.prop1 = prop1;
    }
    

    编辑: Adam 在方面是正确的,而且确实这是一个可能会花费您一些时间的更改。此外,如果您想使用反射,还有另一个问题,因为您与方法的结构有关。将来,如果您想更改方法的名称或类型,您也必须更新该反射助手类。

    我建议在保存它们之前更新时间值,以便您可以将它们与原始值进行比较,但如果您在没有 getter 的情况下直接访问字段/对象,这将涉及更改您的方法。

    最后,第三种选择(总是有第三种)我认为您可能愿意做的就是在您的组件中使用valueChangeListener。例如:

    <h:inputText id="prop1Input" value="#{bean.prop1}" valueChangeListener="#{bean.changesListener}"/>
    

    你的 bean 应该有一个具有这种结构的方法:

    public void changesListener(ValueChangeEvent e) {
        //Get the new value
        Object o = e.getNewValue();
        //get the component's id
        String componentId = e.getComponent().getId();
        //Cast the value and compare it, after that you should update a map. You are
        //going to need one anyway to know which field changed.
        boolean valueChanged = //compare against original value
        if(componentId.equals("prop1Input"));
        map.put("prop1", valueChanged);
    }
    

    关于这种方法的一个重要说明,监听器将在验证阶段执行。此侦听器的目的是能够处理新旧值,这似乎是您的情况。因为你也可以知道触发它的组件,所以你应该没问题。

    【讨论】:

    • 感谢您的回答。我正在寻找类似的东西,但正如我所提到的,我不想更新每个设置器(有很多:))。即使我更新它们,我也可以只调用 setEdited(true) 而不是在堆中创建地图。但是,如果您有任何建议通过反射获取方法,即使我愿意使用该解决方案。
    • @HRgiger 如果不更改所有设置器,在 POJO 级别可能很难做到。一种解决方案是使用 AOP 和方面,但这通常是项目中的一个重大变化。
    • @Gamb 再次感谢。我不想通过 ajax 调用(已经存在问题)来做到这一点,因为我需要为每个组件添加 valuechangelistener。我正在考虑所有这些解决方案,这就是为什么我提出这个问题并寻找更好的选择。
    • @AdamDyga 谢谢你,因为你说我不能使用当前方面,我什至不想更改设置器:)
    • @HRgiger 由于这样做的方式,如果不更改一些代码,您将很难做到这一点。如果 bean setter 和 getter 包装属性的 setter 和 getter,这会容易得多,但如果您直接访问这些字段,则必须修改该代码,这就是 AOP 适合这种情况的原因。我担心这里没有低成本的可集成方法可以帮助你......除非你愿意使用字节码......
    猜你喜欢
    • 1970-01-01
    • 2018-08-28
    • 1970-01-01
    • 2021-04-17
    • 1970-01-01
    • 1970-01-01
    • 2021-06-23
    • 1970-01-01
    • 2011-05-29
    相关资源
    最近更新 更多