3

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

我在 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 对象。这是我正在使用的季节课程:

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 SEVERE: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.service() for servlet Persistent Faces Servlet throw java.lang.IllegalArgumentException: #{season.id} at javax.faces.component.UIComponentBase.validateId(UIComponentBase.java:549) at javax.faces.component.UIComponentBase.setId(UIComponentBase.java:351) at javax。 faces.webapp.UIComponentTag.createComponent(UIComponentTag.java:219) 在 javax.faces.webapp.UIComponentClassicTagBase.createChild(UIComponentClassicTagBase.java:486) 在 javax.faces.webapp.UIComponentClassicTagBase。findComponent(UIComponentClassicTagBase.java:670) at javax.faces.webapp.UIComponentClassicTagBase.doStartTag(UIComponentClassicTagBase.java:1142) at com.icesoft.faces.component.CommandButtonTag.doStartTag(CommandButtonTag.java:741) at 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.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) at com.icesoft.faces.context.View.servePage(View.java:133) at 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.StandardContextValve.invoke(StandardContextValve.java:191) 在 org.apache.catalina.core.StandardHostValve 的 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) .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 中,并在我再次单击时将它们从中删除。

但是,在 UI 上,当我只单击一个按钮时,似乎每个按钮都会被切换。例如,当我点击 2009-2010 时,我看到的是:

全部选择

4

1 回答 1

2
<ice:commandButton binding="#{season}"/>

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


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

id属性不能是动态的 - JSF 将使用clientId确保其在客户端上的唯一性(阅读此内容以获得更多详细信息)。


编辑:

但是,在 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 实例),并且您不要尝试在组件本身上存储任何非声明性状态。

我尽可能地使用actionover actionListener- 它使 JSF 的东西远离 POJO。

于 2009-08-04T21:06:31.290 回答