Spring BootのJPAでMySQLのデータ作成・更新時にユーザ名と日付を毎回自動で指定のカラムに記録するようにする。
プロジェクトの準備
プロジェクトの作成と準備はSpring BootとJPAでMySQLに繋いでデータの操作をしている以下の記事を参考にする。
基本は以下の記事から追加、変更分をこの記事のコードでは説明する。
コード作成・記述
srcフォルダー以下のファイル構造は以下である。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
spring-boot-mysql (master) ✗ tree src src ├── main │ ├── java │ │ └── com │ │ └── example │ │ └── springbootmysql │ │ ├── HelloApi.java │ │ ├── SpringBootMysqlApplication.java │ │ ├── config │ │ │ ├── AuditorAwareImpl.java │ │ │ └── PersistenceConfig.java │ │ ├── controller │ │ │ └── BookController.java │ │ ├── model │ │ │ ├── Auditable.java │ │ │ ├── Book.java │ │ │ └── User.java │ │ ├── repository │ │ │ └── BookRepository.java │ │ └── service │ │ └── BookService.java │ └── resources │ └── application.yml └── test └── java └── com └── example └── springbootmysql └── SpringBootMysqlApplicationTests.java 16 directories, 12 files |
まずは、データの作成、更新のユーザ、日付カラムを扱うAuditable.javaを作成する。
Auditable.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package com.example.springbootmysql.model; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedBy; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import javax.persistence.Column; import javax.persistence.EntityListeners; import javax.persistence.MappedSuperclass; import java.util.Date; @MappedSuperclass @EntityListeners(AuditingEntityListener.class) public abstract class Auditable<U> { @CreatedBy @Column(name = "create_by", nullable = false, updatable = false) protected U createdBy; @CreatedDate @Column(name = "create_date", nullable = false, updatable = false) protected Date creationDate; @LastModifiedBy @Column(name = "update_by") protected U updateBy; @LastModifiedDate @Column(name = "update_date") protected Date updateDate; } |
@CreatedByでデータの作成者を、@CreatedDateデータの作成日を、@LastModifiedByでデータの最終更新者を、@LastModifiedDateでデータの最終更新日を扱う。
@Columnのnameで変数とテーブルのカラム名を対応させている。nullable = false, updatable = falseで作成者、作成日はデータのレコードに必須なのと変更を不可能にしている。
このAuditableをテーブルに対応したEntiryクラスでextendsすることでユーザや日付のカラムが作成され記録できるようになる。
Book.javaで扱いたい場合以下のように変更する。
Book.java
1 2 |
public class Book extends Auditable<String> { // コードの中身に関しては「Spring BootとJPAでMySQLに繋ぐ」の記事を参考 |
次に、作成者や変更者のユーザ名を記録するクラスを作る。
1 2 3 4 5 6 7 8 9 10 |
package com.example.springbootmysql.model; import lombok.Data; import org.springframework.context.annotation.Configuration; @Configuration @Data public class User { private String userName; } |
JPAでauditingを使えるようにいくつかの設定クラスを書く。
PersistenceConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package com.example.springbootmysql.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.domain.AuditorAware; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @Configuration @EnableJpaAuditing(auditorAwareRef = "auditorAware") public class PersistenceConfig { @Bean public AuditorAware<String> auditorAware(){ return new AuditorAwareImpl(); } } |
AuditorAwareImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package com.example.springbootmysql.config; import com.example.springbootmysql.model.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.AuditorAware; import java.util.Optional; public class AuditorAwareImpl implements AuditorAware<String> { @Autowired private User user; @Override public Optional<String> getCurrentAuditor() { return Optional.of(user.getUserName()); } } |
AuditorAwareImplクラスのgetCurrentAuditorでリターンしているものがユーザ名でこれがAuditableクラスのcreatedByやupdateByに代入される。
今回は、Userクラスにユーザ名を保持するuserNameを用意しそれをgetして用いる。
このUserクラスのuserNameに値を代入するのを以下のBookControllerクラスで行なっている。
BookController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package com.example.springbootmysql.controller; import com.example.springbootmysql.model.Book; import com.example.springbootmysql.model.User; import com.example.springbootmysql.service.BookService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/book") public class BookController { @Autowired BookService bookService; @Autowired User user; // データを取得するメソッドについては「Spring BootとJPAでMySQLに繋ぐ」の記事を参考 @RequestMapping(method = RequestMethod.POST, path = "/") public ResponseEntity<Integer> addBook(@RequestHeader("User-Name") String userName, @RequestBody Book book) { user.setUserName(userName); return new ResponseEntity<>(bookService.addBook(book), HttpStatus.CREATED); } @RequestMapping(method = RequestMethod.PUT, path = "/{bookId}") public ResponseEntity<Integer> putBook(@RequestHeader("User-Name") String userName, @PathVariable(value = "bookId") int bookId, @RequestBody Book book) { user.setUserName(userName); book.setBookId(bookId); return new ResponseEntity<>(bookService.addBook(book), HttpStatus.NO_CONTENT); } } |
今回はリクエスト時にヘッダー情報でユーザ名を送ってもらいそれをUserクラスのuserNameに入れて扱う。
Spring Bootでリクエストのヘッダー情報を取得するには@RequestHeader(“User-Name”) String userNameをメソッドの引数に入れるだけで良い。
ここではapplication.ymlの設定でddl-auto: updateと記述しているのでプロジェクト起動時に自動でテーブルは作成される。create table book…..;で作成しても問題はない。
MySQLのテーブルは以下のように作成されている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
mysql> desc book; +-------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+--------------+------+-----+---------+----------------+ | book_id | int(11) | NO | PRI | NULL | auto_increment | | create_by | varchar(255) | NO | | NULL | | | create_date | datetime | NO | | NULL | | | update_by | varchar(255) | YES | | NULL | | | update_date | datetime | YES | | NULL | | | delete_flag | tinyint(1) | NO | | 0 | | | description | varchar(255) | YES | | NULL | | | title | varchar(255) | YES | | NULL | | +-------------+--------------+------+-----+---------+----------------+ 8 rows in set (0.00 sec) |
動作確認
まずは新規のデータ作成。
1 2 |
curl -X POST -H "Content-Type: application/json" -H "User-Name: asan" -d '{"title":"kimetsu", "description":"kimetsu"}' localhost:8080/book/ 1 |
MySQLを確認するとbook_id=1でデータができているのがわかる。create_by, create_date, update_by, update_dateにも値が自動で入っているのがわかる。
1 2 3 4 5 6 7 |
mysql> select * from book; +---------+-----------+---------------------+-----------+---------------------+-------------+-------------+---------+ | book_id | create_by | create_date | update_by | update_date | delete_flag | description | title | +---------+-----------+---------------------+-----------+---------------------+-------------+-------------+---------+ | 1 | asan | 2020-04-01 17:40:14 | asan | 2020-04-01 17:40:14 | 0 | kimetsu | kimetsu | +---------+-----------+---------------------+-----------+---------------------+-------------+-------------+---------+ 1 row in set (0.00 sec) |
次にデータの更新をしてみる。
1 |
curl -X PUT -H "Content-Type: application/json" -H "User-Name: bsan" -d '{"title":"kimetsu2", "description":"kimetsu2"}' localhost:8080/book/1 |
MySQLを確認するとbook_id=1のupdate_by, update_date, title, descriptionが変更しているのがわかる。
1 2 3 4 5 6 7 |
mysql> select * from book; +---------+-----------+---------------------+-----------+---------------------+-------------+-------------+----------+ | book_id | create_by | create_date | update_by | update_date | delete_flag | description | title | +---------+-----------+---------------------+-----------+---------------------+-------------+-------------+----------+ | 1 | asan | 2020-04-01 17:40:14 | bsan | 2020-04-01 17:40:31 | 0 | kimetsu2 | kimetsu2 | +---------+-----------+---------------------+-----------+---------------------+-------------+-------------+----------+ 1 row in set (0.00 sec) |
ついでにデータの取得もしてみるとAuditing情報は返ってこないことがわかる。
1 2 |
curl localhost:8080/book/1 {"bookId":1,"title":"kimetsu2","description":"kimetsu2","deleteFlag":false} |
参考文献

コメント