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>