end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

SpringBoot で 複合主キー DBテーブルへのRepository作成時に、org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userMstRepository' defined in jp.end0tknr.UserMstRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegi

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>