Performing a redirect, when conversion / validation associated with query parameters fails

前端 未结 2 1413
萌比男神i
萌比男神i 2020-12-10 08:19

The following is a simple use case of .


    

        
2条回答
  •  刺人心
    刺人心 (楼主)
    2020-12-10 08:52

    This is specified behavior. When PROCESS_VALIDATIONS phase ends with a validation failure, both the UPDATE_MODEL_VALUES and INVOKE_APPLICATION phases are skipped. Exactly like as in "regular" forms with . Think of as a and a as a and it will become more clear.

    For your particular requirement, performing a redirect when conversion/validation has failed, there are at least 3 solutions:

    1. As you found out, add a . I'd rather hook on postValidate event instead for better self-documentability.

      
          
          
          
      
      
      public void redirectIfNecessary() throws IOException {
          FacesContext context = FacesContext.getCurrentInstance();
      
          if (!context.isPostback() && context.isValidationFailed()) {
              context.getExternalContext().redirect("some.xhtml");
          }
      }
      

      The check on FacesContext#isPostback() prevents the redirect being performed on validation failures of "regular" forms in the same view (if any).


    2. Extend the builtin LongConverter whereby you perform the redirect in getAsObject() (a validator is insuitable as the default converter for Long would already fail on non-numeric inputs; if a converter fails, the validators are never fired). This is however poor design (tight-coupling).

      
          
          
      
      
      @FacesConverter("idConverter")
      public class IdConverter extends LongConverter {
      
          @Override
          public Object getAsObject(FacesContext context, UIComponent component, String value) {
              if (value == null || !value.matches("[0-9]{1,20}")) {
                  try {
                      context.getExternalContext().redirect("some.xhtml");
                      return null;
                  }
                  catch (IOException e) {
                      throw new FacesException(e);
                  }
              }
              else {
                  return super.getAsObject(context, component, value);
              }
          }
      
      }
      

      You could if necessary play around with inside to "pass" parameters to the converter.

      
          
      
      
      String redirect = (String) component.getAttributes().get("redirect");
      context.getExternalContext().redirect(redirect);
      

    3. Create a custom taghandler which does basically the same as but without the need for an additional backing bean method.

      
      
      
          
          
          
      
      

      com.example.taghandler.ViewParamValidationFailed

      public class ViewParamValidationFailed extends TagHandler implements ComponentSystemEventListener {
      
          private String redirect;
      
          public ViewParamValidationFailed(TagConfig config) {
              super(config);
              redirect = getRequiredAttribute("redirect").getValue();
          }
      
          @Override
          public void apply(FaceletContext context, UIComponent parent) throws IOException {
              if (parent instanceof UIViewRoot && !context.getFacesContext().isPostback()) {
                  ((UIViewRoot) parent).subscribeToEvent(PostValidateEvent.class, this);
              }
          }
      
          @Override
          public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
              FacesContext context = FacesContext.getCurrentInstance();
      
              if (context.isValidationFailed()) {
                  try {
                      context.getExternalContext().redirect(redirect);
                  }
                  catch (IOException e) {
                      throw new AbortProcessingException(e);
                  }
              }
          }
      
      }
      

      /WEB-INF/my.taglib.xml

      
      
          http://example.com/ui
      
          
              viewParamValidationFailed
              com.example.taghandler.ViewParamValidationFailed
            
      
      

      /WEB-INF/web.xml

      
          javax.faces.FACELETS_LIBRARIES
          /WEB-INF/my.taglib.xml
      
      

      True, it's a bit of code, but it ends up in clean and reusable tag and is actually a good fit for a new OmniFaces feature.

提交回复
热议问题