11月7日

チーム開発について

作業の進め方

  1. 作業を進める課題を決める
  2. Backlogで課題を担当して処理中にする
  3. 作業のペアを決める(必要に応じて)
  4. コードを書く
  5. 動作確認する
  6. Gitにcommit/pushする
  7. Backlogの課題を「処理済」にする
  8. Gitからpull/fetchして最新コードを取得(他のメンバー)
  9. 動作確認する(他のメンバー)
  10. 他のメンバーが動作確認できたらBacklogの課題を「完了」にする

バッドノウハウ

  • HSQLDBプラグインの設定を変更したが、HSQLEB Serverを再起動してないためにDBに接続できない。
  • Gitにpushできていない。pushできているかどうかは、BacklogのGitタブのリポジトリを参照して確認する。

クラス名や変数名の命名について

Javaの命名規約
http://java.satoshis.com/index.php/java/tutorial/8-naming-convention.html

11月6日

重要な課題

  • 画面遷移(静的ページで可)
  • ログイン・ログアウト
  • パラメータからデータ受け取り
  • 受け取ったデータの表示
  • データの永続化
  • デザイン

Backlogの課題の粒度を小さくする

「各画面の○○」のような課題は、「A画面の○○」「B画面の○○」のように、画面別の課題にする。
DB連携はエンティティ別に分ける。
基本的な動きが完成したときは課題を完了させ、問題点はバグとして新しく課題を追加する。

Webアプリが期待通りに動作しないときの対処

コンテキストルート( http://localhost:8080/appname/ )にアクセスして404エラーになる場合は、設定に問題があるためにアプリケーションコンテキストが動作していない可能性が高い。
コンソールビューを参照して例外が発生していないか確認する。例外が発生している場合は、例外に表示されているメッセージをヒントにして問題を解決する。

コンテキストルートの設定が間違っていないかを確認する。プロジェクトのプロパティを開き、以下の内容をチェックする。

  • 「プロジェクト・ファセット」を選択して「動的Webモジュール」のバージョンを「2.5」に設定し、行の左端のチェックをONにする。
  • 「Webプロジェクトの設定」を選択して、「コンテキスト・ルート」の設定を確認する。

コンテキストルートにアクセスできて、期待通りに動作しない場合は、変更前のJSPやJavaによって動作している可能性があるので、古いファイルを削除するために以下の操作を試してみる。

  • [プロジェクト]-[クリーン]してプロジェクトをビルドしなおす
  • Tomcatを停止してクリーンする(サーバービューのTomcatを右クリックしてクリーン)
  • Tomcat配下のWebアプリを右クリックして「モジュール・ワーク・ディレクトリーをクリーン」を実行する
  • Tomcat配下のWebアプリを削除して追加しなおす
  • サーバービューでTomcatを削除して再登録する

10月31日

小さな粒度の課題を実施する

今日の2現目はテストなので、作業できるのは70分程度。その短い時間で達成できそうな課題を考えて、その課題を完了させることを目標にすること。

Gitの活用

ソースコードを変更しているときに、変更方法が不適切だと気づいたときは、そのソースコードのファイルを右クリックし、[チーム]-[リセット]を選択するとよい。修正を加える前の状態に戻せる。

Gitの問題?

プッシュして、BacklogのGit上では更新されているのに、プルしても最新のファイルを取得できない問題あり?

10月30日

Spring Securityによるログアウトの方法

Spring Security でログアウトを実装するには、設定ファイル spring-security.xml に以下の設定を追加する。

	<sec:http auto-config="true">
		<intercept-url pattern="/**" access="ROLE_USER" />
		<sec:logout
			logout-url="/logout"
			logout-success-url="/"
			invalidate-session="true"
			delete-cookies="JSESSIONID" />
	</sec:http>

sec:logout タグ内の logout-url で指定した URL にアクセスすると、セッション情報が破棄される。

ログアウトを追加したい画面に対応する JSP に、以下のリンクを追加すればよい。
ログイン中のユーザーがここをクリックすると、セッション情報が破棄され、ログアウトする。

<a href="/logout">Logout</a>

トラブルシューティング

DBに登録でエラーになる

Q.新規ユーザーをDBに登録するところで例外が発生して登録できない。
A.コンソールの内容を確認すると、commit()で例外が発生している。メッセージを確認すると、「unique constraint or index violation」と表示。
プライマリキーを自動で割り当てるように、エンティティにアノテーションを追加すれば解決する。

10月17日

認証なしでアクセス可能なページの設定


JavaScriptやCSS、画像など認証不要でアクセス可能なURLを指定する方法について。

cssや画像を取得できるようにする

mvc-config.xmlに以下の設定を追加する。

	<mvc:resources mapping="/css/**" location="/css/" />

Spring Security でアクセス制限する場合、誰でもアクセス可能なページは、security-config.xml で設定する。
たとえば、アプリケーションコンテキストルートに対応するページは誰でもアクセス可能にするべきなので、以下のように設定する。

    <sec:http pattern="/" security="none"/>

以下は security-config.xml の全体。

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:sec="http://www.springframework.org/schema/security"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

	<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<beans:property name="driverClassName" value="org.hsqldb.jdbc.JDBCDriver" />
		<beans:property name="url" value="jdbc:hsqldb:hsql://localhost/exam" />
		<beans:property name="username" value="sa" />
		<beans:property name="password" value="" />
	</beans:bean>

	<beans:bean id="encoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder" />

	<sec:http pattern="/" security="none"/>
	<sec:http pattern="/index.jsp" security="none"/>
	<sec:http auto-config="true">
		<intercept-url pattern="/**" access="ROLE_USER" />
	</sec:http>

	<authentication-manager>
	    <authentication-provider>
                <user-service>
                    <user name="taro" password="abcd" authorities="ROLE_USER" />
                </user-service>
	    </authentication-provider>
	</authentication-manager>

</beans:beans>

Tomcatサーバーにアプリケーションコンテキストを追加できない場合

Tomcatサーバーを右クリックして「追加および除去」を選択し、ダイアログの中に動作させたいアプリケーションコンテキスト名が表示されていない場合は、以下の設定を確認する。

  1. プロジェクトを右クリックし、プロパティを開く。
  2. ダイアログの左で「プロジェクト・ファセット」を選択する。
  3. 「動的Webモジュール」の「バージョン」を「2.5」に変更する。
  4. 「動的Webモジュール」のチェックボックスをチェックする。
  5. ダイアログで「OK」する。

データベースを使った認証

現状では spring-security.xml に書いたユーザー名とパスワードで認証しているが、これをデータベースを使った認証に変更する。

USERSテーブルの準備

HSQLDBのデータベースマネージャを起動し、以下のSQLでテーブルを作成する。

CREATE TABLE users(
 user_id bigint NOT NULL identity,
 user_name varchar(50) NOT NULL,
 password varchar(50) NOT NULL,
 enabled tinyint NOT NULL,
 role varchar(100) NOT NULL
);

テスト用のユーザーをUSERSテーブルに追加する

以下のSQLでユーザーを追加する。

INSERT INTO users ( user_name , password , enabled, role)
   VALUES ( 'taro', 'abcd' , 1, 'ROLE_USER' );

spring-security.xmlの変更

spring-securoty.xml の以下の箇所でユーザー名とパスワードを指定している。

	<authentication-manager>
	    <authentication-provider>
                <user-service>
                    <user name="taro" password="abcd" authorities="ROLE_USER" />
                </user-service>
	    </authentication-provider>
	</authentication-manager>

この部分をデータベースのUSERSテーブルから取得するようにするために、以下のように修正する。

	<authentication-manager>
	    <authentication-provider>
                <jdbc-user-service data-source-ref="dataSource"
	             users-by-username-query="SELECT user_name, password, enabled FROM users WHERE user_name = ?"
	             authorities-by-username-query="SELECT user_name, role FROM users WHERE user_name = ?"
	        />
	    </authentication-provider>
	</authentication-manager>

10月16日

チーム開発の続き

Spring Securityによる認証

サイトにログイン機能を追加するには、Spring Security を使用すると簡単に実装できる。

Spring Security の設定ファイルを読み込ませるために、contextConfigLocation を追加する。

web.xml

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/application-config.xml</param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/spring-security.xml</param-value>
    </context-param>

すべてのページにアクセスする前にアクセス権限のチェックを実行させるため、web.xml の最後に、フィルターを追加する。

web.xml

	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

src/main/resources/spring フォルダに、spring-security.xml を作成する。
まずはXMLで指定したユーザーでログインできるようにする。
ユーザー名: taro
パスワード: abcd

あとでDBから取得するように変更する。

spring-security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:sec="http://www.springframework.org/schema/security"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

	<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<beans:property name="driverClassName" value="org.hsqldb.jdbc.JDBCDriver" />
		<beans:property name="url" value="jdbc:hsqldb:hsql://localhost/exam" />
		<beans:property name="username" value="user" />
		<beans:property name="password" value="password" />
	</beans:bean>

	<beans:bean id="encoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder" />

	<sec:http pattern="/" security="none"/>
	<sec:http pattern="/index.jsp" security="none"/>
	<sec:http auto-config="true">
		<intercept-url pattern="/**" access="ROLE_USER" />
	</sec:http>

	<authentication-manager>
		<authentication-provider>
            <user-service>
                <user name="taro" password="abcd" authorities="ROLE_USER" />
            </user-service>
		</authentication-provider>
	</authentication-manager>

</beans:beans>

exam-8

10月9日

チーム開発について

1日のスケジュール

9:45~10:00
グループミーティングを行う。各メンバーが、その日に取り組む課題を決める。
課題はBacklogで管理する。
全員が何かの課題の担当者となるようにすること。
ミーティングのあと、取り組む課題をBacklogで確認する。

10:00~12:50
成果発表。発表する際には、KPTを意識する。
KPTとは・・・
Keep、Problem、Tryの頭文字。

KPT参考資料

各グループで取り組む課題要旨

・画面遷移図
 ロバストネス図で作成する。
・各画面の作成
 デザイナーではないので、画面に凝らないこと!
・エンティティの設計
 システム内でエンティティとなるクラスを見つける。
 エンティティの責務をはっきりさせる。
・Dao/DaoImpleの作成
 エンティティがわかれば必要なDao/DaoImplもわかる。
・Controllerの作成
 画面遷移図にあわせてControllerを作成する。
 ひとつのControllerには複数の機能を割り当てない。

UML図やロバストネス図を電子化したい場合は astah community が無料で使用できる。
http://astah.change-vision.com/ja/product/astah-community.html

exeファイルだとインストールには管理者権限が必要なので、ZIPファイルをダウンロードして適当なところに展開する。

ログインに関する部分

ログインは、spring-security を使用する。
以下のページを参考にする。

Spring Security: ユーザ認証情報をDBに保存する
http://kurotofu.sytes.net/kanji/fool/?p=934

パスワードの暗号化は後回しにする。
暗号化したパスワードを保存すると、開発中のオーバーヘッドが増えてしまうから。

Gitのコミット&プッシュ

コミットする前に、すべてのファイルのチェックをはずし、自分で編集したファイルだけにチェックを入れる。
コメントランには、編集した内容を簡潔に記述する。(課題のIDと修正内容:○○バグの修正、入力チェックを追加等)

10月3日

GITを使ってチーム内でソースコードを共有する

BacklogのプロジェクトでGitリポジトリを作成する

こちらを参考に、BacklogにGitリポジトリを作成する。

プロジェクトをローカルリポジトリにコミットする

プロジェクトをBacklogのリモートリポジトリにプッシュする

こちらを参考に、プロジェクトをリモートリポジトリにプッシュする。

リモートリポジトリをローカルにクローンする

代表者以外の人は、代表者がリモートリポジトリにプッシュしたプロジェクトを、ローカルにクローンする。

  1. Eclipseで[ファイル]-[インポート]を選択。
  2. ダイアログで[Git]-[Gitからプロジェクト]を選択して「次へ」をクリック。
  3. [Clone URI]を選択して「次へ」をクリック
  4. URI に、BacklogのプロジェクトのGitタブにあるURLを貼り付ける。
  5. backlog-1

  6. Backlogプロジェクトのユーザー名とパスワードを入力して「次へ」をクリック
  7. masterがチェックされた状態で「次へ」をクリック
  8. git-1

  9. ローカルの保管場所はそのままで「次へ」をクリック
  10. git-2

  11. プロジェクトのインポートもそのままの設定で「完了」をクリック
  12. git-4

  13. Eclipseにプロジェクトが追加された!
  14. git-5

ユーザー認証

ユーザー認証はSpring Securityを使用する。

こちらのサイトを参考に。

その他、「srping security hibernate ユーザー認証」などのキーワードで検索するとよい。

9月26日

Rooによる超高速開発

コントローラを作る

Roo Shell で以下のコマンドを実行。

> web mvc controller --class ~.HelloController --preferredMapping /helo

昨日の動作するプロジェクトのバックアップを以下の場所に置いたので、エラーが出る人がこちらからコピーしてみてください。

\\kgakusei1\share\澤田\SE3Java2014\20140925

FormDataクラスを作成する。

package jp.abc;

public class FormData {
	private String input;

	public String getInput() {
		return input;
	}

	public void setInput(String input) {
		this.input = input;
	}
}

index.jspxを編集する。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:jsp="http://java.sun.com/JSP/Page" 
     xmlns:spring="http://www.springframework.org/tags" 
     xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" 
     xmlns:form="http://www.springframework.org/tags/form"
     version="2.0">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <jsp:output omit-xml-declaration="yes"/>
  <spring:message code="label_helo_index" htmlEscape="false" var="title"/>
  <util:panel id="title" title="${title}">
    <spring:message code="application_name" htmlEscape="false" var="app_name"/>
    <h3>
      <spring:message arguments="${app_name}" code="welcome_titlepane"/>
    </h3>
    <p>${message}</p>
    <form:form modelAttribute="formData" action="form">
        <form:input path="input" />
        <input type="submit" />
    </form:form>
  </util:panel>
</div>

HelloController.java を編集する。

package jp.abc;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@RequestMapping("/helo/**")
@Controller
public class HelloController {

    @RequestMapping(method = RequestMethod.POST, value = "{id}")
    public void post(@PathVariable Long id, ModelMap modelMap,
    		HttpServletRequest request,
    		HttpServletResponse response) {
    }

    @RequestMapping
    public String index(Model model) {
    	model.addAttribute("formData", new FormData());
        return "helo/index";
    }

    @RequestMapping(method = RequestMethod.POST, value = "/form")
    public String post(@ModelAttribute FormData form, Errors result, Model model) {
    	model.addAttribute("message", "You typed: " + form.getInput());
    	return "helo/index";
    }
}

Rooは問題が多いのであきらめましょう!

examプロジェクトに戻ります

JUnitを使ったテスト

以下のサイトを参考に。
http://d.hatena.ne.jp/nakaearth/20131204

src/test/java に新規で jp.abc パッケージを作成。
[新規]-[JUnitテストケース]でテストクラスを作成。

package jp.abc;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.context.WebApplicationContext;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public class HomeControllerTest {

	@Autowired
	private WebApplicationContext wac;

	private MockMvc mockMvc;

	@Before
	public void setUp() throws Exception {
		mockMvc = webAppContextSetup(wac).build();
	}

	@Test
	public void testHome() {
		fail("まだ実装されていません");
	}

	@Test
	public void testQuery() {
		fail("まだ実装されていません");
	}

}