SpringBoot で 主キーが複数ある DBテーブルに対しての Entity & Repository を作成後、 eclipseからSpringBootを起動すると、以下のエラーが発生。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userMstRepository' defined in jp.end0tknr.UserMstRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: This class [class jp.end0tknr.UserMstEntity] does not define an IdClass
どうやら、pkeyを表すクラスを作成した上で、 「@IdClass指定」or「@EmbeddedId による単一pkey化」とするとよいらしい。
参考url:
http://itdoc.hitachi.co.jp/manuals/link/cosmi_v0870/APKC/EU070333.HTM
https://dev.classmethod.jp/articles/spring-data-jpa-search-2/
https://qiita.com/t-iguchi/items/9a834aac3874706d80b3
対応の概要
今回は、pkeyを表すクラスを作成した上で、@IdClassを指定しています。
種別 | ファイル名 | 対応概要 |
---|---|---|
DB TABLE | user_mst | column:kyoten_id , user_xmileid が primary key |
Pkey クラス | UserMstEntityPkey | pkeyのfieldのみあります |
Entityクラス | UserMstEntity | 通常の @Id に加え、@IdClass を指定 |
Repository インタフェース | UserMstRepository | DBアクセス手段は複数ありますが、今回はJpaRepository |
Controllerクラス | HelloController | 動作確認用に用意。複合キーへの特別な実装はなし |
JSP | hello2.jsp | 〃 |
properties | application.properties | 〃 |
Maven | pom.xml | 〃 |
DB TABLE - user_mst
今回の対象は、以下の user_mst テーブルで、 kyoten_id , user_xmileid を primary key に持ちます。
mysql> desc user_mst; +------------------------------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------------------------+--------------+------+-----+---------+-------+ | kyoten_id | int | NO | PRI | NULL | | | user_xmileid | varchar(50) | NO | PRI | NULL | | | reg_xmileid | varchar(50) | NO | | NULL | | | reg_name | varchar(400) | NO | | NULL | | | reg_date | datetime | NO | | NULL | | | last_upd_xmileid | varchar(50) | NO | | NULL | | | last_upd_name | varchar(400) | NO | | NULL | | | last_upd_date | datetime | NO | | NULL | | | is_delete | int | NO | | 0 | | | version | int | NO | | NULL | | | user_name | varchar(400) | NO | | NULL | | | user_shozokugroup | varchar(20) | NO | | NULL | | +------------------------------+--------------+------+-----+---------+-------+
Pkey クラス - UserMstEntityPkey.java
pkeyのfieldのみのクラスです。 「implements Serializable」も必要なようです。
package jp.end0tknr; import java.io.Serializable; import lombok.Data; @Data public class UserMstEntityPkey implements Serializable { public Integer kyotenId; public String userXmileid; }
Entityクラス - UserMstEntity.java
単一PkeyのEntityクラスで指定する「@Id」に加え、 「@IdClass(value=UserMstEntityPkey.class)」を指定します。
package jp.end0tknr; import java.io.Serializable; import java.sql.Timestamp; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.IdClass; import javax.persistence.Table; import javax.persistence.Version; import lombok.Data; @Entity @Table(name = "user_mst") @Data @IdClass(value=UserMstEntityPkey.class) public class UserMstEntity implements Serializable { private static final long serialVersionUID = 1L; /** kyotenIdプロパティ */ @Id @Column(precision = 10, nullable = false, unique = false) public Integer kyotenId; /** userXmileidプロパティ */ @Id @Column(length = 50, nullable = false, unique = false) public String userXmileid; /** regXmileidプロパティ */ @Column(length = 50, nullable = false, unique = false) public String regXmileid; /** regNameプロパティ */ @Column(length = 400, nullable = false, unique = false) public String regName; /** regDateプロパティ */ @Column(nullable = false, unique = false) public Timestamp regDate; /** lastUpdXmileidプロパティ */ @Column(length = 50, nullable = false, unique = false) public String lastUpdXmileid; /** lastUpdNameプロパティ */ @Column(length = 400, nullable = false, unique = false) public String lastUpdName; /** lastUpdDateプロパティ */ @Column(nullable = false, unique = false) public Timestamp lastUpdDate; /** isDeleteプロパティ */ @Column(precision = 10, nullable = false, unique = false) public Integer isDelete; /** versionプロパティ */ @Version @Column(precision = 10, nullable = false, unique = false) public Integer version; /** userNameプロパティ */ @Column(length = 400, nullable = false, unique = false) public String userName; /** userShozokugroupプロパティ */ @Column(length = 20, nullable = false, unique = false) public String userShozokugroup; }
Repository インタフェース - UserMstRepository.java
DBアクセス手段は複数ありますが、今回は殆ど実装が不要な JpaRepository を 利用したインターフェース。
package jp.end0tknr; import org.springframework.data.jpa.repository.JpaRepository; public interface UserMstRepository extends JpaRepository<UserMstEntity, Long>{ }
Controllerクラス - HelloController.java
package jp.end0tknr; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @EnableAutoConfiguration public class HelloController { @Autowired UserMstRepository repository; @RequestMapping(value="/", method=RequestMethod.GET) public String hello(Model model) { model.addAttribute("click", false); model.addAttribute("message", "please click!"); return "hello2"; } @RequestMapping(value="/", method=RequestMethod.POST) public String click(Model model) { Iterable<UserMstEntity> userList = repository.findAll(); model.addAttribute("userList", userList); model.addAttribute("click", true); model.addAttribute("afterClickMsg", "It was clicked."); return "hello2"; } }
JSP - hello2.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%> <%@ page session="false" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Hello JSP</title> </head> <body> <div> <c:if test="${click == false}" > <c:out value="${message}" /> <form method="post" action="/"> <input type="submit" value="Click" /> </form> </c:if> </div> <div> <c:if test="${click == true}" > <c:out value="${afterClickMsg}" /> <div> <input type="submit" value="Click" disabled="disabled"/> </div> </c:if> </div> <div> <c:forEach var="user" items="${userList}" varStatus="status"> <c:out value="${user.userXmileid}" /><br/> </c:forEach> </div> </body> </html>
properties - application.properties
spring.mvc.view.prefix: /WEB-INF/views/ spring.mvc.view.suffix: .jsp spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://192.168.63.3:3306/bknkoutei spring.datasource.username=xparcadm spring.datasource.password=admxparc
Maven - pom.xml
<?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.4.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>jp.end0tknr</groupId> <artifactId>MySpringJsp</artifactId> <version>0.0.1-SNAPSHOT</version> <name>MySpringJsp</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> --> <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.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>