11月5日

Spring Security によるログイン

pom.xml に以下の設定を追加する。
pom.xml

		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-core</artifactId>
		    <version>4.0.1.RELEASE</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-web</artifactId>
		    <version>4.0.1.RELEASE</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-config</artifactId>
		    <version>4.0.1.RELEASE</version>
		</dependency>

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>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>


    <!--
		- Servlet that dispatches request to registered handlers (Controller implementations).
	-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/mvc-config.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
    <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>

11月2日

URLごとのアクセス制限

spring-security.xml ファイル内で、ログイン不要でアクセス可能なURLと、ログインが必要なURLを定義する。
CSSやJavaScriptファイルは、基本的にログイン不要でアクセス可能な場所に置く。
10月5日の spring-security.xml では、9~15行が相当する。
CSSやJavaScript を置いたフォルダをアクセス可能にするには、以下のように設定する。

spring-security.xml

    <http pattern="/" security="none"/>
    <http pattern="/index.jsp" security="none"/>
    <http pattern="/css" security="none"/>
    <http pattern="/js" security="none"/>
    <http auto-config="true" >
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
        <form-login />
        <logout />
    </http>

ログインの実装

10月5日に書いた内容の補足。

USERSテーブルを作成するためにはSQLコマンドを実行する必要がある。
SQLコマンドを実行するには、コマンドプロンプトからDatabaseManagerを起動して、HSQLDBに接続する必要がある。
その方法は、9月11日に書いてある。

10月29日

サービスのトップページを作ろう

デフォルトでは「Click to Enter」とだけ表示している画面を、独自のトップページに修正しよう。
修正するファイルは、webapp の下にある index.jsp 。

  • つぶやき6ヶ:未
  • harunoumi:未
  • kentomori:済
  • SESオールスターズ:未
  • 歪みねぇやぴ軍団:未

アクセスコントロール

Springでは、Spring Security によって、ログインなしでアクセスできるところと、ログインが必要なところを分類する。
ログインしていない状態でログインが必要なところにアクセスすると、自動的に標準のログインダイアログを表示する。
ログイン画面を標準のものと変えたいときは、spring-security.xml で、ログ引用のJSPを設定する。

10月16日

Git関連情報

Git リポジトリの削除

Gitリポジトリを削除するには、Backlog の「プロジェクト設定」で Git を選択し、「編集」をクリックする。
そこで、リポジトリの削除ができる。

Git で管理したくないファイル/ディレクトリ

.gitignore ファイルに記述して、.gitignore をコミット/プッシュする。

.で始まるファイルをプロジェクトエクスプローラで表示する

プロジェクトエクスプローラ右上の▽をクリックし、「ビューのカスタマイズ」を選択する。
「.* リソース」のチェックをはずしてOKする。

10月9日

ログインしているユーザー情報の取得

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

MyDataController.java

	@RequestMapping(value = "/mydata", method = RequestMethod.GET)
	public String mydata(Model model, Principal p) {
		model.addAttribute("name", p.getName());
		model.addAttribute("title", "MyData");
		model.addAttribute("message", "データを入力してください");
		MyData mydata = new MyData();
		model.addAttribute("myData", mydata);
		MyDataDao<MyData> dao = new MyDataDaoCriteria();
		List<MyData> list = dao.getAll();
		model.addAttribute("datalist", list);
		return "mydata";
	}

mydata.jsp

<body>
	<h1>${title}</h1>
	<p>${message}</p>
	<p>ようこそ ${name} さん</p>
	<table>
	<form:form modelAttribute="myData">

10月5日

データベースを使用した認証

ユーザーとユーザの権限を管理するためのテーブルを作成する。

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
);

テーブルにテスト用のユーザーを登録する。

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

spring-security.xml を、データベースを使った認証をするように書き換える。

spring-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-4.0.xsd">

    <http pattern="/" security="none"/>
    <http pattern="/index.jsp" security="none"/>
    <http auto-config="true" >
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
        <form-login />
        <logout />
    </http>

    <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/mydatabase" />
        <beans:property name="username" value="sa" />
        <beans:property name="password" value="" />
    </beans:bean>

    <!-- ユーザとROLEを定義 -->
    <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>
</beans:beans>

10月2日

チーム開発

チーム開発のプロジェクト管理にBacklogを使用する。
Backlogには、課題管理、Git、Wikiなどの便利なツールがある。
チーム開発を通して、各ツールの使い方に慣れる。

今後の作業の進め方

  1. スタートアップミーティング
  2. チームでの開発作業
  3. ふりかえり

スタートアップミーティング

朝、10分程度のスタートアップミーティングを行う。
ミーティングで以下の内容を決める。

  • 1日のチーム内の作業分担を決める。
  • 各人がBacklogに課題を登録する。

チーム開発作業

ひとりで難しいときはペアプログラミングで効率を上げる。
課題に書いた内容を実装する。

  • ドキュメント整理(Wikiを活用)
  • JSP作成
  • コントローラ作成
  • エンティティ作成

Wikiで整理するとよさそうな情報

  • ロバストネス図(画面遷移図)
  • 画面デザイン
  • クラス図
  • シーケンス図

12:50ごろから1日のふりかえりを行う

ミーティング後、全員の課題を確認する。
KPT : Keep / Problem / Try

  • 全員の課題の進捗確認。
  • チームごとのKPTの確認。

Spring Securityによるユーザー認証

サイトにログイン機能を追加するには、Spring Security を使用すると簡単に実装できる。
Spring Security の設定ファイルを読み込ませるために、contextConfigLocation を追加する。

pom.xmlの変更

Spring Security のライブラリを追加する。

pom.xml

		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-core</artifactId>
		    <version>4.0.1.RELEASE</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-web</artifactId>
		    <version>4.0.1.RELEASE</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-config</artifactId>
		    <version>4.0.1.RELEASE</version>
		</dependency>

pom.xml を変更したら、プロジェクトの更新と、maven install を実行する。

設定ファイルを読み込ませる

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>

設定ファイルを作成する

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

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

spring-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-4.0.xsd">

    <http pattern="/" security="none"/>
    <http pattern="/index.jsp" security="none"/>
    <http auto-config="true" >
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
        <form-login />
        <logout />
    </http>

    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="admin" password="admin" authorities="ROLE_ADMIN" />
                <user name="user" password="user" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>
</beans:beans>

すべてのページにアクセスする前にアクセス権限のチェックを実行させるため、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>

9月28日

チームごとの決定事項

  • グループA
    • チーム名:つぶやき6ヶ
    • リーダー:新納
    • Webアプリ:Twitter
    • Webアプリ名:Digtter
  • グループB
    • チーム名:harunoumi
    • リーダー:芳賀
    • Webアプリ:匿名掲示板
    • Webアプリ名:はがちゃんねる(HGCH)
  • グループC
    • チーム名:kentomori
    • リーダー:森
    • Webアプリ:スケジュール管理
    • Webアプリ名:スケジュール管理
  • グループD
    • チーム名:SESオールスターズ
    • リーダー:篠原
    • Webアプリ:checkpad
    • Webアプリ名:checkpad
  • グループE
    • チーム名:歪みねぇやぴ軍団
    • リーダー:江藤
    • Webアプリ:Twitter
    • Webアプリ名:本格的♂TEITTER

課題の取り扱い

課題は誰でも作れる。
課題を作るときに、担当者を割り当てる。

  1. 課題を作成する(未対応)
  2. 課題に取り掛かる前に「処理中」に変更する
  3. 課題を済ませたら「処理済」に変更する
  4. 「処理済」の課題を他のメンバーに確認してもらう
  5. 確認OKなら、コミットしてプッシュする
  6. 確認したメンバーが「完了」に変更する

リーダーは課題「ロバストネス図を作成する」を追加する。
他のメンバーは課題「クローンする」を作成する。

9月25日

Backlogを使用したチーム開発

決めること

  • チーム名
  • リーダー
  • 作成するWebアプリ
  • Webアプリ名

Webアプリの例

  • 匿名掲示板
  • Twitter
  • LINE
  • SNS
  • Wiki
  • その他

チームリーダーが以下の作業を実施。

  1. Backlog にアクセス。
  2. 「プラント価格はこちら」をクリック。
  3. 右下の「1プロジェクト、10人までのフリープランはこちら」をクリック。
  4. 必要事項を入力してスペースを作成。
  5. 「ユーザーの追加」からチーム全員を招待する。
  6. ユーザーID:satoshis、メールアドレス:satoshis@gmail.com も招待。
  7. プロジェクトを作成し、プロジェクトにメンバーを追加する。
  1. グループA
  2. https://diguhaga.backlog.jp/

  3. グループB
  4. https://harunoumi.backlog.jp/

  5. グループC
  6. https://kentomori.backlog.jp/

  7. グループD
  8. https://ukshhm.backlog.jp/

  9. グループE
  10. https://yapy.backlog.jp/

9月18日

エンティティの連携

MyDataController に POST メソッドのためのメソッドを追加する。

MyDataController.java

	@RequestMapping(value = "/msg", method = RequestMethod.POST)
	public String msgform(@Valid @ModelAttribute MsgData msgdata, Errors result, Model model) {
		System.out.println("msgform: " + msgdata.getMydata());
		if (result.hasErrors()) {
			model.addAttribute("title", "MsgData [Error]");
			model.addAttribute("message", "値が間違っています");
			return "msgdata";
		}
		MsgDataDao<MsgData> dao = new MsgDataDaoImpl();
		dao.add(msgdata);
		return "redirect:/msg";
	}

この変更でクエリ送信はできるようになるが、エラーが表示される。
java.lang.String を jp.abc.MyData に変換できないというエラー。

この対策のため、テキストp.357からのコードを追加する。
まず新規で MyDataPropertyEditor クラスを作成する。

MyDataPropertyEditor.java

package jp.abc;

import java.beans.PropertyEditorSupport;

public class MyDataPropertyEditor extends PropertyEditorSupport {
	public String getAsText() {
		MyData value = (MyData)getValue();
		System.out.println("getAsText: " + value);
		if (value == null) {
			return "";
		} else {
			return "" + value.getId();
		}
	}

	public void setAsText(String value) {
		MyDataDao<MyData> dao = new MyDataDaoImpl();
		MyData mydata = dao.findById(Long.parseLong(value));
		System.out.println("setAsText: " + mydata);
		setValue(mydata);
	}
}

Controller で、作成した PropertyEditor を利用できるように設定する。
MyDataController の先頭に以下のメソッドを追加する。

MyDataController.java

	@InitBinder
	protected void initBinder(HttpServletRequest req,
			ServletRequestDataBinder binder) throws Exception {
		binder.registerCustomEditor(MyData.class, new MyDataPropertyEditor());
	}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.springframework.samples.service.service</groupId>
  <artifactId>MyData</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

    <properties>

		<!-- Generic properties -->
		<java.version>1.6</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

		<!-- Web -->
		<jsp.version>2.2</jsp.version>
		<jstl.version>1.2</jstl.version>
		<servlet.version>2.5</servlet.version>


		<!-- Spring -->
		<spring-framework.version>3.2.3.RELEASE</spring-framework.version>

		<!-- Hibernate / JPA -->
		<hibernate.version>4.2.1.Final</hibernate.version>

		<!-- Logging -->
		<logback.version>1.0.13</logback.version>
		<slf4j.version>1.7.5</slf4j.version>

		<!-- Test -->
		<junit.version>4.11</junit.version>

	</properties>

	<dependencies>

		<!-- Spring MVC -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Other Web dependencies -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>${jstl.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>${servlet.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>${jsp.version}</version>
			<scope>provided</scope>
		</dependency>

		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Logging with SLF4J & LogBack -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
			<scope>runtime</scope>
		</dependency>

		<!-- Hibernate -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.version}</version>
		</dependency>


		<!-- Test Artifacts -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring-framework.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.1</version>
		</dependency>

		<dependency>
			<groupId>org.hsqldb</groupId>
			<artifactId>hsqldb</artifactId>
			<version>2.3.2</version>
		</dependency>

		<dependency>
			<groupId>javax.transaction</groupId>
			<artifactId>jta</artifactId>
			<version>1.1</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>3.2.4.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>3.2.4.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-jpa</artifactId>
			<version>1.3.4.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.4</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
				<exclusion>
					<groupId>xml-apis</groupId>
					<artifactId>xml-apis</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.1.0.Final</version>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>5.0.1.Final</version>
		</dependency>

	</dependencies>
</project>