2012-01-03 30 views
6

Dưới đây là lĩnh vực:chuyển đổi JSF gây validator (s) để được bỏ qua

<h:inputText id="mobilePhoneNo" 
      value="#{newPatientBean.phoneNo}" 
      required="true" 
      requiredMessage="Required" 
      validator="#{mobilePhoneNumberValidator}" 
      validatorMessage="Not valid (validator)" 
      converter="#{mobilePhoneNumberConverter}" 
      converterMessage="Not valid (converter)" 
      styleClass="newPatientFormField"/> 

Và validator:

@Named 
@ApplicationScoped 
public class MobilePhoneNumberValidator implements Validator, Serializable 
{ 
    @Override 
    public void validate(FacesContext fc, UIComponent uic, Object o) throws ValidatorException 
    { 
     // This will appear in the log if/when this method is called. 
     System.out.println("mobilePhoneNumberValidator.validate()"); 

     UIInput in = (UIInput) uic; 
     String value = in.getSubmittedValue() != null ? in.getSubmittedValue().toString().replace("-", "").replace(" ", "") : ""; 

     if (!value.matches("04\\d{8}")) 
     { 
      throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Please enter a valid mobile phone number.", null)); 
     } 
    } 
} 

Khi tôi bấm vào nút lệnh trong biểu mẫu, tôi nhận được các hành vi sau đây :

  • Khi trường này trống, thông báo "Không hợp lệ (chuyển đổi)".
  • Khi trường có mục nhập hợp lệ, thông báo là "Không hợp lệ (trình xác thực)".
  • Khi trường có mục nhập không hợp lệ, thông báo là "Không hợp lệ (trình chuyển đổi)".

Trong cả ba trường hợp, MobilePhoneNumberConverter.getAsObject() được gọi. MobilePhoneNumberValidator.validate()không bao giờ được gọi là. Và khi trường này trống, nó bỏ qua thuộc tính required="true" và tiến thẳng đến chuyển đổi.

Tôi đã có thể nghĩ các hành vi thích hợp sẽ là:

  • Khi lĩnh vực này là trống, thông điệp cần được "yêu cầu".
  • Khi trường có mục nhập hợp lệ, hoàn toàn không có thông báo nào.
  • Khi trường có mục nhập không hợp lệ, thông báo phải là "Không hợp lệ (trình xác thực)".
  • Nếu, một số cơ hội, xác thực được chuyển bởi chuyển đổi không, thông báo phải là "Không hợp lệ (chuyển đổi)".

Lưu ý: Đậu ủng hộ được yêu cầu, nên không có doanh nghiệp AJAX ưa thích nào đang diễn ra ở đây.

Cập nhật:

nó có thể có một cái gì đó để làm với javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL được thiết lập để true?

Trả lời

12

Chuyển đổi xảy ra trước khi xác thực. Người chuyển đổi cũng sẽ được gọi khi giá trị là null hoặc trống. Nếu bạn muốn ủy quyền giá trị null cho trình xác thực, thì bạn cần phải thiết kế bộ chuyển đổi của mình là nó chỉ trả lại null khi giá trị được cung cấp là null hoặc trống.

@Override 
public Object getAsObject(FacesContext context, UIComponent component, String value) { 
    if (value == null || value.trim().isEmpty()) { 
     return null; 
    } 

    // ... 
} 

Không liên quan cho vấn đề cụ thể, validator của bạn có một lỗ hổng. Bạn không nên trích xuất giá trị đã gửi từ thành phần. Đó là không phải giá trị giống như được trả về bởi công cụ chuyển đổi. Giá trị được gửi và chuyển đổi phải có sẵn dưới dạng đối số phương thức thứ 3.

@Override 
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { 
    if (value == null) { 
     return; // This should normally not be hit when required="true" is set. 
    } 

    String phoneNumber = (String) value; // You need to cast it to the same type as returned by Converter, if any. 

    if (!phoneNumber.matches("04\\d{8}")) { 
     throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Please enter a valid mobile phone number.", null)); 
    } 
} 
+0

Cảm ơn @BalusC. Mặc dù đến sau này và về cơ bản tóm tắt cuộc trò chuyện dài gắn liền với câu trả lời của βнɛƨн Ǥʋяʋиɢ (mà tôi đã chấp nhận), tôi muốn câu trả lời hữu ích nhất là câu trả lời được chấp nhận vì lợi ích của những người khác gặp phải câu hỏi này. Xin lỗi βнɛƨн Ǥʋяʋиɢ :( –

+0

Bạn được hoan nghênh, xin lưu ý rằng tôi đã cập nhật câu trả lời sau khi xem xét kỹ hơn việc triển khai trình duyệt tính hợp lệ của bạn về cơ bản là sai. – BalusC

+0

@BalusC: Cảm ơn bạn đã sửa lỗi. Câu trả lời của tôi –

3

Sau khi đọc nhận xét của BalusC, tôi đang cập nhật bài đăng này một lần nữa.

Tôi đã tạo một ứng dụng trình diễn nhỏ và xem các giai đoạn và thời điểm chuyển đổi và xác thực xảy ra.

Xem:

<h:form> 
    <h:inputText value="#{demoBean.field}"> 
     <f:converter converterId="demoConverter"/> 
     <f:validator validatorId="demoValidator"/> 
    </h:inputText> 
    <h:commandButton value="Submit" action="#{demoBean.demoAxn()}"/> 
</h:form> 

Managed đậu:

@ManagedBean 
@SessionScoped 
public class DemoBean implements Serializable { 
    private String field; 

    public DemoBean() { 
     System.out.println(Thread.currentThread().getStackTrace()[1]); 
    } 

    public String getField() { 
     System.out.println(Thread.currentThread().getStackTrace()[1]); 
     return field; 
    } 

    public void setField(String field) { 
     System.out.println(Thread.currentThread().getStackTrace()[1]); 
     this.field = field; 
    } 

    public String demoAxn() { 
     System.out.println(Thread.currentThread().getStackTrace()[1]); 
     return null; 
    } 
} 

Chuyển đổi:

@FacesConverter(value="demoConverter") 
public class DemoConverter implements Converter { 

    @Override 
    public Object getAsObject(FacesContext context, UIComponent component, String value) { 
     System.out.println(Thread.currentThread().getStackTrace()[1]);    
     return value; 
    } 

    @Override 
    public String getAsString(FacesContext context, UIComponent component, Object value) { 
     System.out.println(Thread.currentThread().getStackTrace()[1]); 
     return (String) value; 
    }  
} 

Validator:

@FacesValidator(value="demoValidator") 
public class DemoValidator implements Validator { 

    @Override 
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { 
     System.out.println(Thread.currentThread().getStackTrace()[1]); 
    } 

} 

Giai đoạn nghe:

public class DemoPhaseListener implements PhaseListener { 
    @Override 
    public void afterPhase(PhaseEvent event) { 
     System.out.println(Thread.currentThread().getStackTrace()[1]); 
     System.out.println("PhaseId: " + event.getPhaseId() + " ===============================\n\n");   
    } 

    @Override 
    public void beforePhase(PhaseEvent event) { 
     System.out.println("\n\nPhaseId: " + event.getPhaseId() + " ==============================="); 
     System.out.println(Thread.currentThread().getStackTrace()[1]);   
    } 

    @Override 
    public PhaseId getPhaseId() { 
     return PhaseId.ANY_PHASE; 
    }  
} 

đăng ký giai đoạn nghe:

<lifecycle> 
    <phase-listener>pkg.DemoPhaseListener</phase-listener> 
</lifecycle> 

Với thiết lập rằng khi "Gửi" nút được nhấn vào, đầu ra là:

 
INFO: PhaseId: RESTORE_VIEW 1 =============================== 
INFO: pkg.DemoPhaseListener.beforePhase(DemoPhaseListener.java:17) 
INFO: pkg.DemoPhaseListener.afterPhase(DemoPhaseListener.java:10) 
INFO: PhaseId: RESTORE_VIEW 1 =============================== 

INFO: PhaseId: APPLY_REQUEST_VALUES 2 =============================== 
INFO: pkg.DemoPhaseListener.beforePhase(DemoPhaseListener.java:17) 
INFO: pkg.DemoPhaseListener.afterPhase(DemoPhaseListener.java:10) 
INFO: PhaseId: APPLY_REQUEST_VALUES 2 =============================== 

INFO: PhaseId: PROCESS_VALIDATIONS 3 =============================== 
INFO: pkg.DemoPhaseListener.beforePhase(DemoPhaseListener.java:17) 
INFO: pkg.DemoConverter.getAsObject(DemoConverter.java:13) 
INFO: pkg.DemoValidator.validate(DemoValidator.java:14) 
INFO: pkg.DemoBean.getField(DemoBean.java:17) 
INFO: pkg.DemoPhaseListener.afterPhase(DemoPhaseListener.java:10) 
INFO: PhaseId: PROCESS_VALIDATIONS 3 =============================== 

INFO: PhaseId: UPDATE_MODEL_VALUES 4 =============================== 
INFO: pkg.DemoPhaseListener.beforePhase(DemoPhaseListener.java:17) 
INFO: pkg.DemoBean.setField(DemoBean.java:22) 
INFO: pkg.DemoPhaseListener.afterPhase(DemoPhaseListener.java:10) 
INFO: PhaseId: UPDATE_MODEL_VALUES 4 =============================== 

INFO: PhaseId: INVOKE_APPLICATION 5 =============================== 
INFO: pkg.DemoPhaseListener.beforePhase(DemoPhaseListener.java:17) 
INFO: pkg.DemoBean.demoAxn(DemoBean.java:27) 
INFO: pkg.DemoPhaseListener.afterPhase(DemoPhaseListener.java:10) 
INFO: PhaseId: INVOKE_APPLICATION 5 =============================== 

INFO: PhaseId: RENDER_RESPONSE 6 =============================== 
INFO: pkg.DemoPhaseListener.beforePhase(DemoPhaseListener.java:17) 
INFO: pkg.DemoBean.getField(DemoBean.java:17) 
INFO: pkg.DemoConverter.getAsString(DemoConverter.java:20) 
INFO: pkg.DemoPhaseListener.afterPhase(DemoPhaseListener.java:10) 
INFO: PhaseId: RENDER_RESPONSE 6 =============================== 

Nhưng khi thực hiện thay đổi để ném NPE vào bộ chuyển đổi như sau:

@Override 
public Object getAsObject(FacesContext context, UIComponent component, String value) { 
    System.out.println(Thread.currentThread().getStackTrace()[1]);    
    throw new NullPointerException(); 
} 

đầu ra là:

 
INFO: PhaseId: RESTORE_VIEW 1 =============================== 
INFO: pkg.DemoPhaseListener.beforePhase(DemoPhaseListener.java:17) 
INFO: pkg.DemoPhaseListener.afterPhase(DemoPhaseListener.java:10) 
INFO: PhaseId: RESTORE_VIEW 1 =============================== 

INFO: PhaseId: APPLY_REQUEST_VALUES 2 =============================== 
INFO: pkg.DemoPhaseListener.beforePhase(DemoPhaseListener.java:17) 
INFO: pkg.DemoPhaseListener.afterPhase(DemoPhaseListener.java:10) 
INFO: PhaseId: APPLY_REQUEST_VALUES 2 =============================== 

INFO: PhaseId: PROCESS_VALIDATIONS 3 =============================== 
INFO: pkg.DemoPhaseListener.beforePhase(DemoPhaseListener.java:17) 
INFO: pkg.DemoConverter.getAsObject(DemoConverter.java:13) 
INFO: pkg.DemoPhaseListener.afterPhase(DemoPhaseListener.java:10) 
INFO: PhaseId: PROCESS_VALIDATIONS 3 =============================== 

INFO: pkg.DemoBean.getField(DemoBean.java:17) 

Nhưng stacktrace được hiển thị trên xem kết quả.

+0

Tôi không biết điều gì đang xảy ra ở đây ... Tôi đã thay đổi trình biến đổi và trình xác thực thành chú thích theo cách JSF 2.0. Đã có một thời gian không lâu trước đây khi điều này hoàn toàn không có sự khác biệt. Có lẽ GlassFish 3.1.1 đang vặn vẹo với tôi. Dù sao, với chú thích "đúng", thuộc tính 'required' vẫn không hoạt động, thay vào đó chuyển thẳng sang chuyển đổi. Trong thực tế, hoàn toàn không có kịch bản nào trong đó xác thực xảy ra. Tôi có nên thực hiện điều này để có nghĩa là các trình chuyển đổi gây ra xác thực bị bỏ qua không? –

+0

"Tôi có nên thực hiện điều này để có nghĩa là các trình chuyển đổi gây ra xác thực bị bỏ qua không?" Không. Họ làm những thứ khác nhau không liên quan, và chúng ta sẽ có thể chạy chúng với nhau. Nhưng, trong trường hợp thất bại, jsf dừng xử lý yêu cầu và bỏ qua các pha khác và nhảy để trả lời. ' –

+0

"Không. Họ làm những thứ khác nhau không liên quan, và chúng ta sẽ có thể chạy chúng với nhau." Tôi thấy nó bằng chính đôi mắt của mình - họ không ** làm việc cùng nhau. "Nhưng, trong trường hợp thất bại, jsf dừng xử lý yêu cầu và bỏ qua các pha khác và nhảy để trả lời." Tuy nhiên, điều này có liên quan như thế nào?Việc xác nhận và chuyển đổi xảy ra trong cùng một pha và jsf sẽ ít nhất chạy giai đoạn này để hoàn thành (để xác nhận * tất cả * các giá trị đã gửi và do đó hiển thị * tất cả * các lỗi xác thực/chuyển đổi) trước khi bỏ qua các giai đoạn còn lại. –

Các vấn đề liên quan