1
1

More than 1 year has passed since last update.

#21 Spring Mybatisを利用したデータベース操作[2. INSERT]

Last updated at Posted at 2022-11-27

#21 Spring Mybatisを利用したデータベース操作[2. INSERT]

今回はMybatisを用いてデータの挿入を行っていきます。

前提条件

この記事はSpringの最低限の知識が必要になります。
また、なるべく分かりやすく書くつもりですが、この記事の目的は自分の勉強のアウトプットであるため所々説明は省略します。

前回まで

前回はMybatisを利用するための環境構築とOracleDBを用いたテーブル作成を行いました。

構築環境

  1. 各バージョン
    Spring Boot ver 2.7.5
    mybatis-spring-boot-starter ver 2.2.2
    Model Mapper ver 3.1.0
    jquery ver 3.6.1
    bootstrap ver 5.2.2
    webjars-locator ver 0.46
    thymeleaf-layout-dialect ver 3.0.0

  2. 依存関係
    image.png

今回行うこと

今回は以下の流れに沿って進めていきます。

  1. エンティティとは
    1. クラス名
    2. データベースへ値の引き渡し
    3. データベースから値の取得
  2. テーブル(M_USER)用のエンティティクラス(MUser.java)の作成
  3. テーブル(M_USER)用のリポジトリー(UserMapper.java)の作成
     1. Mapperとxmlのマッピング
     2. SQLとメソッドのマッピング
     3. メソッドの引数とSQLパラメータのマッピング
  4. UserMapper.xmlにSQLを記述
  5. サービスの処理の記述
    1. UserService.java(インターフェース)
    2. UserServiceImpl.java(実装クラス)
  6. ModelMapperをBeanに登録
  7. コントローラー(SignupController.java)の修正

1. エンティティとは

エンティティはテーブルの1行に対応するクラスです。エンティティに定義されたフィールドはテーブルのカラム値に対応します。

1. クラス名

エンティティのクラス名は対応するデータベースのテーブルと同じ名前にすることが多い

2. データベースへ値の引き渡し

データベースへ値の挿入、更新をする際に、エンティティに値を入れ引き渡す

3. データベースから値の取得

データベースから値を取得した場合に、値をエンティティに保持しておく

2. テーブル(M_USER)用のエンティティクラス(MUser.java)の作成

テーブル(M_USER)に対応させるためのエンティティクラス(MUser.Java)を作成します。

MUser.java
package com.example.model;

import java.util.Date;
import org.springframework.web.multipart.MultipartFile;
import lombok.Data;

@Data
public class MUser {

	private String userId; 
	private Integer phoneNumber; 
	private Integer postalNumber1;
	private Integer postalNumber2;
	private String address;
	private String userName;
	private String password;
	private Date birthday1;
	private Date birthday2;
	private Integer age;
	private byte[] accountIcon;
	private Integer gender;
}

byte[]:画像を取り込む場合、エンティティクラスのデータ型はbyte[]を使用する

3. テーブル(M_USER)用のリポジトリー(UserMapper.java)の作成

リポジトリーとはデータベースのデータ操作を行うクラスです。リポジトリーを作成する場合、特定の実装への依存を回避するために必ずインテーフェースを定義した上で実装します。

Mybatisでリポジトリーを作成するには、インターフェースに@Mapperを付与します。

UserMapper.java
package com.example.repository;

import org.apache.ibatis.annotations.Mapper;
import com.example.model.MUser;

@Mapper
public interface UserMapper {
	
	/* ユーザー登録 */
	public int insertOne(MUser user);
}

4. UserMapper.xmlにSQLを記述

次にUserMapper.xmlに内容を記述します。

UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- Mapperとxmlのマッピング -->
<mapper namespace="com.exeample.repository.UserMapper">
	
	<!-- ユーザー1件登録 -->
	<insert id="insertOne">
		<!-- テーブル(M_USER)の各項目 -->
		insert into m_user(
			user_id,
			phone_number,
			postal_number1,
			postal_number2,
			address,
			user_name,
			password,
			birthday1,
			birthday2,
			age,
			account_icon,
			gender
		)
		<!-- エンティティクラスに定義した各項目 -->
		values(
		values(
			#{userId},
			#{phoneNumber, jdbcType=VARCHAR},
			#{postalNumber1, jdbcType=INTEGER},
			#{postalNumber2, jdbcType=INTEGER},
			#{address, jdbcType=VARCHAR},
			#{userName},
			#{password},
			#{birthday1, jdbcType=DATE},
			#{birthday2, jdbcType=DATE},
			#{age, jdbcType=INTEGER},
			#{accountIcon, jdbcType=BLOB},
			#{gender, jdbcType=INTEGER}
		)
		)
	</insert>
</mapper>

ポイントとしては3点あります。

1. Mapperとxmlのマッピング

<!-- Mapperとxmlのマッピング -->
<mapper namespace="com.exeample.repository.UserMapper">

mapperタグを用いて、Mapperとxmlファイルをマッピングします。
mapperタグのnamespace属性にMapperのインターフェース名をパッケージ名を含めて指定します。

2. SQLとメソッドのマッピング

次にSQLとメソッドのマッピングを行います。

UserMapper.java
	/* UserMapper.javaで記述した抽象メソッド */
	public int insertOne(MUser user);
UserMapper.xml
	<!-- ユーザー1件登録 -->
	<insert id="insertOne">

UserMapper.xmlのid属性にUserMapper.javaで記述した抽象メソッドを指定します。
また、今回はINSERT処理を行うのでタグを<insert></insert>としておきます。

3. メソッドの引数とSQLパラメータのマッピング

次にMapperメソッドの引数をSQLのパラメータに挿入します。
#{メソッド引き数名}形式で指定できます。今回はメソッドの引数をMuserにしているため、2. テーブル(M_USER)用のエンティティクラス(MUser.java)の作成で作成したエンティティクラスのフィールド名をSQL内で指定します。

JDBCの仕様で、insert, update, deleteでnullが許可されている項目を指定する場合、JDBCデータ型(jdbcType) を指定する必要があります。サポートされているJDBCデータ型の一覧は、MyBatisのドキュメントに記載されています。
Nullだとカラムのデータ型がわからないので定義が必要らしいです。

UserMapper.xml
		<!-- エンティティクラスに定義した各項目 -->
		values(
		values(
			#{userId},
			#{phoneNumber, jdbcType=VARCHAR},
			#{postalNumber1, jdbcType=INTEGER},
			#{postalNumber2, jdbcType=INTEGER},
			#{address, jdbcType=VARCHAR},
			#{userName},
			#{password},
			#{birthday1, jdbcType=DATE},
			#{birthday2, jdbcType=DATE},
			#{age, jdbcType=INTEGER},
			#{accountIcon, jdbcType=BLOB},
			#{gender, jdbcType=INTEGER}
		)
		)

5. サービスの処理の記述

次に先ほど作成したコードを利用して実際に行う処理を記述していきます。

1. UserService.java(インターフェース)

UserService.java
package com.example.service;

import java.util.Locale;
import java.util.Map;
import com.example.model.MUser;

public interface UserService {
	
	/* 性別のMapを生成する */
	public Map<String, Integer> getGenderMap(Locale locale);
	
	/* ユーザー登録 */
	public void signUp(MUser muser);
}

2. UserServiceImpl.java(実装クラス)

@Autowiredを用いてDIの注入を行い、UserService.javaで記述した抽象メソッドの実装を行います。

UserServiceImpl.java
package com.example.service.impl;

/* 省略 */

@Service
public class UserServiceImpl implements UserService {

    /* 省略 */
	
	/* レポジトリー(UserMapper.java)のDIを注入 */
	@Autowired
	private UserMapper mapper;
	
	/* データの挿入 */
	@Override
	public void signUp(MUser user) {
		mapper.insertOne(user);
	}
}

6. ModelMapperをBeanに登録

前回の記事でダウンロードしたModelMapperをBeanに登録していきます。
今回のようにライブラリに用意されているクラスをDIコンテナーに登録する場合、Beanのインスタンス(一般的にJavaConfig言われる)を作成します。

JavaConfigには@Configurationアノテーションを付けます。

JavaConfig.java
package com.example.config;

import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JavaConfig {
	
	@Bean
	public ModelMapper modelMapper() {
		return new ModelMapper();
	}
}

7. コントローラー(SignupController.java)の修正

最後にコントローラの作成を行います。

SignupController.java
package com.example.controller;

/* 省略 */

@Controller
@RequestMapping("/user")
@Slf4j
public class SignupController {
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private ModelMapper modelMapper;

	/* ユーザー登録画面を表示 */
	@GetMapping("/signup")
	public String getSignup(Model model, Locale locale, @ModelAttribute SignupForm form) {
		// 性別を取得
		Map<String, Integer> genderMap = userService.getGenderMap(locale);
		model.addAttribute("genderMap", genderMap);
		
		// ユーザー登録画面に遷移
		return "user/signup";
	}
	
	/* ユーザー登録処理 */
	@PostMapping("/signup")
	public String postSignup(Model model, Locale locale, 
			@Validated(GroupOrder.class) @ModelAttribute SignupForm form,
			BindingResult bindingResult) {
		// 入力チェック
		if(bindingResult.hasErrors()) {
			// エラーが発生したので登録画面に戻る
			return getSignup(model, locale, form);
		}

		log.info(form.toString());
		
		// formをMUserクラスに変換
		MUser user = modelMapper.map(form, MUser.class);
		
        log.info(user.toString());

		// ユーザ登録
		userService.signUp(user);

		// ログイン画面にリダイレクト
		return "redirect:/login";
	}
}

先ほどJavaConfigに追加したModelMappermapメソッドを使用することでフィールドの内容をコピーすることができます。
Formクラス(SignupForm.java)に格納されたデータをエンティティクラス(MUser.java)にコピーする。
ただし、コピー元のデータとコピー先のデータのフィールド名は一致している必要がある。

SignupController.java
MUser user = modelMapper.map(form, MUser.class);

バリエーションの設定は省略したSignupForm.java

SignupForm.java
import lombok.Data;

@Data
public class SignupForm {
	private String userId;
	private Integer phoneNumber;
	private Integer postalNumber1;
	private Integer postalNumber2;
	private String address;
	private String userName;
	private String password;
	private Date birthday1;
	private Date birthday2;
	private Integer age;
	private MultipartFile accountIcon;
	private Integer gender;
}

最後に

7. コントローラー(SignupController.java)の修正の中で、ModelMapperのmapメソッドを用いてFormクラス(SignupForm.java)に格納されたデータをエンティティクラス(MUser.java)にコピーしましたが、これには2つの理由があります。

1. 画面に変更があっても、サービスの修正が不要になる
2. 他の画面からもサービスを再利用できるようになる

よって、サービスを利用する場合はFormクラスを利用しないようにする!

試しに以下のようなデータを挿入すると
image.png

以下のログがlog.info(form.toString())により出力されたデータです(見やすいように縦書きに直してあります)。

log.info(form.toString())
 SignupForm(userId=Tokyo@xxx.co.jp, 
            phoneNumber=0353211111, 
            postalNumber1=163, 
            postalNumber2=8001, 
            address=東京都新宿区西新宿二丁目8番1号, 
            userName=TokyoTocho, 
            password=Tokyo_0353211111, 
            birthday1=null, 
            birthday2=Mon Apr 01 00:00:00 JST 1991, 
            age=31, 
            accountIcon=org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile@4028cb11, 
            gender=null)

以下のログがlog.info(user.toString())により出力されたデータです(見やすいように縦書きに直してあります)。

log.info(user.toString())
MUser(userId=Tokyo@xxx.co.jp, 
      phoneNumber=0353211111, 
      postalNumber1=163, 
      postalNumber2=8001, 
      address=東京都新宿区西新宿二丁目8番1号, 
      userName=TokyoTocho, 
      password=Tokyo_0353211111, 
      birthday1=null, 
      birthday2=Mon Apr 01 00:00:00 JST 1991, 
      age=31, 
      accountIcon=null, 
      gender=null)

両方のログを比較すると、画像データであるaccountIconがMUser側ではnullになってしまっています。
次回以降はここを修正していきます。

1
1
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
1
1