2012-05-10 2 views
3

У меня есть этот f:viewParam, что я пытаюсь связать валидацию и преобразовать userId в Player, и я получил неожиданных результатов.е: viewParam с конвертером исключением ViewScoped, когда Invoke второго запроса Аякса

<f:metadata> 
    <f:viewParam name="userId" value="#{myBean.selectedPlayer}" converter="pConverter" 
     converterMessage="Bad Request. Unknown User" required="true" 
     requiredMessage="Bad Request. Please use a link from within the system" /> 

</f:metadata> 
<h:body> 
    <p:messages id="msgs"/>   
    <h:form> 
     <ul> 
      <li><a href="index2.xhtml?userId=1">Harry</a></li> 
      <li><a href="index2.xhtml?userId=2">Tom</a></li> 
      <li><a href="index2.xhtml?userId=3">Peter</a></li> 
     </ul>    
    </h:form> 
    <h:form> 
     <h:panelGrid columns="2" rendered="#{not empty myBean.selectedPlayer}"> 

      <h:outputText value="Id: #{myBean.selectedPlayer.id}"/> 

      <h:outputText value="Name: #{myBean.selectedPlayer.name}"/> 

     </h:panelGrid> 
    </h:form> 
    <h:form id="testForm"> 
     <h:inputText value="#{myBean.text}"/> 
     <p:commandButton value="Switch" update=":msgs testForm"/> 
     <h:outputText value="#{myBean.text}" rendered="#{not empty myBean.text}"/> 
    </h:form>  
</h:body> 

Мой конвертер выглядеть как этот

@FacesConverter(value="pConverter") 
public class PConverter implements Converter { 
private static final List<Player> playerList; 
static{ 
    playerList = new ArrayList<Player>();   
    playerList.add(new Player(1, "Harry")); 
    playerList.add(new Player(2, "Tom")); 
    playerList.add(new Player(3, "Peter")); 
} 

@Override 
public Object getAsObject(FacesContext fc, UIComponent uic, String value) { 
    if(value == null || !value.matches("\\d+")){ 
     return null; 
    } 
    long id = Long.parseLong(value); 
    for(Player p : playerList){ 
     if(p.getId() == id){ 
      return p; 
     } 
    } 
    throw new ConverterException(new FacesMessage("Unknown userId: " + value)); 

} 

@Override 
public String getAsString(FacesContext fc, UIComponent uic, Object value) { 
    if(!(value instanceof Player) || value == null){ 
     return null; 
    } 
    return String.valueOf(((Player)value).getId()); 
} 
} 

Как я нажимаю три ссылки (Гарри, Том, Питер), конвертора работы большой. Он конвертирует идентификатор и связывает player обратно с моим управляемым компонентом. Затем я напечатаю что-то в текстовом поле, а затем нажмите Switch, когда он работает нормально, то, что я набрал, появляется рядом с кнопкой, но затем я меняю то, что я набираю, и снова нажмите Switch, затем появится сообщение об ошибке Bad Request. Please use a link from within the system, которое сообщение об ошибке для required для f:viewParam. Если я возьму f: viewParam, тогда все будет работать нормально. Удивительно, но если я переключусь с f: viewParam на o: viewParam (OmniFaces), тогда он отлично работает.

ответ

4

Это потому, что <f:viewParam> работает на каждом HTTP-запросе, а также на postbacks. Он работает в вашем случае отлично для простых ссылок GET, потому что вы передаете именно этот параметр в ссылках. В вашем случае это не подходит для форм POST, потому что вы не передаете этот параметр в кнопке. Таким образом, он становится null в карте параметров запроса, а валидатор required выполняет и, следовательно, эту ошибку проверки.

Чтобы сохранить <f:viewParam required="true"> счастливыми формами POST, вам в основном нужно сохранить начальный параметр запроса на <f:param> в командных кнопках/ссылках.

<p:commandButton value="Switch" update=":msgs testForm"> 
    <f:param name="userId" value="#{param.userId}" /> 
</p:commandButton> 

В OmniFaces <o:viewParam>, который предназначен для использования в сочетании с видом на области видимости бобов, имеет дополнительную проверку в isRequired() геттере (source code here):

@Override 
public boolean isRequired() { 
    // The request parameter get lost on postbacks, however it's already present in the view scoped bean. 
    // So we can safely skip the required validation on postbacks. 
    return !FacesContext.getCurrentInstance().isPostback() && super.isRequired(); 
} 

Таким образом, это пропускает required валидатора при каждой обратной передаче (и, кроме того, она также пропускает установку значения модели при каждой обратной передаче из-за своей безгражданности). Вот почему вы не видите ошибку проверки, и у вас все еще есть правильное значение модели (которое не сбрасывается при каждой обратной передаче).

+0

спасибо. Omnifaces довольно удивительный, BalusC. У меня есть один вопрос о 'o: viewParam', в вашем блоге вы сказали, что всезначения будут избегать обращения к' Конвертеру' каждый раз при вызове ajax-запроса, однако кажется, что он всегда попадает внутрь метода 'getAsString()'. Поэтому я задаюсь вопросом, правильно ли это поведение. Я знаю, что 'getAsObject' - это то, что устанавливает значение модели, поэтому не вызывать' getAsObject' - отличное улучшение. И я благодарю вас за это. –

+1

'getAsString()' будет вызываться, когда объект должен быть преобразован в строку (для представления в сгенерированном HTML). Но это должно быть довольно дешевое задание, поскольку оно должно быть строковым значением одного из его свойств. У вас есть объект уже в ваших руках, поэтому нет дорогостоящей работы БД. – BalusC

+0

Большое спасибо. –

Смежные вопросы