2010-10-14 14 views
11


Tôi không hiểu hành vi của JSF2 trong quá trình valdation. Hy vọng ai đó có thể giúp tôi.JSF 2 - Xác thực Bean: xác nhận không thành công -> giá trị rỗng được thay thế bằng giá trị hợp lệ cuối cùng từ bean được quản lý

Tôi có một hình thức mà các lĩnh vực được xác nhận sau (ajax) nộp - ok
Nếu xác nhận thất bại trong một thông báo lỗi được hiển thị - ok

Ví dụ của tôi khi tôi bước vào một ngày sinh hợp lệ và trường tên trống rỗng cho tên được hiển thị sau khi gửi.
Bây giờ khi tôi nhập vào một giá trị tên và xóa các đầu vào từ sinh nhật lĩnh vực một errormessage được hiển thị cho sinh nhật (đó là ok) nhưng bây giờ sinh nhật 'hợp lệ' cũ cũng đứng trong lĩnh vực đầu vào! ?!

Làm cách nào để tránh hành vi này? Khi tôi gửi một cánh đồng trống Tôi muốn nhìn thấy một errormessage và một cánh đồng trống ...

Dưới đây là mẫu mã của tôi:

tôi sử dụng một ManagedBean (TestBean) có chứa một EntityBean (Liên). Số Liên hệ chứa các xác thực cho mỗi lần hủy.

public class Contact implements Serializable { 
    @NotNull 
    @Temporal(TemporalType.DATE) 
    private Date birthday; 

    @NotNull 
    @Size(min=3, max=15) 
    private String name; 

    //... 
} 

My ManagedBean:

@ManagedBean 
@ViewScoped 
public class TestBean implements Serializable { 
    private Contact contact; 

    @PostConstruct 
    void init() { 
     System.out.println("init..."); 
     contact = new Contact(); 
    } 

    public void newContact(ActionEvent ae) { 
     System.out.println("newContact..."); 
     contact = new Contact(); 
    } 

    public void save() { 
     System.out.println("save..."); 
     //TODO do something with contact... 
    } 

    public Contact getContact() { return contact; } 

    public void setContact(Contact contact) {this.contact = contact;} 
} 

Một ở đây trang JSF của tôi:

<html xmlns="http://www.w3.org/1999/xhtml" 
     xmlns:h="http://java.sun.com/jsf/html" 
     xmlns:f="http://java.sun.com/jsf/core" >  
<h:body> 
    <h:form>  
     <h:panelGrid columns="3"> 

     <h:outputText value="Birthday: " /> 
     <h:inputText id="birthday" value="#{testBean.contact.birthday}"> 
      <f:convertDateTime/> 
     </h:inputText> 
     <h:message for="birthday" /> 

     <h:outputText value="Name: " /> 
     <h:inputText id="name" value="#{testBean.contact.name}"/> 
     <h:message for="name" /> 

     </h:panelGrid> 

     <h:commandButton value="submit" action="#{testBean.save}"> 
      <f:ajax execute="@form" render="@form"/> 
     </h:commandButton> 

     <h:commandButton value="newContact" actionListener="#{testBean.newContact}" 
         immediate="true"> 
      <f:ajax render="@form"/> 
     </h:commandButton> 

    </h:form> 
</h:body> 
</html> 

cuối cùng một đoạn từ web.xml

<context-param> 
    <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name> 
    <param-value>true</param-value> 
</context-param> 

<context-param> 
    <param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name> 
    <param-value>true</param-value> 
</context-param> 

Cảm ơn một số mẹo

Trả lời

8

vấn đề cụ thể của bạn là do

<context-param> 
    <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name> 
    <param-value>true</param-value> 
</context-param> 

và một lỗi (ít nhất, một giám sát) trong HtmlBasicRenderer#getCurrentValue() của Mojarra:

if (component instanceof UIInput) { 
    Object submittedValue = ((UIInput) component).getSubmittedValue(); 
    if (submittedValue != null) { 
     // value may not be a String... 
     return submittedValue.toString(); 
    } 
} 

String currentValue = null; 
Object currentObj = getValue(component); 
if (currentObj != null) { 
    currentValue = getFormattedValue(context, component, currentObj); 
} 
return currentValue; 

Thông thường, giá trị đã gửi được đặt thành null khi thành phần UIInput được chuyển đổi và xác thực thành công. Khi JSF sắp tái hiển thị giá trị, trước tiên nó sẽ kiểm tra xem giá trị đã gửi có phải là null trước khi tiếp tục hiển thị lại giá trị mô hình hay không. Tuy nhiên, với tham số ngữ cảnh này, nó là null thay vì một chuỗi rỗng khi nó không hợp lệ và do đó nó sẽ luôn hiển thị lại giá trị mô hình ban đầu khi bạn loại bỏ giá trị ban đầu của trường bắt buộc.

Để kiểm tra, hãy đặt giá trị tham số ngữ cảnh đó thành false hoặc xóa hoàn toàn. Bạn sẽ thấy rằng nó hoạt động như dự định. Tuy nhiên, nó sẽ mang lại bất lợi là các giá trị mô hình của bạn sẽ bị lộn xộn với các chuỗi trống trên các trường trống nhưng không bắt buộc và bạn sẽ mất lợi thế khi sử dụng chú thích @NotNull của xác thực bean JSR 303.

Để sửa lỗi này, bạn đã thay đổi phần đầu của HtmlBasicRenderer#getCurrentValue() như sau:

if (component instanceof UIInput && !((UIInput) component).isValid()) { 
    Object submittedValue = ((UIInput) component).getSubmittedValue(); 
    if (submittedValue != null) { 
     // value may not be a String... 
     return submittedValue.toString(); 
    } else { 
     return null; 
    } 
} 

Tôi đã báo cáo nó để cá móm kẻ như issue 2262.

+0

Tôi đã nhận thấy hành vi tương tự khi đầu vào bị ràng buộc vào thuộc tính không phải Chuỗi với trình chuyển đổi, có thể do cùng nguyên nhân gốc. Khi bạn đặt vào một chuỗi rỗng và xác thực không thành công do một trường khác, chuỗi rỗng (hợp lệ) của bạn bị ghi đè bằng giá trị từ bean. Đã được báo cáo là http://java.net/jira/browse/JAVASERVERFACES-838 – wrschneider

+2

@BalusC: Cảm ơn bạn đã giải thích chi tiết! Giải pháp của bạn/giải thích ở đây thường làm cho ngày của tôi ;-) –

+0

@ BalusC Điều đó có nghĩa là ông biên dịch một phiên bản tùy chỉnh của JSF? Tôi đã gặp phải vấn đề tương tự và hy vọng rằng đây không phải là giải pháp duy nhất. – MikeR

0

Tôi nghĩ rằng trong quá trình sử dụng bình thường, mọi người sẽ không nhập ngày hợp lệ, gửi và sau đó xóa ngày trước khi gửi lại. Tôi nhận thấy rằng bạn đã tìm thấy điều này trong khi thử nghiệm, nhưng có lẽ mọi người chỉ đang cố gắng điền vào biểu mẫu thành công và không xóa nội dung họ đã nhập, trong trường hợp đó có lẽ việc giữ giá trị hợp lệ cuối cùng là chức năng tốt nhất.

Nếu bạn cứ khăng khăng ... Nó có vẻ như phương pháp setter "sinh nhật" không bao giờ được gọi vì giá trị không hợp lệ, và sau đó khi trang được hiển thị lại giá trị hiện tại của "sinh nhật" được hiển thị (giá trị hiện tại là giá trị hợp lệ đã được lưu trước đó). Có lẽ bạn có thể viết trình xác nhận tùy chỉnh đặt giá trị và THEN xác nhận giá trị, nhưng điều này sẽ không thực sự có ý nghĩa nhiều. Bạn sẽ vẫn phải xác thực giá trị đầu tiên cho các trường hợp khi người dùng nhập chuỗi văn bản như "ngày hôm qua" thay vì ngày hợp lệ và sau đó bạn phải đặt ngày thành thứ dựa trên giá trị không hợp lệ đó, và sau đó bạn sẽ có để thêm thông điệp vào FacesContext. Vì vậy, mã sẽ phải làm một cái gì đó như sau.

1) xác thực giá trị ngày
2) nếu không hợp lệ, sau đó đặt trường thành giá trị nào đó có ý nghĩa và thêm thông báo lỗi vào FacesContext.
3) nếu nó hợp lệ thì hãy sử dụng.

Đó của không-thể, nhưng kỳ lạ bởi vì bạn đang thay đổi giá trị của lĩnh vực này mặc dù được thông qua vào giá trị không hợp lệ ...

+0

Xin chào Aaron, cảm ơn bạn đã trả lời! Tôi mã ví dụ của tôi có một trường hợp khác cho thấy cùng một vấn đề trong khi cố gắng thay thế mô hình phụ trợ (nút newContact). Đối với tôi, nó trông giống như một vấn đề thế giới thực - và không giống như một trường hợp thử nghiệm học tập. Tôi đã tìm thấy giải pháp (không đẹp, nhưng nó hoạt động ...).Đối với các giải pháp tôi đã chỉnh sửa mã mẫu một chút. Xem câu trả lời của riêng tôi –

0

Aaron đã descripes hành vi.

Sự cố tôi đã mô tả cũng tồn tại bằng cách nhấp vào nút 'newContact'. Nếu lần gửi đầu tiên không hợp lệ (ngày sinh đã được nhập, trường tên sẽ trống) thông báo lỗi sẽ hiển thị. được.

Sau đó nút 'newContact' không làm mới (xóa) chế độ xem. Mặc dù mô hình đã được định vị lại (contact = new Contact()).

Tôi tìm thấy một số Tipps đây: http://wiki.apache.org/myfaces/ClearInputComponents

Đây là giải pháp của tôi:

public void newContact(ActionEvent ae) { 
    contact = new Contact(); 
    contact.setBirthday(new Date()); //for testing only 

    resetForm(ae.getComponent()); 
} 

private void resetForm(UIComponent uiComponent) { 
    //get form component 
    UIComponent parentComponent = uiComponent.getParent(); 
    if (uiComponent instanceof UIForm) 
     resetFields(uiComponent); 
    else if (parentComponent != null) 
     resetForm(parentComponent); 
    else 
     resetFields(uiComponent); 

} 

private void resetFields(UIComponent baseComponent) { 
    for (UIComponent c : baseComponent.getChildren()) { 
     if (c.getChildCount() > 0) 
      resetFields(c); 

     if (c instanceof UIInput) 
      ((UIInput) c).resetValue(); 
    } 
} 
0

Đã xảy ra sự cố tương tự khi giá trị được tải từ bean sao lưu sẽ được đặt lại khi trường bị xóa và thành phần khác không xác thực được. Tôi phải thêm một chút vào mã của BalusC để làm cho nó hoạt động.

protected String getCurrentValue(FacesContext context, 
            UIComponent component) { 

     if (component instanceof UIInput && !((UIInput) component).isValid()) { 
      Object submittedValue = ((UIInput) component).getSubmittedValue(); 
      if (submittedValue != null) { 
       // value may not be a String... 
       return submittedValue.toString(); 
      } else { 
       return null; 
      } 
     } 


     String currentValue = null; 
     Object currentObj; 

     if (component instanceof UIInput && ((UIInput)component).isLocalValueSet()) 
     { 
      currentObj = ((UIInput)component).getLocalValue(); 
     } 
     else { 
      currentObj = getValue(component); 
     } 

     if (currentObj != null) { 
      currentValue = getFormattedValue(context, component, currentObj); 
     } 
     return currentValue; 


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