【问题标题】:Avoiding to create the same converters for different beans避免为不同的 bean 创建相同的转换器
【发布时间】:2018-05-20 05:29:59
【问题描述】:

我成功实现了一个 bean 使用的 h:selectOneMenu 转换器,但我想使用来自不同 bean 的相同转换器,而不是再次创建相同的转换器。

目前我有:

转换器

@FacesConverter(value = "csiConverter")
public class CsiConverter implements Converter {

@Override
public Object getAsObject(FacesContext ctx, UIComponent uiComponent, String dcId) {
    ValueExpression vex =
            ctx.getApplication().getExpressionFactory()
                    .createValueExpression(ctx.getELContext(),
                            "#{cfgbean}", CfgDbBean.class);

   ...
}

@Override
public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object o) {
    return ((Csi) o).getCsi();
}

和xhtml

     <div class="form-group">
      <label>CSI</label>
     <h:selectOneMenu id="csi" styleClass="form-control" value="#{cfgbean.csi}" converter="csiConverter">
            <f:selectItems var="csival" itemLabel="#{csival.csi} - #{csival.name}" itemValue="${csival}" value="#{cfgbean.csilist}" />
        </h:selectOneMenu>          
      </div>

一切正常。 现在我想在不同的 xhtml 中创建相同的 selectOneMenu 联系不同的 bean 以显示相同的内容。

问题是转换器类内部连接了 bean 引用和 bean 类。(createValueExpression(ctx.getELContext(), "#{cfgbean}", CfgDbBean.class);)

如何避免连接该引用并为所有 Bean 提供通用 csiConverter

谢谢

【问题讨论】:

  • 感谢您的回复,我将尝试创建一个专用 bean 并从所有其他人那里引用它,我想应该比实现所读到的内容更容易。稍后我会分享和评论。
  • 我试过了,但它不起作用。所以我们需要在 getasobject 方法中添加一些检查以从不同的 bean 获取对象

标签: jsf jsf-2 converter


【解决方案1】:

我有一个转换器,其中getAsObject 方法可选地使用属性来传递bean 名称。如果未设置属性,我使用组件的 value 属性来检测值绑定到的对象类型:

ValueExpression valueExpression = uiComponent.getValueExpression("value");
Class<?> type = valueExpression.getType(ctx.getELContext());

从类型中我可以确定 bean 名称。这可能也是您的一个选择。

就我而言:

String beanName = type.getSimpleName() + "Bean";
beanName = beanName.substring(0, 1).toLowerCase() +
           beanName.substring(1);

如果您在不同的 bean 上使用相同的类型,您应该能够从以下位置获取 bean 名称:

valueExpression.getExpressionString()

它返回用于创建表达式的原始字符串,未经修改。在你的情况下:

#{cfgbean.csi}

只需从该字符串中删除 .csi 部分即可获取 bean。如果您的 bean 扩展了一个抽象 bean / 实现了一个类似 CsiHolder 的接口(或您给它起的任何名称),您可以获得这样的 bean:

ctx.getApplication().evaluateExpressionGet(ctx, "#{cfgbean}", CsiHolder.class)

【讨论】:

  • 你能分享更多关于如何实现它的信息吗?谢谢
  • .. 但我猜你在不同的 bean 中使用相同的类型,对吧?
  • 是的,不同的 bean 正在同时使用。按照建议做,我得到了 FormAdd.xhtml @162,154 value="#{formbean.csi}" 所以我应该解析这个值字符串以获取 bean 名称并在映射 java 类之后,对吗?
  • 在这种情况下你可以使用valueExpression.getExpressionString()
  • 是的,这会返回正确的#{cfgbean.csi},那么获取 bean 的类呢?因为这个 Class> type = valueExpression.getType(ctx.getELContext());返回 Csi 对象
【解决方案2】:

这是在 Jasper 的帮助下完成的部分。

    ValueExpression valueExpression = uiComponent.getValueExpression("value");
    String beanName = valueExpression.getExpressionString();
    //#{formbean.data}
    if(beanName.contains("#{")){
        String[] output = beanName.split("\\{");
        if(output.length!=2){
            throw new IllegalArgumentException(beanName + " - invalid format!");
        }else{
            if(output[1].contains(".")){
                String[] bean = output[1].split("\\.");
                beanName = bean[0];
            }else{
                throw new IllegalArgumentException(output[1] + " - invalid format!");
            }
        }
    }else{
        throw new IllegalArgumentException(beanName + " - invalid format!");
    }

    Object p = ctx.getApplication().evaluateExpressionGet(ctx, "#{"+beanName+"}", Object.class);

    if(p instanceof FormBean){
        FormBean p2 = (FormBean) p;
        return p2.getName(dcId); 
    }
    ...
    ...
    ...

一切正常,我解决了这个问题。

【讨论】:

    猜你喜欢
    • 2016-11-21
    • 2015-01-12
    • 2016-03-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-13
    • 2018-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多