私はこのようなページをたくさん書くプロジェクトにいるので、最も効率的な (書く) コーディング パターンを使用したいと考えています。
背景: 以前は CODI の @ViewAccessScoped を使用してリクエスト間で状態を保持していましたが、最近ではフラッシュ スコープ オブジェクトを使用して状態を保存するようになりました。私は CDI を使用しており、うまく連携できないため、JSF @ViewScoped を使用できません。したがって、@RequestScoped バッキング Bean のみでこれを実行できるかどうかを確認したいと思います。
このページは次のように設計されています (p 名前空間は Primefaces です)。
<f:metadata>
<f:viewParam name="ID" value="#{backing.id}" />
</f:metadata>
....
<h1>Edit Object Page</h1>
<h:form id="formObj" rendered="#{backing.accessOK}">
<p:panelGrid columns="2">
<h:outputLabel value="Field #1:"/>
<p:inputText value="#{backing.record.field1}" />
(more input fields)
<h:outputLabel value="Action:" />
<h:panelGroup>
<p:commandButton value="Save"
action="#{backing.save}"
/>
<p:commandButton value="Cancel" action="backing.cancel" />
</h:panelGroup>
</p:panelGrid>
<p:messages showDetail="true" showSummary="true" />
</h:form>
ページが要求された場合、メソッドaccessOK()にはh:formがレンダリングされないようにする機能があります。代わりに、p:messagesは、 accessOK()メソッドが設定するFacesMessage (s)とともに表示されます。
Beanバッキングのパターンは次のようになります。
@Named
@RequestScoped
public class Backing {
private long id;
private SomeJPAEntity record;
private Boolean accessOK;
public long getId() { return id; }
public void setId(long value) { id = value; }
public boolean accessOK() {
if (accessOK != null) return accessOK;
if (getRecord() == null) {
// add a FacesMessage that explains the record
// does not exist
return accessOK = false; // note single =
}
// do any other access checks, such as write permissions
return accessOK = true;
}
public SomeJPAEntity getRecord() {
if (record != null) return record;
if (getId() > 0) record = // get the record from DB
else record = new SomeJPAEntity();
return record;
}
public String execute() {
if (!accessOK()) return null; // bad edit
// do other integrity checks here. If fail, set FacesMessages
// and return null;
if (getId() > 0) // merge the record back into the data base
else // persist the record
}
}
このモデルの問題点は次のとおりです。[保存] ボタンをクリックすると、Backingの新しいインスタンスが作成され、setID ()セッターが呼び出される前にgetRecord()ゲッターが多数呼び出されます。したがって、getRecord()のロジックは、呼び出されたときにidプロパティが有効であることに依存できないため、壊れます。
これが@ViewAccessScoped (またはViewScoped ) バッキング Bean であった場合、フォームが commandButton で処理されるときに、id プロパティと record プロパティの両方が既に設定されています。または、これらのプロパティをフラッシュ ストレージに保存することもできますが、それには回避したい独自の問題があります。
このプログラミング モデルを仕様内で動作させる方法はありますか?
アップデート:
経験的に、フラッシュまたはビュースコープのバリアントに頼らずにこれを機能させる回避策があります。上記のように、フォームが処理されるとき、setId()への最初の呼び出しの前にgetRecord() への呼び出しがいくつかあります。そして最後にsave()メソッドが呼び出されます。
私がしていることは、次のようにsetId()を変更することです:
public void setId(long value) {
id = value;
record = null;
}
これにより、getRecord()がプロパティrecordを再計算 (フェッチ/ビルド) し、その後の呼び出しが機能します。特に、save()メソッドは、レコードエンティティの内容を含めて適切に初期化されたオブジェクトと共に入力されます。getRecord()への以前のすべての呼び出しが何のためにあったのかわかりません。
この時点で、信頼できるかどうかもわかりませんが、 getId()が設定された後、レコードエンティティに書き込まれたすべての値がUIinputコンポーネントから転送されるかどうかです。もしそうなら、私はこのパターンを使用することができます。これは仕様によって制御されていますか、それとも運だけで機能していますか?
コメントや提案はありますか?