3
3

Spring Boot学習③~Spring Data JPAを使ってデータベースにアクセス~

Last updated at Posted at 2024-01-02

以下の動画を参考に、ハンズオン形式でSpring BootでWebアプリを制作していきます。

今回はPart8。
Spring Data JPAを使ってデータベースにアクセスします。

準備として、MySQLでIDとパスワードが入ったテーブルを準備しています。

スクリーンショット 2023-12-28 162817.png

今回やることとしては、ログインフォームに入力された値とuser_infoテーブルの中のデータを照合して画面の表示を変えます。

Spring Data JPAの導入に関しては、以下のサイトが分かりやすいです。

まず、DBとの接続設定をしてあげましょう。
ほとんどテンプレ化しているようなので、調べれば出てきます。
今回はMySQLとの接続です。
接続設定はapplication.propertiespom.xmlの二つにコードを追加する必要があります。

application.properties

application.properties
spring.datasource.url=jdbc:mysql://localhost/spring_dev
spring.datasource.username=devUser01
spring.datasource.password=mysql
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

上から順に
spring_devというスキーマを使うよ
ユーザー名はdevUser01だよ
パスワードはmysqlだよ
MySQLと接続するよ
って感じですね。

pom.xml

pom.xml
<!-- Spring Data JPA -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

spring-boot-starter-data-jpaはデータアクセス関連のAPIです。
この依存性注入を行うことで、次に紹介するエンティティやレポジトリを利用することができます。

DBの操作を行うには、以下の二つのパッケージが必要です。
①エンティティ
②レポジトリ

エンティティとは、DBのテーブルに対応したパッケージです。
MySQLの特定のスキーマと接続しただけでは、その中にあるテーブルを利用することはできません。
テーブル一つにつきエンティティを一つ作ってあげて、MySQLの中にはこんなテーブルがあるんだよーと紹介してあげる必要があります。

一方でレポジトリとは、データベースとの対話をしてくれる存在です。
データベースへのアクセスやCRUD操作などは、このレポジトリを用意することで可能になります。

それぞれコードを見てみましょう。

エンティティ

UserInfo.java
@Entity
@Table(name = "user_info")
@data_mom 
public class UserInfo {
	@Id
	@Column(name = "login_id")
	private String loginId;
	
	private String password;

}

@Entityとアノテーションすることで、その下のクラスがエンティティとして定義されます。
@Table(name = "user_info")では、user_infoというテーブルを使いますよーと宣言。
@Dataは例のごとく、便利メソッドの追加です。

クラス内の@Idはそのテーブルの主キーはこれだよーというお知らせです。
@Columnは、変数名とカラム名が異なる時に修正するための手段です。変数名とカラム名が一致している場合(今回のpasswordのように)は何も書かなくても自動で理解してくれますが、少しでも異なるとわかんないよー状態になります。
login_idというカラムをloginIdというJavaの命名規則に従って宣言するために必要なアノテーションです。

以上で、spring_devスキーマ内のuser_infoテーブルのデータがどのようなものかを分からせてやりました。

レポジトリ

UserInfoRepository.java
@Repository
public interface UserInfoRepository extends JpaRepository<UserInfo,String>{

}

レポジトリでは、データ操作を行うためのコードを追加します。
といっても、今回はたった1行なので簡単です。
作るレポジトリは、JpaRepositoryというインターフェースを拡張したものです。

JpaRepositoryはデータ操作に必要なメソッドをもったインターフェースです。ダイヤモンド演算子の中でデータ操作したエンティティ名とその主キーの型を指定することで、事前にもっているメソッドの中身をそのエンティティ専用に書き換えてくれます。

なので今回は、UserInfoというエンティティ(主キーの型はloginIdString)を操作するUserInfoRepositoryインターフェースを作ったぜということです。

エンティティとレポジトリを作ったことで、user_infoテーブルの操作を行えるようになりました=!

今回行いたいのは、フォームに記入されたログインIDがDBに存在するのか、存在したときにはパスワードとの組み合わせが一致しているのかを確かめることです。

なので、まずはログインIDがuser_info内に存在するかを確認するためのパッケージを作成します。

LoginService.java

LoginService.java
@Service
@RequiredArgsConstructor
public class LoginService {
	
	private final UserInfoRepository repository;
	
	public Optional<UserInfo> searchUserById(String loginId){
		return repository.findById(loginId);
	}

}

まず、サービスクラスには@Serviceというアノテーションを付けます。
これによって、このクラスがレポジトリとコントローラーを繋ぐサービスクラスであることがSpringに伝わります。(伝わることの効用は少し難しいので省略します)

次に、private final UserInfoRepository repository;で先ほど作ったレポジトリのフィールドを宣言します。
この時に、@RequiredArgsConstructorとアノテーションをつけ、final修飾子をつけることで、LoginServiceクラスのコンストラクタが生成される際に、引数にUserInfoRepository repositoryが追加されます。

最後に、ID検索のメソッドを追加します。

戻り値の型がOptional<UserInfo>なのは、検索したIDが存在しなかった場合にnullが返ってくる可能性があるからです。
String型などでnullが返ってくるとヌルポインターエラーになる可能性がありますが、Optional<UserInfo>にしておけばOptional.empty()と値が存在しないことを正確に教えてくれるため、エラーなどにも対応しやすくなります。

searchUserByIdとメソッド名を名づけ、引数には画面で入力されるIDを受け取ります。

メソッドの中身の部分は、‘repository.findById(loginId);で入力された値が存在するかを確かめます。 findByIdはSpring Data JPAで用意されているメソッドで、引数の値が、参照しているテーブルに存在するかを確かめます。 存在する場合はtrue、しない場合はOptional.empty()`を返します。

これで準備は整いました。
IDの判別をログインコントローラに追加しましょう。

LoginController

LoginController.java
@Controller
@RequiredArgsConstructor
public class LoginController {
	
	private final LoginService service;

	@GetMapping("/login")
	public String view(Model model, LoginForm form) {
		
		return "login"; //login.htmlをする
	}
	
	@PostMapping("/login")
	public String login(Model model, LoginForm form) {
		var userInfo = service.searchUserById(form.getLoginId());
		var isCorrectUserAuth = userInfo.isPresent() 
				&& form.getPassword().equals(userInfo.get().getPassword());
		if(isCorrectUserAuth) {
			return "redirect:/menu";
		}else {
			model.addAttribute("errorMsg","IDとPASSの組み合わせが間違っています。");
			return "login";
		}
	}
}

コントローラクラスにも@RequiredArgsConstructorをつけて、コンストラクタの引数にLoginService serviceを追加します。
こうすることで、コンストラクタの再定義をおこなったり、LoginController内でLoginServiceのインスタンス化を行う必要がありません。

主に追加した部分は以下です。

LoginController.java
	
	@PostMapping("/login")
	public String login(Model model, LoginForm form) {
		var userInfo = service.searchUserById(form.getLoginId());
		var isCorrectUserAuth = userInfo.isPresent() 
				&& form.getPassword().equals(userInfo.get().getPassword());
		if(isCorrectUserAuth) {
			return "redirect:/menu";
		}else {
			model.addAttribute("errorMsg","IDとPASSの組み合わせが間違っています。");
			return "login";
		}
	}
}

var userInfo = service.searchUserById(form.getLoginId());
で、ログインフォームに記入されたLoginIdのエンティティをuserInfoに代入しています。

var isCorrectUserAuth = userInfo.isPresent() && form.getPassword().equals(userInfo.get().getPassword());
では、上のuserInfoが存在しているかどうか、そして、存在している場合は&&以下に続き、フォームに入力されたパスワードとエンティティのパスワードが一致しているかを確かめます。

どちらもtrueならisCorrectUserAuthtrueとなります。

if文以下は前回と変わりません。
完全に一致している場合はメニュー画面にリダイレクトし、それ以外はログイン画面に文言が追加されて表示されます。

次→https://qiita.com/19960417akiho/items/4f89cf51b69125c4cdc9

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3