12月10日

今後の予定について

12月17日まで

基本機能が動作するようにがんばりましょう!
機能の単位はロバストネス図で考えること。

12月17日

発表用のパワポ作成の課題を誰かに割り当てる
(テンプレートを用意するので必要事項を記入する)
発表する機能の動作確認。

1月7日

1現目はチーム内でパワポの確認とデモ内容の確認。
2現目は発表。

基本機能の確認

新規登録

  1. トップページを表示する
  2. 「新規登録」などのリンクをクリック
  3. 新規登録の画面を表示する
  4. 新規登録の画面で入力する
    1. 問題なければ新規登録する
    2. 不足があればエラー表示する

ログイン

  1. トップページを表示する
  2. 「ログイン」などのリンクをクリック
  3. ログインの画面を表示する
  4. IDとパスワードを入力する
    1. 一致すればホーム画面に進む
    2. 不一致ならエラー表示する

Webアプリの基本機能

  1. ホーム画面にWebアプリ特有の情報を表示する?
  2. ホーム画面からデータを送信する
  3. 送信したデータがDBに登録される(はず?)
  4. 送信したデータが画面上に表示される(?)

12月3日

ログアウトの設定

ログアウトを実行したい場合、spring-security.xml に以下の設定をする。

<sec:http auto-config="true">
    <intercept-url pattern="/**" access="ROLE_USER" />
    <sec:form-login login-page="/login.jsp"
        default-target-url="/home"
        authentication-failure-handler-ref="authenticationFailureHandler" />
    <sec:logout
        logout-url="/logout"
        logout-success-url="/"
        invalidate-session="true"
        delete-cookies="JSESSIONID" />
</sec:http>
 
<beans:bean id="authenticationFailureHandler"
    class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
    <beans:property name="defaultFailureUrl" value="/login.jsp?error=true"/>
    <beans:property name="useForward" value="true"/>
</beans:bean>

ログインしたユーザー情報の取得

ログインしたユーザーを取得するには、コントローラの引数に Principal を追加する。
ここでは、追加した Princical から getName()メソッドでユーザー名を取得し、addAttribute() で name に値を設定している。

@RequestMapping(value = "/home", method = RequestMethod.GET)
public String home(Model model, Principal p) {
    model.addAttribute("name", p.getName());
    return "home";
}

Userインスタンスの取得

Principal から取得できるのは名前だけなので、詳細な情報を取得するには、名前をキーにしてUsersテーブルから取得する必要がある。
Usersテーブルから名前をキーにして取得するために、DAOにメソッド定義 findByName() を追加する。

UserDao.java

public interface UserDao<T> {
    public List<T> getAll();
    public T findById(long id);
    public T findByName(String name);
    public void add(T data);
    public void update(T data);
    public void delete(T data);
    public void delete(long id);
}

UserDaoImpl で、検索機能を実装する。

UserDaoImpl.java

public class UserDaoImpl implements UserDao<User> {
    private static EntityManagerFactory factory = Persistence.createEntityManagerFactory("persistenceUnit");
 
    public List<User> getAll() {
        EntityManager manager = factory.createEntityManager();
        CriteriaBuilder builder = manager.getCriteriaBuilder();
        CriteriaQuery<User> query = builder.createQuery(User.class);
        Root<User> root = query.from(User.class);
        query.select(root);
        List<User> list = null;
        try {
            list = manager.createQuery(query).getResultList();
        } catch (NoResultException e) {
            //
        }
        return list;
    }
 
    public User findById(long id) {
        EntityManager manager = factory.createEntityManager();
        CriteriaBuilder builder = manager.getCriteriaBuilder();
        CriteriaQuery<User> query = builder.createQuery(User.class);
        Root<User> root = query.from(User.class);
        query.select(root).where(builder.equal(root.get("id"), id));
        User u = null;
        try {
            u = manager.createQuery(query).getSingleResult();
        } catch (NoResultException e) {
            //
        }
        return u;
    }
 
    public User findByName(String name) {
        EntityManager manager = factory.createEntityManager();
        CriteriaBuilder builder = manager.getCriteriaBuilder();
        CriteriaQuery<User> query = builder.createQuery(User.class);
        Root<User> root = query.from(User.class);
        query.select(root).where(builder.equal(root.get("name"), name));
        User u = null;
        try {
            u = manager.createQuery(query).getSingleResult();
        } catch (NoResultException e) {
            //
        }
        return u;
    }
 
    public void add(User user) {
        EntityManager manager = factory.createEntityManager();
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        User u = findById(user.getId());
        if (u == null) {
            try {
                manager.persist(user);
                transaction.commit();
            } catch (PersistenceException e) {
                transaction.rollback();
            }
            manager.close();
        } else {
            throw new PersistenceException("Duplicate user-id : " + u.getId());
        }
    }
 
    public void update(User user) {
        EntityManager manager = factory.createEntityManager();
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        try {
            manager.merge(user);
            transaction.commit();
        } catch (PersistenceException e) {
            transaction.rollback();
        }
        manager.close();
    }
 
    public void delete(User user) {
        EntityManager manager = factory.createEntityManager();
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        try {
            manager.remove(user);
            transaction.commit();
        } catch (PersistenceException e) {
            transaction.rollback();
        }
        manager.close();
    }
 
    public void delete(long id) {
        delete(findById(id));
    }
 
}

11月19日

残り時間は約1ヶ月

基本機能だけは動作するように実装を急ぎましょう!

JavaScriptの構文エラーが出る場合

以下の設定を行い、ダウンロードしたJavaScriptファイルのエラーを無視するようにする。

  1. プロジェクトを右クリックし[プロパティ]を選択。
  2. 左の一覧から JavaScript を選択し、ツリーを展開する。
  3. JavaScriptの下階層にある「インクルード・パス」を選択する。
  4. 右画面で「ソース」タブを選択する。
  5. プロジェクトのツリーを展開する。
  6. 「除外」を選択する。
  7. 右側の「編集」ボタンをクリックする。
  8. 「組み込みパターンおよび除外パターン」ダイアログ下側の「除外パターン」の右側にある「追加」をクリックする。
  9. 除外パターンに「**/*.min.js」を入力してOKをクリックする。
  10. 「組み込みパターンおよび除外パターン」ダイアログの「完了」をクリック。
  11. プロジェクトプロパティダイアログの「OK」をクリック。

11月16日

共有データベースの作り方

共有データベースを配置するパソコンを決める。
そのパソコンで、server.properties を作成する。
作成する場所は、C:\Users\se3\db\hsqldb-2.3.2\hsqldb\data フォルダ。

server.properties

# Hsqldb Server cfg file.
# See the HyperSQL Network Listeners chapter of the HyperSQL User Guide.

# Each server.database.X setting defines a database "catalog".
# I.e., an independent set of data.
# Each server.database.X setting corresponds exactly to the jdbc:hsqldb:*
# JDBC URL you would use if you wanted to get a direct (In-Process)
# Connection to the catalog instead of "serving" it.
server.database.0=file:db0/mydatabase
server.dbname.0=mydatabase

# I suggest that, for every file: catalog you define, you add the
# connection property "ifexists=true" after the database instance
# is created (which happens simply by starting the Server one time).
# Just append ";ifexists=true" to the file: URL, like so:
# server.database.0=file:db0/db0;ifexists=true

# server.dbname.0 defaults to "" (i.e. server.dbname.n for n==0), but
# the catalog definition n will be entirely ignored for n > 0 if you do not
# set server.dbname.n.  I.e. dbname setting is required for n > 0, though it
# may be set to blank (e.g. "server.dbname.3=")

C:\Users\se3\db\hsqldb-2.3.2\hsqldb\bin にある、runServer.bat をダブルクリックして起動する。

コマンドプロンプトに次の出力があれば、データベースの作成に成功している。

C:\Users\se3\db\hsqldb-2.3.2\hsqldb\bin>cd ..\data
[Server@24d46ca6]: [Thread[main,5,main]]: checkRunning(false) entered
[Server@24d46ca6]: [Thread[main,5,main]]: checkRunning(false) exited
[Server@24d46ca6]: Startup sequence initiated from main() method
[Server@24d46ca6]: Loaded properties from [C:\Users\se3\db\hsqldb-2.3.2\hsqldb\data\server.properties]
[Server@24d46ca6]: Initiating startup sequence...
[Server@24d46ca6]: Server socket opened successfully in 15 ms.
[Server@24d46ca6]: Database [index=0, id=0, db=file:db0/mydatabase, alias=mydata
base] opened sucessfully in 484 ms.
[Server@24d46ca6]: Startup sequence completed in 499 ms.
[Server@24d46ca6]: 2015-11-16 11:12:14.474 HSQLDB server 2.3.2 is online on port 9001
[Server@24d46ca6]: To close normally, connect and execute SHUTDOWN SQL
[Server@24d46ca6]: From command line, use [Ctrl]+[C] to abort abruptly

C:\Users\se3\db\hsqldb-2.3.2\hsqldb\bin にある、runManager.bat をダブルクリックして起動する。
接続のために以下の設定をして、OKすると接続できる。

 Type : HSQL Database Engine Server
 URL  : jdbc:hsqldb:hsql://localhost/mydatabase

他のパソコンから接続するには、パソコンのIPアドレスを調べる必要がある。
コマンドプロンプトを起動して ipconfig コマンドを実行して、IPアドレスを調べる。

C:\Users\se3>ipconfig

Windows IP 構成


Wireless LAN adapter ワイヤレス ネットワーク接続:

   メディアの状態. . . . . . . . . . : メディアは接続されていません
   接続固有の DNS サフィックス . . . :

イーサネット アダプター ローカル エリア接続 2:

   接続固有の DNS サフィックス . . . :
   IPv4 アドレス . . . . . . . . . . : 172.25.20.23
   サブネット マスク . . . . . . . . : 255.255.0.0
   デフォルト ゲートウェイ . . . . . : 172.25.1.254

イーサネット アダプター ローカル エリア接続 3:

   接続固有の DNS サフィックス . . . :
   IPv4 アドレス . . . . . . . . . . : 192.168.56.1
   サブネット マスク . . . . . . . . : 255.255.255.0
   デフォルト ゲートウェイ . . . . . :

他のパソコンから接続する場合は、localhost の代わりにそのパソコンのIPアドレスを指定する。
C:\Users\se3\db\hsqldb-2.3.2\hsqldb\bin にある、runManager.bat をダブルクリックして起動する。
接続のために以下の設定をして、OKすると接続できる。

 Type : HSQL Database Engine Server
 URL  : jdbc:hsqldb:hsql://192.168.56.1/mydatabase

エンティティを1対多の関係にする

Onwerが複数のChildを持つ場合は、以下のようにエンティティを作成する。

Owner.java

@Entity
public class Onwer {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @NutNull
    public long id;

    @OneToMany(cascade=CascadeType.ALL)
    @Column(nullable = false)
    private List<Child> children;

    // gettere/setter を用意
}

Child.java

@Entity
public class Child {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @NutNull
    public long id;

    @ManyToOne
    @Column(nullable = false)
    private Owner owner;

    // getter/setter を用意
}

Onwerに複数のChildを追加した状態でエンティティを永続化すると、そのOwnerをDBから取り出したときは、追加した複数のChildが追加された状態で取り出せる。

11月12日

課題をたくさん完了させよう!

課題をなかなか完了できない場合は、課題を細かく分割する。

XxControllerを作成する。
XxControllerにURL=/hoge の GET リクエストを実装する。
hoge.jsp を作成する。
XxControllerのURL=/hoge の応答で、hoge.jsp を表示する。
XxControllerのURL=/hoge の GET リクエストで message データを設定する。
hoge.jsp で message データを表示する。
hoge.jsp に form を追加する。
XxControllerにURL /hoge の POST リクエストを実装する。
XxControllerのURL=/hoge の POST リクエストの応答で resp.jsp を表示する。

11月9日

機能の検討方法と課題の作り方

機能を検討するときは、必要最小限の機能を先に作る。
たとえば、編集や削除を行う場合に、編集内容や削除の確認があったほうがいいと思った場合、まずは確認を行わないUIを作成する。
課題は以下のように作成する。

  1. 編集画面の作成(JSP)
  2. 編集を受け付けるコントローラの実装
  3. 編集をDBに反映するDAOの実装

確認しないUIで作成して動かしてみる。
実際に使ってみて、確認が必要だと思ったら確認のUIを追加する。

  1. 編集確認のUI作成(JSP/JavaScript)
  2. 編集確認でOKでの実装
  3. 編集確認でキャンセル時の実装