JSF 1.1:如何在验证消息中显示组件标签而不是clientId



我正在编写一个自定义组件来显示弹出窗口中的验证消息,它工作得很好,但我仍然有一个问题:我想在验证消息中显示组件标签而不是cliendIds。

我已经看了这个问题和类似的问题:

在JSF中使用消息包时从验证消息中删除组件Id

,但我使用jsf 1.1,我得到一个编译错误,如果我试图设置属性labelrequiredMessage的值。因此,我尝试使用<outputLabel />为组件分配标签:

<h:outputLabel for="phone" value="Phone number" />
<h:inputText id="phone" required="true" value="#{backingBean.phoneNumber}" />

无效

是否有一个简单的方法在jsf 1.1使标签出现在验证消息,而不是客户端id?如果没有,我如何在给定组件的情况下检索其相关的标签组件以在Java代码中完成工作?

谢谢。

我找到了一个不需要修改现有JSF代码的解决方案。

  1. 让我的组件渲染器扩展战斧的HtmlMessagesRenderer,它能够使用组件标签而不是它的id
  2. 使用HtmlMessagesRenderer#findInputId检索消息
  3. 组件的Id
  4. 使用HtmlMessagesRenderer#findInputLabel检索消息
  5. 组件的Label
  6. 将消息中的组件Id替换为组件标签

下面是我的组件Render encodeBegin方法的代码摘录,其中我制作了两个分开的循环,第一个用于组件消息,另一个用于全局消息。

注意,FacesContext#getClientIdsWithMessages也返回null,它被认为是全局消息的clientId。

注意,因为组件本身能够检索和使用组件标签,所以if存在;这个解决方案只需要在JSF页面代码中放置一个<myCustomMessages />标签。

public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
// ....
// replace id with label in messages for components
        Iterator<String> clientIdsWithMessages=context.getClientIdsWithMessages();
        while(clientIdsWithMessages.hasNext()){
            String clientIdWithMessages=clientIdsWithMessages.next();
            if(clientIdWithMessages!=null){
                Iterator<FacesMessage> componentMessages=context.getMessages(clientIdWithMessages);
                while(componentMessages.hasNext()){
                    String stringMessage=componentMessages.next().getDetail();
                    try{
                        String inputId =findInputId(context, clientIdWithMessages);
                        String inputLabel = findInputLabel(context, clientIdWithMessages);
                        if(inputId!=null && inputLabel!=null)
                            stringMessage=stringMessage.replace(inputId, inputLabel);
                    } catch(Exception e){
                        // do nothing in this catch, just let the message be rendered with the componentId instead of a label                       }
                    msgBuilder.append(stringMessage);
                    msgBuilder.append("<br />");
                }
            }
        }

        // process global messages
        Iterator<FacesMessage> globalMessages=context.getMessages(null);
        while(globalMessages.hasNext()){
            FacesMessage message=globalMessages.next();
            msgBuilder.append(message.getDetail());
            msgBuilder.append("<br />");
        }
// ...

这里是HtmlMessagesRenderer#findInputLabel源代码的参考,看看它是如何工作的

我想到一个解决办法。你可以添加新的PhaseListener,它将查找PhaseEventPhaseId = RENDER_RESPONSE,并在它的beforePhase方法中写这样的东西:

public class MyPhaseListener implements PhaseListener {
  private void findKeyValuePairInTree(UIComponent root, 
                                      Map<String, String> map) {
    if (root instanceof HtmlOutputLabel) {
      map.put(((HtmlOutputLabel) root).getFor(), 
                       ((HtmlOutputLabel) root).getValue());
    }
    if (root.getChilder() != null && !root.getChildren().isEmpty()) {
      for (UIComponent child : root.getChilder()) {
        findKeyValuePairInTree(child, map);
      }
    }
  private HashMap<String, String> idToLabelMap= new HashMap<String,String>();
  public void beforePhase(PhaseEvent event) {
    if (event.getPhaseId().equals(PhaseId.RENDER_RESPONSE) {
      findKeyValuePairInTree(FacesContext.getCurrentInstance().getViewRoot(),
                             idToLabelMap);
      // after above function finished execution in idToLabelMap will be all 
      // pairs of component ID used in standard FacesMessage as key
      // and HtmlOutputLabel value attr used as value
     
      Set<String> keySet = idToLabelMap.keySet();
      for(String key : keySet) {
        Iterator messages = FacesContext.getCurrentInstance().getMessages(key);
        while (iterator.hasNext) {
          FacesMessage msg = (FacesMessage) iterator.next();
          // now replace all occurences of clientId with label value from map
          msg.setSummary(msg.getSummary().replaceAll(key, idToLabelMap.get(key)));
          msg.setDetails(msg.getDetails().replaceAll(key, idToLabelMap.get(key)));
        }
      }
      FacesContext.getCurrentInstance().getMessages();
    } 
  }
...
}

现在在这个方法之后的渲染阶段,FacesContext.getCurrentInstance().getMessages()中的所有消息都将改变clientId的标签值,因为验证阶段在渲染阶段之前,所有验证将通过或失败-没有更多的消息将来自验证。

唯一的问题是当您在HtmlOutputLabel实例的for属性中使用相同的id两次或更多次时,因为在不同的形式中可以为组件使用相同的id。然后你可以在for attr中在<h:outputLabel>中使用更复杂的id,例如用form id或类似的东西提示它

  1. 绑定你的输出标签。
  2. 绑定错误信息。
  3. 现在设置java输出标签的值。
  4. 检查验证,如果验证失败,获取输出标签值并将其设置为错误消息变量。

相关内容

  • 没有找到相关文章

最新更新