【入門編】Slim3で始める!GAE/JでWebアプリケーション開発 (第3回)

残機能の開発

記事削除を行うControllerの実装

<記事編集>にて記事削除ボタンが押下された際のControllerを実装します。


記事削除概要イメージ

  • Antタスク gen-controller-without-view の実行gen-controller-without-view に /bbs/deleteEntry と入力して以下のクラスを生成します。
    • simplebbs.controller.bbs.DeleteEntryController
    • simplebbs.controller.bbs.DeleteEntryControllerTest
  • テストケースの作成記事削除ではユーザの入力値はありませんのでバリデーションの検査は不要です。正常ケースと、対象の記事が存在しないケースをテストします。

    DeleteEntryControllerTest.java

    package simplebbs.controller.bbs;
    
    import java.util.Date;
    
    import org.slim3.datastore.Datastore;
    import org.slim3.tester.ControllerTestCase;
    import org.junit.Test;
    
    import simplebbs.model.bbs.Body;
    import simplebbs.model.bbs.Head;
    import simplebbs.service.bbs.BbsService;
    import static org.junit.Assert.*;
    import static org.hamcrest.CoreMatchers.*;
    
    public class DeleteEntryControllerTest extends ControllerTestCase {
    
        private BbsService service = new BbsService();
        private String keyString = null;
    
        @Override
        // 各テストの前に実行される処理
        public void setUp() throws Exception {
            super.setUp();
            // テスト前に記事を1件登録しておく
            insertEntry("テスト用の記事", "テストユーザ", new Date(), "テスト用の記事の本文です。", "password");
            // 登録した1件の記事を取得する
            Head head = service.getAll().get(0);
            // この記事のKeyを文字列に変換して保持
            keyString = Datastore.keyToString(head.getKey());
        }
    
        // 記事を新規登録する
        private void insertEntry(String subject, String username, Date postDate, String text, String password) throws Exception {
            // 記事の作成
            Head head = new Head();
            head.setSubject(subject);
            head.setUsername(username);
            head.setPostDate(postDate);
            head.setPassword(password);
            // 本文の作成
            Body body = new Body();
            body.setText(text);
            // データストアへ登録
            service.insert(head, body);
        }
    
        @Test
        public void testValidParameter() throws Exception {
            // 記事編集で削除ボタンが押下された動作をエミュレート
            tester.param("key", keyString);
            tester.param("password", "password");
            tester.request.setMethod("POST");
            tester.start("/bbs/deleteEntry");
            DeleteEntryController controller = tester.getController();
            // ========== assertion start ========== //
            assertThat(controller, is(notNullValue()));
            // 記事は0件であること
            assertThat(service.getAll().size(), is(0));
            // エラーメッセージは空であること
            assertThat(tester.getErrors().isEmpty(), is(true));
            // トップページにリダイレクトしていること
            assertThat(tester.getDestinationPath(), is("/bbs/"));
            assertThat(tester.isRedirect(), is(true));
            // ========== assertion end ========== //
        }
        @Test
        public void testAfterDeleted() throws Exception {
            // 該当の記事を削除しておく
            service.delete(Datastore.stringToKey(keyString));
            // 記事編集で削除ボタンが押下された動作をエミュレート
            tester.param("key", keyString);
            tester.param("password", "password");
            tester.request.setMethod("POST");
            tester.start("/bbs/deleteEntry");
            DeleteEntryController controller = tester.getController();
            // ========== assertion start ========== //
            assertThat(controller, is(notNullValue()));
            // Errorsのキー"message"にエラーメッセージがセットされていること
            assertThat(tester.getErrors().get("message"), is(notNullValue()));
            // 記事一覧(/bbs/)にフォワードしていること
            assertThat(tester.getDestinationPath(), is("/bbs/"));
            assertThat(tester.isRedirect(), is(false));
            // ========== assertion end ========== //
        }
    }
    

    例によってテストを実行して失敗することを確認しておきましょう。


    DeleteEntryControllerTest失敗イメージ

  • 必要な処理の実装DeleteEntryControllerは以下のように修正しました。

    DeleteEntryController.java

    package simplebbs.controller.bbs;
    
    import org.slim3.controller.Controller;
    import org.slim3.controller.Navigation;
    import org.slim3.util.ApplicationMessage;
    
    import simplebbs.model.bbs.Head;
    import simplebbs.service.bbs.BbsService;
    
    public class DeleteEntryController extends Controller {
    
        @Override
        public Navigation run() throws Exception {
            if (!isPost()) {
                // POSTではないリクエストはトップページへリダイレクト
                return redirect(basePath);
            }
            BbsService service = new BbsService();
            Head head = null;
            try {
                // 指定されたkeyから記事を取得
                head = service.get(asKey("key"));
            }
            catch (Exception e) {
                // keyが不正な場合
            }
            // 記事が取得できなかった場合
            if (head == null) {
                // 指定されたキーに該当する記事がない場合はトップへ戻る
                errors.put("message", ApplicationMessage.get("error.entry.notfound"));
                return forward(basePath);
            }
            if (!asString("password").equals(head.getPassword())) {
                // パスワードが不一致の場合は記事詳細へ戻る
                errors.put("password", ApplicationMessage.get("error.password.invalid"));
                return forward("read");
            }
            // 記事削除
            service.delete(head.getKey());
            // トップページへリダイレクト
            return redirect(basePath);
        }
    }
    

    DeleteEntryControllerの処理は、先に作成したUpdateEntryControllerの処理を流用して作成可能です。

  • テストケースの実行DeleteEntryControllerの実装が完了したら保存して、テストを実行してみます。
    DeleteControllerTest成功イメージ
    テストがグリーンになったら、ブラウザからも動作確認しましょう。記事編集ページから削除ボタンを押下してみます。
    記事削除ボタン押下イメージ
    すると、JavaScriptで仕込んだ確認ダイアログが表示されるのでOKボタンを押下します。
    記事削除後イメージ
    トップページに遷移し、先ほど削除した記事がなくなっていることを確認しました。以上で<記事削除>の実装は完了です。作成したソースは以下になります。

    • simplebbs.controller.bbs.DeleteEntryController.java
    • simplebbs.controller.bbs.DeleteEntryControllerTest.java

    次はいよいよ最後の処理<コメント登録>を実装します。