【问题标题】:Dynamically generate ice:commandButton components动态生成 ice:commandButton 组件
【发布时间】:2010-11-16 19:10:33
【问题描述】:

我一直在尝试很多不同的东西,我认为它们会按预期工作。然而,它们让我有些沮丧。这是独家新闻:

我在 Java EE Web 应用程序中使用 ICEFaces 1.8 组件。我的目标是根据对我的数据库的查询在页面上呈现一堆 ice:commandButtons。我希望这些按钮能够切换我稍后将用于参数的选择到另一个数据库查询(基本上是一组用户的查询前端)。我希望输出看起来像这样:

当我点击一个按钮时,我希望对我的页面进行以下更新:

当我在页面上静态创建按钮时,如下所示:

<ice:commandButton id="seasonSEP09" style="background-color: #FFFFFF;" partialSubmit="true" actionListener="#{bean.updateSeasons}" value="2009-2010" />
<ice:commandButton id="seasonSEP08" style="background-color: #FFFFFF;" partialSubmit="true" actionListener="#{bean.updateSeasons}" value="2008-2009" />
<ice:commandButton id="seasonSEP07" style="background-color: #FFFFFF;" partialSubmit="true" actionListener="#{bean.updateSeasons}" value="2007-2008" />
<ice:commandButton id="seasonSEP06" style="background-color: #FFFFFF;" partialSubmit="true" actionListener="#{bean.updateSeasons}" value="2006-2007" />

这很好用,每个按钮都可以按我的预期单独工作。我的支持 bean 已更新,参数已正确添加到 updateSeasons() 方法中,最后我的输出产生了正确的记录。

但是,我知道这不是我想要的。我不想在系统中输入另一个季节时更新这些。维护的噩梦,对吧?

所以我想做的是根据我的数据库表动态生成这些 ice:commandButton 组件,该表充满了 Season 对象。这是我正在使用的 Season 类:

public class Season
{
    String StartMonth;
    String Season;

    public String getStartMonth()
    {
        return StartMonth;
    }
    public void setStartMonth(String startMonth)
    {
        StartMonth = sweep;
    }    
    public void setSeason(String season)
    {
        Season = season;
    }
    public String getSeason()
    {
        return Season;
    }
}

非常简单。两个属性,我保证在数据库中是唯一的。

这是我正在使用的支持 bean:

public class Bean
{
    public Bean()
    {
        defineSeasonsList();
    }

    public List<HtmlCommandButton> seasonsList;

    // seasonsList getter & setter omitted

    public List<String> selectedSeasons;

    // selectedSeasons getter & setter omitted

    private void defineSeasonsList()
    {
        seasonsList = new ArrayList<HtmlCommandButton>();
        selectedSeasons = new ArrayList<String>();

        try
        {
            hibernate.openTransaction();

            for(Season season:defineSeasonsListFromDataSource()))
            {
                HtmlCommandButton button = new HtmlCommandButton();

                button.setId("season" + season.getStartMonth());
                button.setValue(season.getSeason);
                button.setStyle("background-color: #FFFFFF;");
                button.setPartialSubmit(true);

                seasonsList.add(button);
            }                         
        } 
        catch (Exception e)
        {
            System.out.println("Error defining seasons list: " + e.getMessage());
        }
        finally
        {
            hibernate.commitTransaction();
        }               
    }

    public void updateSeasons(ActionEvent ae)
    {
        HtmlCommandButton selected = (HtmlCommandButton) ae.getComponent();

        if(selectedSeasons.contains(selected.getValue().toString()))
        {
            selectedSeasons.remove(selected.getValue().toString());   
            selected.setStyle("background: #FFFFFF;");
        }
        else
        {
            selectedSeasons.add(selected.getValue().toString());
            selected.setStyle("background: #009DD9; color: #FFFFFF;");
        }
    }
}   

好的,我的困境来了。

首先,我尝试渲染这个标记:

<p>
    <ice:panelGroup>
        <ice:panelSeries id="seasonsList" value="#{bean.seasonsList}" var="season">
                <ice:commandButton binding="#{season}"/>                                        
        </ice:panelSeries>
    </ice:panelGroup>
</p>     

我得到这个输出:

因此,出于沮丧和冒险精神,我尝试渲染此标记以实现我的目标:

<p>
    <ice:panelGroup>
        <ice:panelSeries id="seasonsList" value="#{bean.seasonsList}" var="season">
                <ice:commandButton id="#{season.id}" partialSubmit="true" style="background-color: #FFFFFF" value="#{season.value}" actionListener="#{bean.updateSeasons}"/>                                        
        </ice:panelSeries>
    </ice:panelGroup>
</p>   

产生了以下堆栈跟踪:

2009 年 8 月 4 日下午 2:28:11 com.sun.faces.lifecycle.Phase doPhase 严重:JSF1054:(阶段 ID:RENDER_RESPONSE 6,视图 ID:/phase1.jspx)阶段执行期间引发的异常:javax.faces.event.PhaseEvent[source=com.sun.faces.lifecycle.LifecycleImpl@1a477b7] 2009 年 8 月 4 日下午 2:28:11 org.apache.catalina.core.StandardWrapperValve 调用 严重:servlet Persistent Faces Servlet 的 Servlet.service() 抛出异常 java.lang.IllegalArgumentException: #{season.id} 在 javax.faces.component.UIComponentBase.validateId(UIComponentBase.java:549) 在 javax.faces.component.UIComponentBase.setId(UIComponentBase.java:351) 在 javax.faces.webapp.UIComponentTag.createComponent(UIComponentTag.java:219) 在 javax.faces.webapp.UIComponentClassicTagBase.createChild(UIComponentClassicTagBase.java:486) 在 javax.faces.webapp.UIComponentClassicTagBase.findComponent(UIComponentClassicTagBase.java:670) 在 javax.faces.webapp.UIComponentClassicTagBase.doStartTag(UIComponentClassicTagBase.java:1142) 在 com.icesoft.faces.component.CommandButtonTag.doStartTag(CommandButtonTag.java:741) 在 com.icesoft.faces.webapp.parser.Parser.executeJspLifecycle(Parser.java:204) 在 com.icesoft.faces.webapp.parser.Parser.executeJspLifecycle(Parser.java:229) 在 com.icesoft.faces.webapp.parser.Parser.executeJspLifecycle(Parser.java:229) 在 com.icesoft.faces.webapp.parser.Parser.executeJspLifecycle(Parser.java:229) 在 com.icesoft.faces.webapp.parser.Parser.executeJspLifecycle(Parser.java:229) 在 com.icesoft.faces.webapp.parser.Parser.executeJspLifecycle(Parser.java:229) 在 com.icesoft.faces.webapp.parser.Parser.executeJspLifecycle(Parser.java:229) 在 com.icesoft.faces.webapp.parser.Parser.executeJspLifecycle(Parser.java:229) 在 com.icesoft.faces.webapp.parser.Parser.executeJspLifecycle(Parser.java:229) 在 com.icesoft.faces.webapp.parser.Parser.executeJspLifecycle(Parser.java:229) 在 com.icesoft.faces.webapp.parser.Parser.executeJspLifecycle(Parser.java:229) 在 com.icesoft.faces.webapp.parser.Parser.executeJspLifecycle(Parser.java:229) 在 com.icesoft.faces.webapp.parser.Parser.parse(Parser.java:162) 在 com.icesoft.faces.application.D2DViewHandler.renderResponse(D2DViewHandler.java:464) 在 com.icesoft.faces.application.D2DViewHandler.renderView(D2DViewHandler.java:153) 在 com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:110) 在 com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100) 在 com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) 在 com.icesoft.faces.webapp.http.core.JsfLifecycleExecutor.apply(JsfLifecycleExecutor.java:17) 在 com.icesoft.faces.context.View$2$1.respond(View.java:47) 在 com.icesoft.faces.webapp.http.servlet.ServletRequestResponse.respondWith(ServletRequestResponse.java:197) 在 com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet$ThreadBlockingRequestResponse.respondWith(ThreadBlockingAdaptingServlet.java:36) 在 com.icesoft.faces.context.View$2.serve(View.java:72) 在 com.icesoft.faces.context.View.servePage(View.java:133) 在 com.icesoft.faces.webapp.http.core.SingleViewServer.service(SingleViewServer.java:52) 在 com.icesoft.faces.webapp.http.common.ServerProxy.service(ServerProxy.java:11) 在 com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet$4.service(MainSessionBoundServlet.java:114) 在 com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer.service(PathDispatcherServer.java:24) 在 com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet.service(MainSessionBoundServlet.java:160) 在 com.icesoft.faces.webapp.http.servlet.SessionDispatcher$1.service(SessionDispatcher.java:42) 在 com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet.service(ThreadBlockingAdaptingServlet.java:19) 在 com.icesoft.faces.webapp.http.servlet.EnvironmentAdaptingServlet.service(EnvironmentAdaptingServlet.java:63) 在 com.icesoft.faces.webapp.http.servlet.SessionDispatcher.service(SessionDispatcher.java:62) 在 com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:23) 在 com.icesoft.faces.webapp.http.servlet.MainServlet.service(MainServlet.java:153) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:717) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286) 在 org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845) 在 org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583) 在 org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447) 在 java.lang.Thread.run(Thread.java:619)

我是否正在尝试做一些我不应该做的事情?

有没有更好的方法来实现这个目标?

如果需要更多信息,我很乐意提供。

提前谢谢朋友们。

更新

所以我尝试将 seasonsList 集合从 List 更改为 List 并呈现一些不同的标记,如下所示:

<p>
    <ice:panelGroup>
        <ice:panelSeries value="#{bean.seasonsList}" var="season">
                <ice:commandButton partialSubmit="true" style="background-color: #FFFFFF" value="#{season}" actionListener="#{Phase1EventBean.updateSeasons}"/>                                        
        </ice:panelSeries>
    </ice:panelGroup>
</p>

并将defineSeasonsList() 方法更改为:

public void defineNationalSeasonsList()
{
    try
    {
        seasonsList = new ArrayList<String>();
        selectedSeasonsList = new ArrayList<String>();

        hibernate.openTransaction();

        for(UedaNationalDates season:hibernate.getList(new UedaNationalDates(), QueryFactory.getUedaNationalSeasons(hibernate.getHibSession())))
        { 
            nationalSeasonsList.add(season.getSeason());
        }       
    } 
    catch (Exception e)
    {
        System.out.println("Error defining nationalMeasurementPeriods: " + e.getMessage());
    }
    finally
    {
        hibernate.commitTransaction();
    }               
}

这实际上呈现了我想看到的所有按钮,并在我单击它们时将它们正确添加到我的支持 bean 中的 selectedSeasonsList 中,并在我再次单击时将它们从中删除。

但是,在用户界面上,当我单击一个按钮时,每个按钮似乎都被切换了。例如,当我点击 2009-2010 时,我看到的是这样的:

【问题讨论】:

    标签: jsf jakarta-ee icefaces


    【解决方案1】:
    <ice:commandButton binding="#{season}"/>
    

    绑定属性必须绑定到UIComponent 类型的bean 属性。它用于您希望框架为您提供对支持 bean 中的组件的引用或从支持 bean 提供实例的地方)。有关详细信息,请参阅JSF 1.2 spec 的第 3.1.5 节。


    <ice:commandButton id="#{season.id}"
       partialSubmit="true"
       style="background-color: #FFFFFF"
       value="#{season.value}"
       actionListener="#{Phase1EventBean.updateSeasons}"/>
    

    id 属性不能是动态的 - JSF 将使用clientId (read this for more detail) 确保其在客户端上的唯一性。


    编辑:

    但是,在 UI 上,当我单击一个按钮时,似乎每个按钮都被切换了。

    我猜ice:panelSeries 不会像某些重复控件(例如 dataTable)那样存储每一行​​的组件状态。请记住,只有一个按钮实例,即使每“行”编码/解码一次也是如此。

    我从未使用过 ICEfaces,但我建议绑定到类似这样的 bean:

    public class Bean {
    
      private final List<SelectionBean> seasonsList = Arrays.asList(
          new SelectionBean("Spring"), new SelectionBean("Summer"),
          new SelectionBean("Autumn"), new SelectionBean("Winter"));
    
      public List<SelectionBean> getSeasonsList() { return seasonsList; }
    
      public static class SelectionBean {
    
        private String season;
        private boolean selected;
    
        public SelectionBean() {}
        public SelectionBean(String season) { this.season = season; }
    
        public String getSeason() { return season; }
        public void setSeason(String season) { this.season = season; }
    
        public String toggle() {
          System.out.println("toggle " + season);
          selected = !selected;
          return null;
        }
    
        public String getStyle() {
          return selected ? "background-color: yellow" : "background-color: blue";
        }
      }
    }
    

    我已将逻辑缩减到最低限度,但希望您了解如何修改逻辑以重新加入休眠支持。您的组件将变成这样:

    <ice:panelSeries value="#{bean.seasonsList}" var="item">
      <ice:commandButton partialSubmit="true"
         style="#{item.style}"
         value="#{item.season}"
         action="#{item.toggle}"/>                                        
    </ice:panelSeries>
    

    因此,对于列表中的每个项目,所有绑定都会返回到一个状态(一个 SelectionBean 实例),并且您不要尝试在组件本身上存储任何非声明性状态。

    我尽量使用 action 而不是 actionListener - 它使 JSF 的东西远离 POJO。

    【讨论】:

    • 另外,我在我的 actionListener 属性中错误地使用了 Phase1EventBean,我已经更新了。我很抱歉。
    • 哦,HtmlCommandButton 是正确的类型。唔。绑定的措辞是“指定的 ValueExpression 必须指向 UIComponent(或适当的子类)类型的读写 JavaBeans 属性”。我不确定绑定到“var”是否算数。
    • 很好的建议,@McDowell。我会试试这个并在今天晚些时候提供更新。
    • 成功了,@McDowell!感谢您的洞察力!有点令人不安,我不能直接绑定到 HtmlCommandButton 并且需要引入一个额外的类,但这种行为正是我所需要的。荣誉。
    猜你喜欢
    • 2017-05-14
    • 2015-07-26
    • 1970-01-01
    • 1970-01-01
    • 2014-09-28
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 2021-09-29
    相关资源
    最近更新 更多