11月25日

SpringBoot アプリケーションの起動方法

プロジェクトを右クリックして[実行]-[Spring Boot アプリケーション]を選択することでWebアプリケーションを起動できる。

が。

[実行]のサブメニューから[SpringBootアプリケーション]が消えてしまうことがある。

その場合は、[実行]-[mvn ビルド…]を選択し、ゴールに「spring-boot:run」と入力して「実行」をクリックする。

※[実行]-[Spring Boot アプリケーション]を選択するとバックグラウンドで「mvn spring-boot:run」コマンドが実行されている。

コミットメッセージに課題キーを書き忘れたとき

以下の手順で、課題のコメントに「リビジョン詳細へのリンク」を追加する。

  1. BacklogでGitの画面に進む。
  2. 「最近の更新」または「コミット履歴」から、課題キーを書き忘れたコミットを探す。
  3. リビジョンID(10桁の英数字)をクリックする
  4. リビジョン詳細へのリンクをコピーする
  5. そのコミットが対応する課題を開く
  6. コメントにコピーした「リビジョン詳細へのリンク」を貼り付ける

11月21日

CSSやJSファイルが読み込まれない場合は、ブラウザがキャッシュされているファイルを使っている可能性が高い。
そのような場合は、強制的に再読み込みを行う。
SHIFT+F5 まはた SHIFT を押しながら再読み込みボタンをクリックすることで、キャッシュが更新される。

9月9日

ACID特性

Atomicity・Consistency・Isolation・Durabilityを考慮してプログラミングしよう。

入力フィールドのチェックを username と password で分割する。(Atomicity)

$(function() {
	$('[type=submit]').attr('disabled', true);
	$('[name=username]').on('keyup', function() {
		checkUserNameField();
	});
	$('[type=password]').on('keyup', function() {
		checkPasswordField();
	});
});

function checkUserNameField() {
	var name = $('[name=username]').val();
	if (name.length == 0) {
		$('[type=submit]').attr('disabled', true);
		$('div.err').text('ユーザー名を入力してください。');
		return;
	}
	$('div.err').text('');
	$('[type=submit]').attr('disabled', false);
}

function checkPasswordField() {
	var p1 = $('[name=password]').val();
	var p2 = $('[name=password2]').val();
	if (p1 != p2) {
		$('div.err').text('パスワードが一致していません。');
		$('[type=submit]').attr('disabled', true);
		return;
	}
	$('div.err').text('');
	$('[type=submit]').attr('disabled', false);
}

ログインしたユーザー名を表示する

マイページでは、ログインしたユーザー名を表示してみよう。
メソッドに Principal 引数を追加すると、ログインしたユーザーに関する情報をもらえる。

MyController.java

	@RequestMapping(value = "/mypage")
	public ModelAndView top(ModelAndView mav, Principal p) {
		mav.setViewName("mypage");
		mav.addObject("username", p.getName());
		return mav;
	}

HTMLテンプレートで受け取った username を表示する。

mypage.html

<body>
    <h1>マイページ</h1>
    <p>ようこそ、<span th:text="${username}"></span>さん!</p>
    <form th:action="@{/logout}" method="post">
        <input type="submit" value="ログアウト" />
    </form>
</body>

ユーザーの情報を持たせるために Profile クラスを作成する。

Profile.java

package jp.abc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class Profile {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column
    @NotNull
    private long id;

    @Column(length = 200, nullable = false)
    @NotEmpty
    private String username;

    @Column
    private String profile;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getProfile() {
		return profile;
	}

	public void setProfile(String profile) {
		this.profile = profile;
	}

}

エンティティを作ったので対応するリポジトリを作成する。

ProfileRepository.java

package jp.abc;

import org.springframework.data.jpa.repository.JpaRepository;

public interface ProfileRepository extends JpaRepository<Profile, Long> {

}

Principal からは username しか取得できないので、 username をもとに Profile を取得するメソッドをリポジトリに追加する。

package jp.abc;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;

public interface ProfileRepository extends JpaRepository<Profile, Long> {
	public Optional<Profile> findByUsername(String username);
}

コントローラで、Profileを検索してみて、なかったら新規登録する。

	@RequestMapping(value = "/mypage")
	public ModelAndView top(ModelAndView mav, Principal p) {
		mav.setViewName("mypage");
		mav.addObject("username", p.getName());
		Optional<Profile> data = repository.findByUsername(p.getName());
		Profile profile = data.get();
		if (profile == null) {
			profile = new Profile();
			profile.setUsername(p.getName());
			repository.saveAndFlush(profile);
		}
		mav.addObject("profile", profile);
		return mav;
	}

HTMLテンプレートでは、profile の情報も表示してみる。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>login</title>
</head>
<body>
    <h1>マイページ</h1>
    <p>ようこそ、<span th:text="${username}"></span>さん!</p>
    <p th:text="${profile.username}"></p>
    <form th:action="@{/logout}" method="post">
        <input type="submit" value="ログアウト" />
    </form>
</body>
</html>

コントローラのコードが悪かったようで、例外が発生した。

java.util.NoSuchElementException: No value present
	at java.util.Optional.get(Optional.java:135) ~[na:1.8.0_152]
	at jp.abc.MyController.top(MyController.java:59) ~[classes/:na]

値が存在しないときは Optional#get() を呼んではいけないらしいので、コードを書き換える。

	@RequestMapping(value = "/mypage")
	public ModelAndView top(ModelAndView mav, Principal p) {
		mav.setViewName("mypage");
		mav.addObject("username", p.getName());
		Optional<Profile> data = repository.findByUsername(p.getName());
		Profile profile;
		if (!data.isPresent()) {
			profile = new Profile();
			profile.setUsername(p.getName());
			repository.saveAndFlush(profile);
		} else {
			profile = data.get();
		}
		mav.addObject("profile", profile);
		return mav;
	}

Tweet クラスを作成する。

Tweet.java

package jp.abc;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class Tweet {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column
    @NotNull
    private long id;

    @Column(length = 200, nullable = false)
    @NotEmpty
    private String content;

    @Column(nullable = false)
    private Date time;

    @ManyToOne
    private Profile profile;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public Date getTime() {
		return time;
	}

	public void setTime(Date time) {
		this.time = time;
	}

	public Profile getProfile() {
		return profile;
	}

	public void setProfile(Profile profile) {
		this.profile = profile;
	}
}

Profile と Tweet を連携する。

Profile.java

package jp.abc;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class Profile {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column
    @NotNull
    private long id;

    @Column(length = 200, nullable = false)
    @NotEmpty
    private String username;

    @Column
    private String profile;

    @OneToMany
    private List<Tweet> tweets;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getProfile() {
		return profile;
	}

	public void setProfile(String profile) {
		this.profile = profile;
	}

	public List<Tweet> getTweets() {
		return tweets;
	}

	public void setTweets(List<Tweet> tweets) {
		this.tweets = tweets;
	}

}

HTMLテンプレートに投稿用フォームを追加する。

mypage.html

<body>
    <h1>マイページ</h1>
    <p>ようこそ、<span th:text="${username}"></span>さん!</p>
    <p th:text="${profile.username}"></p>
    <form th:action="@{/tweet}" th:object="${tweet}">
    	<textarea name="content" cols="40" rows="10"></textarea>
    	<br />
    	<input type="submit" value="ツイートする" />
    </form>
    <form th:action="@{/logout}" method="post">
        <input type="submit" value="ログアウト" />
    </form>
</body>

9月5日

ユーザー登録のバリデーション

パスワードは確認のために二回入力させる。
新規ユーザー登録で、登録できないときはエラーを表示する。

  • すでに登録済みのユーザー名の場合
  • パスワードが不一致の場合

以下のコードでパスワードの不一致のエラーを表示できる。
ただし、登録ボタンを押せるので、登録はできてしまう。
不一致のときは、登録ボタンを押せないようにする必要がある。

newuser.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>新規ユーザー登録</title>
    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
</head>
<style type="text/css">
.err {
	background: #ff8080;
}
</style>
<script type="text/javascript">
$(function() {
	$('[type=password]').on('change', function() {
		var p1 = $('[name=password]').val();
		var p2 = $('[name=password2]').val();
		if (p1 != p2) {
			$('div.err').text('パスワードが一致していません。');
		} else {
			$('div.err').text('');
		}
	});
})
</script>
<body>
    <h1>新規ユーザー登録</h1>
    <form th:action="@{/newuser}" method="post">
        <div><label>ユーザ名: <input type="text" name="username"/> </label></div>
        <div><label>パスワード: <input type="password" name="password"/> </label></div>
        <div><label>パスワード再入力: <input type="password" name="password2"/> </label></div>
        <div class="err"></div>
        <div><input type="submit" value="登録"/></div>
    </form>
    <a href="/">戻る</a>
</body>
</html>

ユーザーをデータベースに登録するときのエラー
データベース登録時のエラーはサーバーサイドでチェックする。

package jp.abc;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.User.UserBuilder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class MyController {
	@Autowired
	private JdbcUserDetailsManager userManager;

	@RequestMapping(value = "/")
	public String index() {
		return "index";
	}

	@RequestMapping(value = "/login")
	public String login() {
		return "login";
	}

	@RequestMapping(value = "/newuser", method = RequestMethod.GET)
	public String newuser() {
		return "newuser";
	}

	@RequestMapping(value = "/newuser", method = RequestMethod.POST)
	public String register(@RequestParam("username") String username,
			@RequestParam("password") String password,
			HttpServletRequest req) {
		UserBuilder users = User.withDefaultPasswordEncoder();
		try {
			userManager.createUser(users.username(username).password(password).roles("USER").build());
		} catch (Exception e) {
			req.setAttribute("msg", "その名前は登録できません。");
			return "newuser";
		}
		return "login";
	}

	@RequestMapping(value = "/mypage")
	public String top() {
		return "mypage";
	}
}

HTMLテンプレートにエラーメッセージを表示するコードを追加する。

<body>
    <h1>新規ユーザー登録</h1>
    <form th:action="@{/newuser}" method="post">
        <div><label>ユーザ名: <input type="text" name="username"/> </label></div>
        <div><label>パスワード: <input type="password" name="password"/> </label></div>
        <div><label>パスワード再入力: <input type="password" name="password2"/> </label></div>
        <div class="err" th:text="${msg}"></div>
        <div><input type="submit" value="登録"/></div>
    </form>
    <a href="/">戻る</a>
</body>

パスワードの1文字を入力するたびに不一致のエラーを表示する。
newuser.html

<script type="text/javascript">
$(function() {
	$('[type=password]').on('keyup', function() {
		var p1 = $('[name=password]').val();
		var p2 = $('[name=password2]').val();
		if (p1 != p2) {
			$('div.err').text('パスワードが一致していません。');
		} else {
			$('div.err').text('');
		}
	});
})

パスワード不一致
パスワードの不一致の場合や、ユーザー名が空欄のときは登録ボタンを押せないようにする。

<script type="text/javascript">
$(function() {
	$('[type=password]').on('keyup', function() {
		var p1 = $('[name=password]').val();
		var p2 = $('[name=password2]').val();
		if (p1 != p2) {
			$('div.err').text('パスワードが一致していません。');
			$('[type=submit]').attr('disabled', true);
		} else {
			$('div.err').text('');
			var name = $('[name=username]').val();
			if (name != '') {
				$('[type=submit]').attr('disabled', false);
			}
		}
	});
})
</script>

パスワードが一致しているときにユーザー名を入力しても登録ボタンを押せないままなので、そこを改善する。

newuser.html

<script type="text/javascript">
$(function() {
	$('[type=submit]').attr('disabled', true);
	$('[name=username]').on('keyup', function() {
		checkFields();
	});
	$('[type=password]').on('keyup', function() {
		checkFields();
	});
});

function checkFields() {
	var name = $('[name=username]').val();
	if (name.length == 0) {
		$('[type=submit]').attr('disabled', true);
		$('div.err').text('ユーザー名を入力してください。');
		return;
	}
	var p1 = $('[name=password]').val();
	var p2 = $('[name=password2]').val();
	if (p1 != p2) {
		$('div.err').text('パスワードが一致していません。');
		$('[type=submit]').attr('disabled', true);
		return;
	}
	$('div.err').text('');
	$('[type=submit]').attr('disabled', false);
}
</script>

9月2日

ログイン認証

プロジェクト名: tweeter
パッケージ名: jp.abc

pom.xmlにTymeleafとJPAとHSQLDBの依存関係を追加する。
Spring Boot のバージョンを2.1.4にする。

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.4.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>jp.abc</groupId>
	<artifactId>tweeter</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>tweeter</name>
	<description>Tweeter</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>

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

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

HSQLDBを起動するBATファイルを修正する。tweeter インスタンスを追加する。

cd C:\pleiades\hsqldb-2.4.1\hsqldb\lib
java -cp hsqldb.jar org.hsqldb.Server --database.0 db/tweeter --dbname.0 tweeter

application.properties にHSQLDBの設定を追加する。

spring.datasource.url=jdbc:hsqldb:hsql://localhost/tweeter
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect
spring.jpa.hibernate.ddl-auto=update

Spring Boot でJDBCを使ってユーザー登録・ユーザー認証する方法

4つのHTMLテンプレートを作成する。

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>トップページ</title>
</head>
<body>
    <h1>トップページ</h1>
    <a href="/mypage">マイページ</a>
</body>
</html>

mypage.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>login</title>
</head>
<body>
    <h1>マイページ</h1>
    <form th:action="@{/logout}" method="post">
        <input type="submit" value="ログアウト" />
    </form>
</body>
</html>

login.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>login</title>
</head>
<body>
    <div th:if="${param.error}">
        エラー: ユーザ名・パスワードが違います。
    </div>
    <form th:action="@{/login}" method="post">
        <div><label>ユーザ名: <input type="text" name="username"/> </label></div>
        <div><label>パスワード: <input type="password" name="password"/> </label></div>
        <div><input type="submit" value="ログイン"/></div>
    </form>
    <div><a href="/newuser">新規ユーザー登録</a></div>
    <a href="/">戻る</a>
</body>
</html>

newuser.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>新規ユーザー登録</title>
</head>
<body>
    <h1>新規ユーザー登録</h1>
    <form th:action="@{/newuser}" method="post">
        <div><label>ユーザ名: <input type="text" name="username"/> </label></div>
        <div><label>パスワード: <input type="password" name="password"/> </label></div>
        <div><label>パスワード再入力: <input type="password" name="password2"/> </label></div>
        <div><input type="submit" value="登録"/></div>
    </form>
    <a href="/">戻る</a>
</body>
</html>

コントローラを作成する。
MyController.java

package jp.abc;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MyController {
    @RequestMapping(value = "/")
    public String index() {
        return "index";
    }

    @RequestMapping(value = "/login")
    public String login() {
        return "login";
    }

    @RequestMapping(value = "/newuser")
    public String newuser() {
        return "newuser";
    }

    @RequestMapping(value = "/mypage")
    public String top() {
        return "mypage";
    }
}

WebSecurityConfig クラスを作成する。

package jp.abc;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/", "/newuser").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
            .logout()
            .permitAll();
    }
}

WebSecurityConfig にデータベース認証のコードを追加する。

package jp.abc;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.User.UserBuilder;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
	@Autowired
	private DataSource dataSource;

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		UserBuilder users = User.withDefaultPasswordEncoder();
		auth
		.jdbcAuthentication()
		.dataSource(dataSource)
		.withDefaultSchema()
		.withUser(users.username("user").password("password").roles("USER"));
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
		.antMatchers("/", "/newuser").permitAll()
		.anyRequest().authenticated()
		.and()
		.formLogin()
		.loginPage("/login")
		.permitAll()
		.and()
		.logout()
		.permitAll();
	}
}

このコードで起動すると、1度目は正常に起動するが、再起動すると例外が発生して起動できなくなる。
例外の原因が withDefaultScheme() と withUser() なので、その部分を削除する。

WebSecurityConfig.java

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth
		.jdbcAuthentication()
		.dataSource(dataSource);
	}

コントローラで新規ユーザー登録のPOSTメソッドを受け付けるようにする。

package jp.abc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.User.UserBuilder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class MyController {
	@Autowired
	private JdbcUserDetailsManager userManager;

	@RequestMapping(value = "/")
	public String index() {
		return "index";
	}

	@RequestMapping(value = "/login")
	public String login() {
		return "login";
	}

	@RequestMapping(value = "/newuser", method = RequestMethod.GET)
	public String newuser() {
		return "newuser";
	}

	@RequestMapping(value = "/newuser", method = RequestMethod.POST)
	public String register(@RequestParam("username") String username,
			@RequestParam("password") String password) {
		UserBuilder users = User.withDefaultPasswordEncoder();
		userManager.createUser(users.username(username).password(password).roles("USER").build());
		return "login";
	}

	@RequestMapping(value = "/mypage")
	public String top() {
		return "mypage";
	}
}

この状態で起動しようとするとエラーが発生して起動に失敗する。

***************************
APPLICATION FAILED TO START
***************************

Description:

Field userManager in jp.abc.MyController required a bean of type 'org.springframework.security.provisioning.JdbcUserDetailsManager' that could not be found.

The injection point has the following annotations:
	- @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'org.springframework.security.provisioning.JdbcUserDetailsManager' in your configuration.

JdbcUserDetailManager のビーンを設定に用意しろと言われているので、その設定を追加する。

WebSecurityConfig.java

	@Bean
	public JdbcUserDetailsManager jdbcUserDetailsManager() throws Exception {
		JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager();
		jdbcUserDetailsManager.setDataSource(dataSource);
		return jdbcUserDetailsManager;
	}

設定を追加した後に再起動すると、エラーなく起動できる。
ユーザー登録とログインもできるようになっていて、ログインすればマイページにアクセスできる。

8月26日

BookshelfとBookを連携する

src/main/java/
└jp.abc
 └Bookshelf.java

package jp.abc;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class Bookshelf {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String name;

	@OneToMany
	private List<Book> books;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public List<Book> getBooks() {
		return books;
	}

	public void setBooks(List<Book> books) {
		this.books = books;
	}
}

src/main/java/
└jp.abc
 └Book.java

package jp.abc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class Book {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String title;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String author;

	@ManyToOne
	private Bookshelf bookshelf;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public Bookshelf getBookshelf() {
		return bookshelf;
	}

	public void setBookshelf(Bookshelf bookshelf) {
		this.bookshelf = bookshelf;
	}

}

HTMLテンプレートを修正する。

src/main/resources/
└templates
 └book.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Book</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>
<h1>Book</h1>
<p th:text="${msg}"></p>
<form method="post" action="/book" th:object="${formModel}">
  <table>
    <tr>
      <td><label for="title">タイトル</label></td>
      <td>
        <input type="text" name="title" th:value="*{title}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('title')}" th:errors="*{title}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td><label for="author">著者</label></td>
      <td>
        <input type="text" name="author" th:value="*{author}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('author')}" th:errors="*{author}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td><label for="bookshelf">本棚</label></td>
      <td>
        <input type="text" name="bookshelf" th:value="*{bookshelf}"
                th:errorclass="err"/>
        <div th:if="${#fields.hasErrors('bookshelf')}" th:errors="*{bookshelf}"
            th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

<hr />
<table>
  <tr>
    <th>ID</th><th>タイトル</th><th>著者</th><th>本棚</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.title}"></td>
    <td th:text="${obj.author}"></td>
    <td th:if="${obj.bookshelf != null}" th:text="${obj.bookshelf.name}"></td>
    <td th:if="${obj.bookshelf == null}" th:text="本棚なし"></td>
  </tr>
</table>

</body>
</html>

本を編集できるようにする

HTMLテンプレートを用意する。

src/main/resources/
└templates
 └edit.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>本の編集</title>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
pre {
  border: solid 3px #ddd;
  padding: 10px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
</style>
</head>
<body>

<h1>本の編集</h1>

<form method="post" action="/edit" th:object="${formModel}">
  <input type="hidden" name="id" th:value="*{id}" />
  <table>
    <tr>
      <td><label for="title">タイトル</label></td>
      <td><input type="text" name="title" th:value="*{title}" /></td>
    </tr>
    <tr>
      <td><label for="artist">著者</label></td>
      <td><input type="text" name="author" th:value="*{author}" /></td>
    </tr>
    <tr>
      <td><label for="bookshelf">本棚</label></td>
      <td th:if="*{bookshelf != null}">
        <input type="text" name="bookshelf" th:value="*{bookshelf.id}" />
      </td>
      <td th:if="*{bookshelf == null}">
        <input type="text" name="bookshelf" value="" />
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>


</body>
</html>

コントローラに編集画面へのマッピングを追加する。

src/main/java/
└jp.abc
 └BookController.java

	@RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
	public ModelAndView edit(@ModelAttribute Book book,
	        @PathVariable long id,
	        ModelAndView mav) {
	    mav.setViewName("edit");
	    mav.addObject("title", "edit music");
	    Optional<Book> data = repository.findById(id);
	    mav.addObject("formModel", data.get());
	    return mav;
	}

POSTメソッドを受け取れるようにする。

	@RequestMapping(value = "/edit", method = RequestMethod.POST)
	public ModelAndView form(@ModelAttribute @Validated Book book,
	        Errors result,
	        ModelAndView mav) {
	    if (result.hasErrors()) {
	        return mav;
	    }
	    repository.saveAndFlush(book);
	    return new ModelAndView("redirect:/book");
	}

book.html に編集と削除のリンクを追加する。

src/main/resources/
└templates
 └book.html

<hr />
<table>
  <tr>
    <th>ID</th><th>タイトル</th><th>著者</th><th>本棚</th><th>編集</th><th>削除</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.title}"></td>
    <td th:text="${obj.author}"></td>
    <td th:if="${obj.bookshelf != null}" th:text="${obj.bookshelf.name}"></td>
    <td th:if="${obj.bookshelf == null}" th:text="本棚なし"></td>
    <td><a th:href="@{'/edit/' + ${obj.id}}">編集</a></td>
    <td><a th:href="@{'/delete/' + ${obj.id}}">削除</a></td>
  </tr>
</table>

本を削除できるようにする

src/main/resources/
└templates
 └delete.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>本の削除</title>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
pre {
  border: solid 3px #ddd;
  padding: 10px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
</style>
</head>
<body>

<h1>本の削除</h1>

<form method="post" action="/delete" th:object="${formModel}">
  <input type="hidden" name="id" th:value="*{id}" />
  <table>
    <tr><td><p th:text="|タイトル : *{title}|"></p></td></tr>
    <tr><td><p th:text="|著者 : *{author}|"></p></td></tr>
    <tr><td><input type="submit" value="削除" /></td></tr>
  </table>
</form>


</body>
</html>

コントローラに削除ページへのマッピングを追加する。

src/main/java/
└jp.abc
 └BookController.java

	@RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
	public ModelAndView delete(@PathVariable int id,
	        ModelAndView mav) {
	    mav.setViewName("delete");
	    mav.addObject("title", "本の削除");
	    Optional<Book> data = repository.findById((long)id);
	    mav.addObject("formModel", data.get());
	    return mav;
	}

	@RequestMapping(value = "/delete", method = RequestMethod.POST)
	public ModelAndView remove(@RequestParam long id,
	        ModelAndView mav) {
	    repository.deleteById(id);
	    return new ModelAndView("redirect:/book");
	}

8月22日

Bookshelfを登録できるようにする

Repositoryを作成する。

src/main/java/
└jp.abc
 └BookshelfRepository.java

package jp.abc;

import org.springframework.data.jpa.repository.JpaRepository;

public interface BookshelfRepository extends JpaRepository<Bookshelf, Long> {

}

コントローラがPOSTメソッドを受け取れるようにする。

src/main/java/
└jp.abc
 └BookshelfController.java

package jp.abc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class BookshelfController {

	@Autowired
	private BookshelfRepository repository;

	@RequestMapping(value = "/bookshelf", method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("bookshelf");
		mav.addObject("formModel", new Bookshelf());
		mav.addObject("datalist", repository.findAll());
		return mav;
	}

	@RequestMapping(value = "/bookshelf", method = RequestMethod.POST)
	public ModelAndView post(
			@ModelAttribute("formModel") @Validated Bookshelf bookshelf,
			Errors errors,
			ModelAndView mav) {
		if (errors.hasErrors()) {
			mav.addObject("msg", "エラーですよ");
			return mav;
		}
		repository.saveAndFlush(bookshelf);
		return new ModelAndView("redirect:/bookshelf");
	}
}

データベース接続設定を application.properties に記述する。

src/main/resources/
└application.properties

spring.datasource.url=jdbc:hsqldb:hsql://localhost/bookshelf
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect
spring.jpa.hibernate.ddl-auto=update

本棚に収納するための本のクラス Book を作成する。

src/main/java/
└jp.abc
 └Book.java

package jp.abc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class Book {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String title;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String author;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

}

Book用のHTMLテンプレートを作成する。

src/main/resources/
└templates
 └book.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Book</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>
<h1>Book</h1>
<p th:text="${msg}"></p>
<form method="post" action="/book" th:object="${formModel}">
  <table>
    <tr>
      <td><label for="title">タイトル</label></td>
      <td>
        <input type="text" name="title" th:value="*{title}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('title')}" th:errors="*{title}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td><label for="author">著者</label></td>
      <td>
        <input type="text" name="author" th:value="*{author}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('author')}" th:errors="*{author}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

<hr />
<table>
  <tr>
    <th>ID</th><th>タイトル</th><th>著者</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.title}"></td>
    <td th:text="${obj.author}"></td>
  </tr>
</table>

</body>
</html>

Book用のリポジトリを作成する。
src/main/java/
└jp.abc
 └BookRepository.java

package jp.abc;

import org.springframework.data.jpa.repository.JpaRepository;

public interface BookRepository extends JpaRepository<Book, Long> {

}

Book用のコントローラを作成する。

src/main/java/
└jp.abc
 └BookController.java

package jp.abc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class BookController {

	@Autowired
	private BookRepository repository;

	@RequestMapping(value = "/book", method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("book");
		mav.addObject("formModel", new Book());
		mav.addObject("datalist", repository.findAll());
		return mav;
	}

	@RequestMapping(value = "/book", method = RequestMethod.POST)
	public ModelAndView post(
			@ModelAttribute("formModel") @Validated Book book,
			Errors errors,
			ModelAndView mav) {
		if (errors.hasErrors()) {
			mav.addObject("msg", "エラーですよ");
			return mav;
		}
		repository.saveAndFlush(book);
		return new ModelAndView("redirect:/book");
	}
}

8月19日

Spring Bootの復習

簡単なWebアプリを作成してみる。

プロジェクト名: bookshelf
パッケージ名: jp.abc

プロジェクトを作成すると、pom.xml内でのSpringBootのバージョンが2.1.7になっているが、そのままではビルドエラーになるので、これを2.1.4に変更する。

BookshelfエンティティとBookエンティティを作成する。

Bookshelfのプロパティは name のみ。

Bookのプロパティは title と author の二つ。

作成するページ

  • トップページ http://localhost:8080/
  • Bookshelfページ http://localhost:8080/bookshelf
  • Bookページ http://localhost:8080/book

ビルドでエラーが出る人は、サーバーの 
 授業資料・OC資料\澤田\2019_SpringBOOT\repository
を、
 ユーザー\.m2
に上書きしてみる。

pom.xmlの変更
7月2日のページを参照して、pom.xmlを変更する。
ThymeleafとJPAとHSQLDBの依存関係を追加する。

データベースの用意
デスクトップに作成したhsqldb.batを編集して bookshelf インスタンスを用意する。

cd C:\pleiades\hsqldb-2.4.1\hsqldb\lib
java -cp hsqldb.jar org.hsqldb.Server --database.0 db/mydata --dbname.0 mydata --database.1 db/bookshelf --dbname.1 bookshelf

トップページを作成する

src/main/resources/
└templates
 └index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>top page</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
</style>
</head>
<body>

<h1>top page</h1>

</body>
</html>

トップページを表示するためのコントローラを作成する

src/main/java/
└jp.abc
 └IndexController.java

package jp.abc;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class IndexController {
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		return mav;
	}

}

Bookshelf(本棚)を作成する

HTMLテンプレートを作成する。

src/main/resources/
└templates
 └bookshelf.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Bookshelf</title>
<style type="text/css">
h1 {
  font-size: 18pt;
  font-weight: bold;
  color: gray;
}
body {
  font-size: 13pt;
  color: gray;
  margin: 5px 25px;
}
tr {
  margin: 5px;
}
th {
  padding: 5px;
  color: white;
  background: darkgray;
}
td {
  padding: 5px;
  color: black;
  background: #f0f0f0;
}
.err {
  color: red;
}
</style>
</head>
<body>
<h1>Bookshelf</h1>
<p th:text="${msg}"></p>
<form method="post" action="/bookshelf" th:object="${formModel}">
  <table>
    <tr>
      <td><label for="name">名前</label></td>
      <td>
        <input type="text" name="name" th:value="*{name}"
      			th:errorclass="err" />
      	<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"
      		th:errorclass="err"></div>
      </td>
    </tr>
    <tr>
      <td></td>
      <td><input type="submit" /></td>
    </tr>
  </table>
</form>

<hr />
<table>
  <tr>
    <th>ID</th><th>名前</th>
  </tr>
  <tr th:each="obj : ${datalist}">
    <td th:text="${obj.id}"></td>
    <td th:text="${obj.name}"></td>
  </tr>
</table>

</body>
</html>

Bookshelfエンティティを作成する

src/main/java/
└jp.abc
 └Bookshelf.java

package jp.abc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Entity
public class Bookshelf {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

	@Column(length = 200, nullable = false)
	@NotEmpty
	private String name;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

コントローラを作成する

src/main/java/
└jp.abc
 └BookshelfController.java

package jp.abc;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class BookshelfController {
	@RequestMapping(value = "/bookshelf", method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("bookshelf");
		mav.addObject("formModel", new Bookshelf());
		mav.addObject("datalist", null);
		return mav;
	}

}

前期提出課題

プロジェクト

プロジェクト名: se3NN (NN は学籍番号の下2桁)
パッケージ名: jp.abc

MyBootApp と同様のWebアプリケーションを作成する。
MyDataのかわりに、Userクラスを作成し、MsgDataクラスの代わりに Tweetクラスを作成する。

作成するページとURL

トップページ: http://localhost:8080/
ユーザー一覧&ユーザー登録: http://localhost:8080/user/
ユーザー編集ページ: http://localhost:8080/edit/{id}
ツイート一覧&ツイート投稿: http://localhost:8080/tweet/

エンティティ

User
・id – Long
・name – String
・profile – String
・tweets – List<Tweet>
Tweet
・id – Long
・time – java.util.Date
・content – String
・user – User

作成するHTMLテンプレート

  • index.html : トップページ
  • user.html : ユーザー一覧&ユーザー登録ページ
  • edit.html : ユーザー編集ページ
  • tweet.html : ツイート一覧&ツイート投稿ページ

トップページの内容

  • titleとh1タグに番号と名前を書くこと
  • ユーザー一覧&ユーザー登録ページへのリンクを作成
  • ツイート一覧&ツイート投稿ページへのリンクを作成

ユーザー一覧&ユーザー登録ページの内容

  • titleとh1タグに番号と名前を書くこと
  • h1のすぐ下にトップページへのリンクを作成
  • 入力フォームで名前(name)と自己紹介(profile)を入力できる
  • 自己紹介はtextareaにすること
  • 名前は1文字以上30文字以下
  • 自己紹介は1文字以上200文字以下
  • 送信ボタンを表示
  • 入力フォームの下に、登録済みユーザー一覧を表示する
  • ユーザー一覧にはID、名前、編集ページへのリンクを表示する

ユーザー編集ページの内容

  • titleとh1タグに番号と名前を書くこと
  • h1のすぐ下にトップページへのリンクを作成
  • 入力フォームに編集前の名前と自己紹介を表示
  • 入力フォームで名前と自己紹介を入力できる
  • 送信ボタンを表示

ツイート一覧&投稿ページの内容

  • titleとh1タグに番号と名前を書くこと
  • h1のすぐ下にトップページへのリンクを作成
  • 入力フォームで投稿内容(content)を入力できる
  • 投稿は1文字以上140文字以下
  • 投稿欄はtextareaにすること
  • 送信ボタンを表示
  • 日時はフォームに用意せず、コントローラが現在時刻を設定する
  • 入力フォームの下に、投稿済みツイート一覧を表示する
  • 投稿一覧にはID、名前、日時、投稿内容を表示する

application.properties

spring.datasource.url=jdbc:hsqldb:hsql://localhost/se3NN  ←NNは学籍番号の下2桁
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect
spring.jpa.hibernate.ddl-auto=update

hsqldb.bat
データベースインスタンスを追加する。
インスタンス名は se3NN (NNは学籍番号の下2桁)

cd (hsqldbの置き場所)\lib
java -cp hsqldb.jar org.hsqldb.Server --database.0 db/mydata --dbname.0 mydata --database.1 db/se3NN --dbname.1 se3NN

課題提出方法

プロジェクトを作成したフォルダを、エクスプローラで開く。

フォルダ「se3NN」(NNは学籍番号の下2桁)を右クリックし、[送る]-[圧縮(zip 形式)フォルダー]を選択する。
se3NN.zip ファイルができるので、そのファイルを提出する。

提出先

サーバーの以下のフォルダに提出。

\\stfs\ABKC\課題提出用\澤田\2019_SE3\課題提出

配点

接続先データベースや、プロジェクト名、番号・名前の間違いは、他人のものをコピーしたと判断し0点。
コピペもOKだけど最低限ができてなければ論外。
Webサイトを作って納品してもサイト名や会社名が間違ってたら、まず次の仕事はない。

  1. トップページ : 10点
    • titleとh1に番号と名前
    • ユーザーページへのリンク
    • 投稿ページへのリンク
  2. ユーザー一覧&ユーザー登録(GET) : 10点
    • titleとh1に番号と名前
    • 入力フォーム
    • 送信ボタン
    • ユーザー一覧
    • トップページへのリンク
  3. ユーザー一覧&ユーザー登録(POST) : 10点
    • 名前のエラーチェック
    • 自己紹介のエラーチェック
    • エラーメッセージ
    • データベースに保存
  4. ユーザー編集(GET) : 10点
    • titleとh1に番号と名前
    • 入力フォーム
    • 送信ボタン
    • トップページへのリンク
  5. ユーザー編集(POST) : 10点
    • 名前のエラーチェック
    • 自己紹介のエラーチェック
    • エラーメッセージ
    • データベースに保存
  6. ツイート一覧&投稿(GET) : 10点
    • titleとh1に番号と名前
    • 入力フォーム
    • 送信ボタン
    • ツイート一覧
    • トップページへのリンク
  7. ツイート一覧&投稿(POST) : 10点
    • 投稿内容のエラーチェック
    • 現在時刻を自動設定
    • エラーメッセージ
    • データベースに保存
  8. ツイート一覧で投稿者名が表示される(エンティティの連携) : 10点
  9. エラーメッセージの日本語化(全部できていれば) : 10点
  10. ツイート投稿でSELECT/OPTIONでユーザーを選択できる : 10点
  11. ツイート一覧でIDと名前の下に投稿が表示される : 10点
  12. ツイート一覧で複数行投稿がきちんと表示される : 10点
  13. トップページに授業の感想・意見を書く : 1〜20点

※1〜8はプログラムで採点しています。なので、1〜8の部分点はありません。
※14の授業の感想・意見は参考になった度合いで加点します。
※配点の総合計は100点を超えてますが、最大は100点です。

提出期限

7月19日(金)17:00