質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.77%

【JavaEE 7】h:commandButtonのaction属性で指定したCDIビーンのメソッドが実行されない

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 949

akiratto

score 7

前提・実現したいこと

h:commandButtonのaction属性で指定した、CDIビーン(@RequestScoped)のメソッドが実行されない。@ViewScopedにスコープを変更すると実行できました。
できるだけ短いスコープで動作させていので@RequestScopedで実行させる方法があれば知りたいです。

発生している問題・エラーメッセージ

以下のような手順で社員情報を登録・編集するアプリを作成していたのですが、
一覧画面から詳細画面に遷移後、「編集」ボタンを押すと、項目がすべて空欄となり、「編集」ボタン(h:commandButton)のaction属性に指定していたbeginEdit()メソッドが実行されませんでした。

1.社員一覧画面を開く
社員一覧画面

2."0001"のリンクをクリックして詳細画面へ遷移する。
社員詳細画面(遷移直後)

3.「編集」ボタンをクリックする
社員詳細画面(編集ボタン押下後)

「編集」ボタンをクリック後、何故かCDIビーンのbeginEdit()メソッドは実行されない状態です。

beginEdit()メソッドが実行されていれば、下記のようにURLにクエリ文字列が付加されて、項目が入力可能になる想定でした。
編集ボタン押下後(成功)

該当のソースコード

【社員一覧画面】employeeList.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>社員一覧</title>
    </h:head>
    <h:body>
        <h:form id="f">
            <h:dataTable value="#{employeeList.extract()}" var="emp" >
                <h:column><f:facet name="header"><h:outputText value="社員ID" /></f:facet><h:commandLink action="#{employeeList.gotoDetail(emp.employee_id, 'Read')}">#{emp.employee_id}</h:commandLink></h:column>
                <h:column><f:facet name="header"><h:outputText value="名前" /></f:facet>#{emp.name}</h:column>
                <h:column><f:facet name="header"><h:outputText value="性別" /></f:facet>#{emp.gender}</h:column>
                <h:column><f:facet name="header"><h:outputText value="電話番号" /></f:facet>#{emp.phone}</h:column>
                <h:column><f:facet name="header"><h:outputText value="携帯電話番号" /></f:facet>#{emp.mobilePhone}</h:column>    
                <h:column><f:facet name="header"><h:outputText value="郵便番号" /></f:facet>#{emp.zipCode}</h:column>
                <h:column><f:facet name="header"><h:outputText value="住所" /></f:facet>#{emp.address}</h:column>
                <h:column><f:facet name="header"><h:outputText value="備考" /></f:facet>#{emp.remarks}</h:column>
            </h:dataTable>
        </h:form>
    </h:body>
</html>


【社員一覧画面 CDIビーン】EmployeeList.java

package cdi;

//~~~import文省略~~~
import javax.enterprise.context.RequestScoped;
//~~~import文省略~~~

/**
 *
 * @author owner
 */
@Named
@RequestScoped
public class EmployeeList {
    @PersistenceContext
    private EntityManager em;

//~~~省略~~~

    public String gotoDetail(String employeeId, String mode) throws UnsupportedEncodingException
    {
        System.out.println(String.format(">>> EmployeeList gotoDetail(%s,%s) BEGIN >>>", employeeId, mode));

        TEmployee tEmployee = em.find(TEmployee.class, employeeId);
        if(tEmployee == null) {
            return "";
        }

        System.out.println(String.format("<<< EmployeeList gotoDetail(%s,%s) END <<<", employeeId, mode));
        return "employeeDetail?faces-redirect=true&employee_id=" + URLEncoder.encode(employeeId, "UTF-8") + "&mode=" + URLEncoder.encode(mode, "UTF-8");
    }
}

 
【社員詳細画面】employeeDetail.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>社員情報</title>
    </h:head>
    <h:outputStylesheet library="css" name="format.css" />
    <h:body>
        <f:metadata>
            <f:viewParam name="employee_id" value="#{employee.employeeId}" />
            <f:viewParam name="mode" value="#{employee.mode}" />
            <f:viewAction action="#{employee.initQueryParameters()}" />
        </f:metadata>
        <h1>社員台帳</h1>
        <h:form id="frm">
            <h:messages styleClass="preformatted"/>
            <h:panelGrid columns="3" >
                <h:commandButton value="編集" action="#{employee.beginEdit()}" rendered="#{employee.isRead()}" />
                <h:commandButton value="保存" action="#{employee.save()}" rendered="#{employee.isEdit()}" />
                <h:commandButton value="取消" action="#{employee.cancelEdit()}" rendered="#{employee.isEdit()}" />
            </h:panelGrid>
<!-- ~~~ 省略 ~~~ -->
        </h:form>
    </h:body>
</html>


 
【社員詳細画面 CDIビーン】Employee.java

package cdi;

//~~~import文省略~~~
import javax.enterprise.context.RequestScoped;
//~~~import文省略~~~

@Named
@RequestScoped
public class Employee implements Serializable {
    public enum Mode {
        Undefined,
        New,
        Read,
        Edit
    }
    private String employeeId;
    private String name;
    private String gender;
    private String phone;
    private String mobilePhone;
    private String zipCode;
    private String address;
    private String remarks;
    private Mode mode = Mode.Undefined;

    @PersistenceContext
    protected EntityManager em;

    @PostConstruct
    public void init()
    {
        System.out.println(">>> Employee init() BEGIN >>>");
        System.out.println("<<< Employee init() END <<<");
    }

    @PreDestroy
    public void terminate()
    {
        System.out.println(">>> Employee terminate() BEGIN >>>");
        System.out.println("<<< Employee terminate() END <<<");
    }

    public void initQueryParameters()
    {

        System.out.println(">>> Employee initQueryParameters() BEGIN >>>");
        if(employeeId != null && !employeeId.equals("")) {
            TEmployee tEmployee = em.find(TEmployee.class, employeeId);
            if(tEmployee != null) {
                System.out.println("employee found! [employeeId=" + tEmployee.getEmployee_id() + ", mode=" + mode.name() + "]");
                employeeId = tEmployee.getEmployee_id();
                name = tEmployee.getName();
                gender = tEmployee.getGender();
                phone = tEmployee.getPhone();
                mobilePhone = tEmployee.getMobilePhone();
                zipCode = tEmployee.getZipCode();
                address = tEmployee.getAddress();
                remarks = tEmployee.getRemarks();
            }
        }
        System.out.println("<<< Employee initQueryParameters() END <<<");
    }

    private String getViewId() throws UnsupportedEncodingException
    {
        String viewId = String.format("employeeDetail?faces-redirect=true&employee_id=%s&mode=%s"
                                            , URLEncoder.encode(employeeId, "UTF-8")
                                            , URLEncoder.encode(mode.name(), "UTF-8"));
        System.out.println("viewId=" + viewId);
        return viewId;
    }

//~~~setter, getter省略~~~

    public boolean isNew() { return mode == Mode.New; }
    public boolean isRead() { return mode == Mode.Read; }
    public boolean isEdit() { return mode == Mode.Edit; }

    //★★★ このメソッドが実行されない!!! ★★★
    public String beginEdit() throws UnsupportedEncodingException
    {
        System.out.println(">>> Employee beginEdit() BEGIN >>>");
        this.mode = Mode.Edit;
        String viewId = getViewId();
        System.out.println("Return ViewId=" + viewId);
        System.out.println("<<< Employee beginEdit() END <<<");
        return viewId;
    }

//~~~ 以下省略 ~~~
}

試したこと

1.PhaseListenerでログを出力
INVOKE_APPLICATIONのフェーズでbeginEdit()メソッドが実行されていないことを以下のログで確認しました。

「編集」ボタンクリック後に出力されたログ

情報: [Not Found] before: RESTORE_VIEW 1
情報: [/employeeDetail.xhtml] after: RESTORE_VIEW 1
情報: [/employeeDetail.xhtml] before: APPLY_REQUEST_VALUES 2
情報: >>> Employee init() BEGIN >>>    ★Employeeインスタンス開始★
情報: <<< Employee init() END <<<
情報: [/employeeDetail.xhtml] after: APPLY_REQUEST_VALUES 2
情報: [/employeeDetail.xhtml] before: PROCESS_VALIDATIONS 3
情報: [/employeeDetail.xhtml] after: PROCESS_VALIDATIONS 3
情報: [/employeeDetail.xhtml] before: UPDATE_MODEL_VALUES 4
情報: [/employeeDetail.xhtml] after: UPDATE_MODEL_VALUES 4
情報: [/employeeDetail.xhtml] before: INVOKE_APPLICATION 5    ←この行の直後にbeginEdit()メソッドが実行されない!
情報: [/employeeDetail.xhtml] after: INVOKE_APPLICATION 5
情報: [/employeeDetail.xhtml] before: RENDER_RESPONSE 6
情報: [/employeeDetail.xhtml] after: RENDER_RESPONSE 6
情報: >>> Employee terminate() BEGIN >>>
情報: <<< Employee terminate() END <<<    ★Employeeインスタンス終了★

 
2.CDIビーンのスコープを@ViewScopedへ変更

Employeeクラスを@RequestScopedから@ViewScopedに変更すると、何故かbeginEdit()が実行されるようになりました。
ですが、上記のログを見る限り、INVOKE_APPLICATIONフェーズの実行時にはEmployeeのインスタンスはまだ残っているので、実行されるはず・・・。

補足情報(FW/ツールのバージョンなど)

OS:Windows 10
IDE:NetBeans8.2
データベース:PostgreSQL 9.4
アプリケーションサーバ:GlassFish 4.1
FW:Java EE 7

長くてすいません。宜しくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る