How to display my application's errors in JSF?

2019-01-07 05:20发布

In my JSF/Facelets app, here's a simplified version of part of my form:

<h:form id="myform">
  <h:inputSecret value="#{createNewPassword.newPassword1}" id="newPassword1" />
  <h:message class="error" for="newPassword1" />
  <h:inputSecret value="#{createNewPassword.newPassword2}" id="newPassword2" />
  <h:message class="error" for="newPassword2" />
  <h:commandButton value="Continue" action="#{createNewPassword.continueButton}" />
</h:form>

I'd like to be able to assign an error to a specific h:message tag based on something happening in the continueButton() method. Different errors need to be displayed for newPassword and newPassword2. A validator won't really work, because the method that will deliver results (from the DB) is run in the continueButton() method, and is too expensive to run twice.

I can't use the h:messages tag because the page has multiple places that I need to display different error messages. When I tried this, the page displayed duplicates of every message.

I tried this as a best guess, but no luck:

public Navigation continueButton() {
  ...
  expensiveMethod();
  if(...) {
    FacesContext.getCurrentInstance().addMessage("newPassword", new FacesMessage("Error: Your password is NOT strong enough."));
  }
}

What am I missing? Any help would be appreciated!

8条回答
趁早两清
2楼-- · 2019-01-07 05:26

In case anyone was curious, I was able to figure this out based on all of your responses combined!

This is in the Facelet:

<h:form id="myform">
  <h:inputSecret value="#{createNewPassword.newPassword1}" id="newPassword1" />
  <h:message class="error" for="newPassword1" id="newPassword1Error" />
  <h:inputSecret value="#{createNewPassword.newPassword2}" id="newPassword2" />
  <h:message class="error" for="newPassword2" id="newPassword2Error" />
  <h:commandButton value="Continue" action="#{createNewPassword.continueButton}" />
</h:form>

This is in the continueButton() method:

FacesContext.getCurrentInstance().addMessage("myForm:newPassword1", new FacesMessage(PASSWORDS_DONT_MATCH, PASSWORDS_DONT_MATCH));

And it works! Thanks for the help!

查看更多
聊天终结者
3楼-- · 2019-01-07 05:28

Simple answer, if you don't need to bind it to a specific component...

Java:

            FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Authentication failed", null);
            FacesContext context = FacesContext.getCurrentInstance();
            context.addMessage(null, message);      

XHTML:

            <h:messages></h:messages>
查看更多
爱情/是我丢掉的垃圾
4楼-- · 2019-01-07 05:34

Remember that:

FacesContext context = FacesContext.getCurrentInstance();
context.addMessage( null, new FacesMessage( "The message to display in client" ));            

is also valid, because when null is specified as first parameter, it is applied to the whole form.

More info: coreservlets.com //Outdated

查看更多
走好不送
5楼-- · 2019-01-07 05:35

I tried this as a best guess, but no luck:

It looks right to me. Have you tried setting a message severity explicitly? Also I believe the ID needs to be the same as that of a component (i.e., you'd need to use newPassword1 or newPassword2, if those are your IDs, and not newPassword as you had in the example).

FacesContext.getCurrentInstance().addMessage("newPassword1", 
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error Message"));

Then use <h:message for="newPassword1" /> to display the error message on the JSF page.

查看更多
放荡不羁爱自由
6楼-- · 2019-01-07 05:37

Found this while Googling. The second post makes a point about the different phases of JSF, which might be causing your error message to become lost. Also, try null in place of "newPassword" because you do not have any object with the id newPassword.

查看更多
放荡不羁爱自由
7楼-- · 2019-01-07 05:41

FacesContext.addMessage(String, FacesMessage) requires the component's clientId, not it's id. If you're wondering why, think about having a control as a child of a dataTable, stamping out different values with the same control for each row - it would be possible to have a different message printed for each row. The id is always the same; the clientId is unique per row.

So "myform:mybutton" is the correct value, but hard-coding this is ill-advised. A lookup would create less coupling between the view and the business logic and would be an approach that works in more restrictive environments like portlets.

<f:view>
  <h:form>
    <h:commandButton id="mybutton" value="click"
      binding="#{showMessageAction.mybutton}"
      action="#{showMessageAction.validatePassword}" />
    <h:message for="mybutton" />
  </h:form>
</f:view>

Managed bean logic:

/** Must be request scope for binding */
public class ShowMessageAction {

    private UIComponent mybutton;

    private boolean isOK = false;

    public String validatePassword() {
        if (isOK) {
            return "ok";
        }
        else {
            // invalid
            FacesMessage message = new FacesMessage("Invalid password length");
            FacesContext context = FacesContext.getCurrentInstance();
            context.addMessage(mybutton.getClientId(context), message);
        }
        return null;
    }

    public void setMybutton(UIComponent mybutton) {
        this.mybutton = mybutton;
    }

    public UIComponent getMybutton() {
        return mybutton;
    }
}
查看更多
登录 后发表回答