p:commandButton を使用した jsf アクションで奇妙な動作が発生しています。対応するページは、いくつかの作成および更新タスクを処理します。そのため、空白のフォームでページにアクセスしたり、フォームに読み込まれた保存済みのデータを引き続き使用したりできます。期待どおりに機能しないボタンは、保存アクションをトリガーしてフォーム情報を保持します。
ここに私の問題があります。すでに保存されているデータを続行して「保存」をクリックすると、すべて正常に動作します。アクションが呼び出され、データが永続化されるか、検証エラーが表示されます。MyPhaseListener.afterPhase() にログインして取得したログ ステートメントを次に示します。データが保持されていることを実際に確認するログ行をいくつかカットしました。
10:43:53,959 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:43:53,960 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) AFTER PHASE RESTORE_VIEW 1
10:43:53,960 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) Method expression of the action being invoked: #{tollRegistrationBean.saveRegistration('CUSTOMER_DATA')}
10:43:53,960 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:43:53,961 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:43:53,961 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) AFTER PHASE APPLY_REQUEST_VALUES 2
10:43:53,962 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) Method expression of the action being invoked: #{tollRegistrationBean.saveRegistration('CUSTOMER_DATA')}
10:43:53,962 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:43:53,963 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:43:53,964 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) AFTER PHASE PROCESS_VALIDATIONS 3
10:43:53,964 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) Method expression of the action being invoked: #{tollRegistrationBean.saveRegistration('CUSTOMER_DATA')}
10:43:53,964 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:43:53,965 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:43:53,965 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) AFTER PHASE UPDATE_MODEL_VALUES 4
10:43:53,965 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) Method expression of the action being invoked: #{tollRegistrationBean.saveRegistration('CUSTOMER_DATA')}
10:43:53,966 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:43:54,041 INFO [com.egrima.cockpit.beans.toll.TollRegistrationBean] (http-localhost/127.0.0.1:8080-1) WEB: TOLL_REGISTRATION_SAVE "registrationId:210001-2783,registrationStatus:OPEN"
10:43:54,081 DEBUG [com.egrima.cockpit.beans.toll.TollRegistrationBean] (http-localhost/127.0.0.1:8080-1) Registration saved by user noreply@example.com and customer number 210001
10:43:54,081 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:43:54,082 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) AFTER PHASE INVOKE_APPLICATION 5
10:43:54,083 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) Method expression of the action being invoked: #{tollRegistrationBean.saveRegistration('CUSTOMER_DATA')}
10:43:54,083 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:43:54,121 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:43:54,121 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) AFTER PHASE RENDER_RESPONSE 6
10:43:54,121 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) Method expression of the action being invoked: #{tollRegistrationBean.saveRegistration('CUSTOMER_DATA')}
10:43:54,121 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
ここで奇妙な部分は、新しいデータの保存を行うときに、アクションが呼び出されないことです。したがって、目標は既存のデータを更新することではなく、新しいデータを挿入することですが、その違いは、JSF Bean よりも JPA レイヤーにとって興味深いものです。ライフサイクルは正常に処理されますが、呼び出されるアクションはありません。
10:51:10,813 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:51:10,813 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) AFTER PHASE RESTORE_VIEW 1
10:51:10,813 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:51:10,813 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:51:10,813 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) AFTER PHASE APPLY_REQUEST_VALUES 2
10:51:10,814 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:51:10,814 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:51:10,814 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) AFTER PHASE PROCESS_VALIDATIONS 3
10:51:10,814 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:51:10,814 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:51:10,814 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) AFTER PHASE UPDATE_MODEL_VALUES 4
10:51:10,814 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:51:10,814 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:51:10,815 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) AFTER PHASE INVOKE_APPLICATION 5
10:51:10,815 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:51:10,825 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
10:51:10,825 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) AFTER PHASE RENDER_RESPONSE 6
10:51:10,825 INFO [com.egrima.cockpit.server.LifeCycleListener] (http-localhost/127.0.0.1:8080-1) --------------------------------------------------------------------
アクションを呼び出すことを除けば、見た目は非常に似ています。そして、それが私が頭を悩ませることができないものです。まったく同じボタンをクリックして、まったく同じアクションを呼び出しています。
これが、h:form を含む完全な xhtml ファイルです。少し短くしました。ファイル全体には、より多くの入力フィールド (すべて同じパターンに従います) と、スタイリング目的でのみ重要ないくつかの追加タグが含まれています。
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:form id="tollCustomerForm">
<h:panelGrid columns="3" cellpadding="0" styleClass="width-100" columnClasses="width-50 valign-top, width-50 valign-top">
<h:panelGrid columns="2" columnClasses="width-30, width-70 space-right" rendered="#{tollRegistrationBean.registration.customerData.company.visible}">
<h:panelGroup>
<h:outputLabel for="inputCompany" value="#{msg.toll_registration_customerData_company}" />
<h:outputLabel value=" #{msg.gloabl_required_field_sign}" rendered="false" />
</h:panelGroup>
<h:inputText id="inputCompany" value="#{tollRegistrationBean.registration.customerData.company.value}"
styleClass="#{!component.valid ? 'errorInputText' : 'dkv-inputText'}" readonly="true" disabled="#{tollRegistrationBean.registrationSent}"
label="#{msg.toll_registration_accordion_tab_customer_data} - #{msg.toll_registration_customerData_company}" required="false" />
</h:panelGrid>
<h:panelGrid columns="2" columnClasses="width-30, width-70 space-right" rendered="#{tollRegistrationBean.registration.customerData.addressAddition.visible}">
<h:panelGroup>
<h:outputLabel for="inputCountry" value="#{msg.toll_registration_customerData_country}" />
<h:outputLabel value=" #{msg.gloabl_required_field_sign}" rendered="false" />
</h:panelGroup>
<h:inputText id="inputCountry" value="#{tollRegistrationBean.getCountryName(tollRegistrationBean.registration.customerData.country.value)}"
styleClass="#{!component.valid ? 'errorInputText' : 'dkv-inputText'}" readonly="true" disabled="#{tollRegistrationBean.registrationSent}"
label="#{msg.toll_registration_accordion_tab_customer_data} - #{msg.toll_registration_customerData_country}" required="false" />
</h:panelGrid>
<h:panelGrid columns="2" columnClasses="space-left width-30, width-70" rendered="#{customerBean.renderCustomernumbers}">
<h:panelGroup>
<h:outputLabel for="inputCustomerNumber" value="#{msg.toll_registration_customerData_customerNumber}" />
<h:outputLabel value=" #{msg.gloabl_required_field_sign}" rendered="false" />
</h:panelGroup>
<h:inputText id="inputCustomerNumber" value="#{customerBean.customernumber}"
styleClass="#{!component.valid ? 'errorInputText' : 'dkv-inputText'}" readonly="true" disabled="#{tollRegistrationBean.registrationSent}"
label="#{msg.toll_registration_accordion_tab_customer_data} - #{msg.toll_registration_customerData_customerNumber}" required="false" />
</h:panelGrid>
<h:panelGrid columns="2" columnClasses="space-left width-30, width-70" rendered="#{tollRegistrationBean.registration.customerData.email.visible}">
<h:panelGroup>
<h:outputLabel for="inputEmail" value="#{msg.toll_registration_customerData_email}" />
<h:outputLabel value=" #{msg.gloabl_required_field_sign}" rendered="false" />
</h:panelGroup>
<h:inputText id="inputEmail" value="#{tollRegistrationBean.registration.customerData.email.value}"
styleClass="#{!component.valid ? 'errorInputText' : 'dkv-inputText'}" readonly="true" disabled="#{tollRegistrationBean.registrationSent}"
label="#{msg.toll_registration_accordion_tab_customer_data} - #{msg.toll_registration_customerData_email}" required="false" />
</h:panelGrid>
</h:panelGrid>
<!-- ########## THE STRANGE SAVE BUTTON ########## -->
<p:commandButton value="#{msg.toll_registration_accordion_save_step_button}" id="saveRegBtn" update=":tollAccordion :tollSelectionForm:globalMessages :tollSelectionForm:registrationProgressBar"
action="#{tollRegistrationBean.saveRegistration('CUSTOMER_DATA')}" disabled="#{tollRegistrationBean.registrationSent}" styleClass="dkv-button" >
<p:resetInput target=":tollAccordion:tollCustomerForm" />
</p:commandButton>
<!-- ########## THE STRANGE SAVE BUTTON ########## -->
<!-- preValidation method only executed, if submit button is pressed (not called, if save-button is clicked) -->
<h:panelGroup rendered="#{param['tollAccordion:tollCustomerForm:saveAndNextStepRegBtn']!=null}">
<f:event listener="#{tollRegistrationBean.listenNextAccordionStep}" type="preValidate" />
<f:attribute name="currentAccordionStep" value="CUSTOMER_DATA" />
</h:panelGroup>
</h:form>
</ui:composition>
この ui:composition は、レイアウト情報を含む別の xhtml ファイルに含まれています。このレイアウト テンプレートはあまり見栄えがよくなく、ah:form が含まれていないため、ネストされたフォームはありません。
そして私の(短縮された)jsf Bean
@Component
@Scope("view")
public class TollRegistrationBean implements Serializable {
...
@PostConstruct
public void init() {
// get registrationId by param and load registration
RequestContext context = RequestContext.getCurrentInstance();
String registrationId = (String)context.getCallbackParams().get(TollRegistrationMainBean.CALLBACK_PARAM_SELECTED_REGISTRATION_ID);
if (registrationId != null && !registrationId.isEmpty()) {
registration = tollPersistingService.loadRegistrationAndCheckFields(registrationId);
}
if (registration != null) {
createAccordionOrder();
selectedTolls = registration.getTollTypes();
// update saved customer data, read from DB, with data from crm
tollCustomerBean.loadCustomerDataFromCRM(registration);
}
activeIndex = 0;
registrationSent = false;
}
public void saveRegistration(String currentAccordionStep) {
log.info("TollRegistrationBean.saveRegistration()");
try {
tollPersistingService.saveRegistration(registration, customerBean.getCustomernumber());
activeIndex = accordionOrder.indexOf(currentAccordionStep);
registration.getStepByStepName(StepName.valueOf(currentAccordionStep)).setCssAccordionIcon("");
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO, MessageUtils.getMessage("toll_registration_info_saved_successfully"), ""));
String userEmail = UserUtils.getCurrentUser().getEmailAddress();
log.database(AdvancedLoggerUtils.Actions.TOLL_REGISTRATION_SAVE.name(), registration.toDatabaseLogString(), userEmail,
AdvancedLoggerUtils.System.WEB.name());
log.debug("Registration saved by user " + userEmail + " and customer number " + customerBean.getCustomernumber());
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
JSF 2.2、Primefaces 5.2、および Spring 4.1.4.RELEASE を使用しています。
誰かが同じまたは同様の問題を経験しましたか? 助けやヒントがあれば本当に感謝しています。私はちょっとこれで立ち往生しています。
ありがとう、セバスチャン