CRUD(JPA) - Spring Boot

  • 作成日:
  • 最終更新日:2025/10/11

環境

プロジェクト Maven
データベース MariaDB
データベース名 java
テーブル名 users
# データベースの作成
CREATE DATABASE java;

# テーブルの作成
CREATE TABLE users (id INT AUTO_INCREMENT, name VARCHAR(255) NOT NULL PRIMARY KEY (id));
  • myapp
    • src/main/java
      • com.example
        • MyappApplication.java
      • com.example.controller
        • UserController.java
      • com.example.entity
        • User.java
      • com.example.exception
        • UserNotFoundException.java
      • com.example.repository
        • UserRepository.java
    • src/main/resources
      • static
      • templates
        • error
          • 404.html
        • users
          • create.html
          • edit.html
          • index.html
          • show.html
      • application.properties
    • ~ 中略 ~
    • pom.xml

ファイル

UserController.java

package com.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import com.example.entity.User;
import com.example.repository.UserRepository;
import com.example.exception.UserNotFoundException;

@Controller
@RequestMapping("/users")
public class UserController {
private final UserRepository userRepository;

public UserController(UserRepository userRepository) {
    this.userRepository = userRepository;
}

@GetMapping
public String indexUser(Model model) {
    model.addAttribute("users", userRepository.findAll());
    return "users/index";  // templates/users.html を表示
}

// ユーザー詳細ページ
@GetMapping("/{id}")
public String getUser(@PathVariable Long id, Model model) {
    User user = userRepository.findById(id)
            .orElseThrow(() -> new IllegalArgumentException("Invalid user Id:" + id));
    model.addAttribute("user", user);
    return "users/show";
}

@GetMapping("/new")
public String newUserForm(Model model) {
    model.addAttribute("user", new User());
    return "users/create"; // templates/user_form.html を表示
}

// フォームからのPOST
@PostMapping
public String createUser(@ModelAttribute User user) {
    userRepository.save(user);
    return "redirect:/users"; // 一覧ページにリダイレクト
}

// ユーザー編集フォーム
@GetMapping("/{id}/edit")
public String editUserForm(@PathVariable Long id, Model model) {
    try {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new UserNotFoundException(id));
        model.addAttribute("user", user);
        return "users/edit";
    } catch (UserNotFoundException ex) {
        System.err.println(ex.getMessage()); // "User not found with id: 10" が出力される
        ex.printStackTrace(); // スタックトレース付きで出力
        return "error/404";
    }
    
}

// 編集内容の保存
@PostMapping("/{id}")
public String updateUser(@PathVariable Long id, @ModelAttribute User user) {
    user.setId(id); // idをセットしないと新規作成になってしまう
    userRepository.save(user);
    return "redirect:/users";
}

// ユーザー削除
@PostMapping("/{id}/delete")
public String deleteUser(@PathVariable Long id) {
    userRepository.deleteById(id);
    return "redirect:/users"; // 削除後は一覧ページへ
}
}

User.java

package com.example.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

public Long getId() { return id; }
public void setId(Long id) { this.id = id; }

public String getName() { return name; }
public void setName(String name) { this.name = name; }
}

UserNotFoundException.java

package com.example.exception;

public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(Long id) {
    super("User not found with id: " + id);
}
}

UserRepository.java

package com.example.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import com.example.entity.User;

public interface UserRepository extends JpaRepository<User, Long> {
}

HTML ファイル

404.html

<!doctype html>
<html lang="ja">
<head>
	<meta charset="UTF-8" />
	<title>Document</title>
</head>
<body>
	<h1>404</h1>
</body>
</html>

create.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Create User</title>
</head>
<body>
<h1>Create User</h1>

<form th:action="@{/users}" method="post">
<div>
    <label for="name">Name:</label>
    <input type="text" id="name" name="name" th:value="${user.name}" required>
</div>
<div>
    <button type="submit">Save</button>
</div>
</form>

<a th:href="@{/users}">Back to list</a>
</body>
</html>

edit.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>User Form</title>
</head>
<body>
<h1>Edit User</h1>

<form th:action="@{'/users/' + ${user.id}}" method="post">
<div>
    <label for="name">Name:</label>
    <input type="text" id="name" name="name" th:value="${user.name}" required>
</div>
<div>
    <button type="submit">Save</button>
</div>
</form>

<a th:href="@{/users}">Back to list</a>
</body>
</html>

index.html

<!doctype html>
<html lang="ja">
<head>
	<meta charset="UTF-8" />
	<title>Document</title>
</head>
<body>
<h1>User Index</h1>
<table>
    <tr>
        <th>ID</th><th>Name</th><th>Actions</th>
    </tr>
    <tr th:each="user : ${users}">
        <td th:text="${user.id}"></td>
        <td><a th:href="@{'/users/' + ${user.id}}" th:text="${user.name}"></a></td>
        <td>
            <a th:href="@{'/users/' + ${user.id} + '/edit'}">Edit</a>
            <form th:action="@{'/users/' + ${user.id} + '/delete'}" method="post" style="display:inline;">
                <button type="submit" onclick="return confirm('Are you sure you want to delete this user?');">Delete</button>
            </form>
        </td>
    </tr>
</table>
<p><a th:href="@{/users/new}">New User</a></p>
</body>
</html>

show.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>User Detail</title>
</head>
<body>
<h1>User Detail</h1>

<p><strong>ID:</strong> <span th:text="${user.id}"></span></p>
<p><strong>Name:</strong> <span th:text="${user.name}"></span></p>

<a th:href="@{/users}">Back to list</a>
<a th:href="@{'/users/' + ${user.id} + '/edit'}">Edit</a>
</body>
</html>

その他ファイル

application.properties

spring.application.name=myapp

spring.datasource.url=jdbc:mariadb://localhost:3306/java?useUnicode=true&characterEncoding=utf8mb4
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driverClassName=org.mariadb.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect

spring.thymeleaf.cache=false

mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.example.entity

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>3.5.6</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>myapp</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>myapp</name>
	<description>Demo project for Spring Boot</description>
	<url/>
	<licenses>
		<license/>
	</licenses>
	<developers>
		<developer/>
	</developers>
	<scm>
		<connection/>
		<developerConnection/>
		<tag/>
		<url/>
	</scm>
	<properties>
		<java.version>21</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.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.mariadb.jdbc</groupId>
        <artifactId>mariadb-java-client</artifactId>
    </dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>