🌶️
SpringBoot MyBatisでMySQLにCRUDするRestAPIを作成してみた
フォルダ構成
フォルダ構成 抜粋
demo $ tree
.
├── gradlew
├── build.gradle
├── docker-compose.yml
├── db_data
├── my.cnf
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── demo
│ │ ├── DemoApplication.java
│ │ └── component
│ │ └── user
│ │ ├── User.java
│ │ ├── UserController.java
│ │ ├── UserDao.java
│ │ └── UserService.java
│ └── resources
│ └── application.yml
db_dataのフォルダを作成し、mysqlのデータを永続化する
DB準備
docker-composeでmysql準備
mysql準備
docker-compose.yml
version: '3'
services:
mysql:
image: mysql:5.7
command: mysqld
ports:
- 3306:3306
environment:
MYSQL_DATABASE: testdb
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_USER: user
MYSQL_PASSWORD: userpass
TZ: Asia/Tokyo
volumes:
- ./db_data:/var/lib/mysql
- ./my.cnf:/etc/mysql/my.cnf
my.cnf
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_bin
lower_case_table_names=1
[client]
default-character-set=utf8mb4
details lower_case_table_names=1を設定する理由
mysql> create table User ( id int , name char(10) );
ERROR 1146 (42S02): Table 'testdb.user' doesn't exist
といったエラーが出た。
my.cnfに下記を設定することでこの状況を回避できた
lower_case_table_names=1
テーブル作成
docker-compose up -d
docker-compose ps
mysql -u user -puserpass testdb -h 127.0.0.1
create table users(
id int(11),
name char(10)
);
create unique index user_idx on users(id);
desc users;
build.gradleにdependencies追加
build.gradle
plugins {
id 'org.springframework.boot' version '2.6.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'
implementation 'mysql:mysql-connector-java:8.0.27'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
test {
useJUnitPlatform()
}
mysql接続設定
application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/testdb
username: user
password: userpass
driver-class-name: com.mysql.cj.jdbc.Driver
sql-script-encoding: utf-8
MyBatisでの接続
User.java
package com.example.demo.component.user;
import lombok.Data;
@Data
public class User {
private Integer id;
private String name;
}
UserDao.java
package com.example.demo.component.user;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
@Mapper
public interface UserDao {
@Select("select * from users where id=#{id}")
User findById(User user);
@Select("select * from users")
List<User> findAll();
@Insert("insert into users (id , name) values (#{id},#{name})")
void insert(User user);
@Update("update users set name = #{name} where id=#{id}")
boolean update(User user);
@Delete("delete from users where id=#{id}")
boolean delete(User user);
}
@Mapperは@Autowiredと対になっている
@Mapperで定義しておくことで、@Autowiredでインジェクションできるようになる
xmlでSQLを設定するやり方もありが、そのやり方だと、パッケージのリファクタリングをした際に、vscodeで自動修正できず、手作業での修正が発生してしまう。
UserService.java
package com.example.demo.component.user;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final UserDao userDao;
@Autowired
public UserService(UserDao userDao){
this.userDao = userDao;
}
public User findById(User user){
return this.userDao.findById(user);
}
public List<User> getUserList(){
return this.userDao.findAll();
}
public User insert(User user){
this.userDao.insert(user);
return user;
}
public User update(User user){
if(this.userDao.update(user)){
return user;
}else{
return null;
}
}
public User delete (User user){
User delUser = findById(user);
if(this.userDao.delete(user)){
return delUser;
}else{
return null;
}
}
}
@Serviceは@Autowiredと対になっている
@Serviceで定義しておくことで、@Autowiredでインジェクションできるようになる
UserDaoをコンストラクトインジェクションにすることで、userDaoをfinalで定義している。
このため、不変性が担保できる
UserController
package com.example.demo.component.user;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService){
this.userService = userService;
}
private static final Logger log =
LoggerFactory.getLogger(UserController.class);
@GetMapping("/user/{id}")
public User getUser(@PathVariable Integer id ){
log.info("getUser");
User user = new User();
user.setId(id);
return userService.findById(user);
}
@GetMapping("/users")
public List<User> getUserList(){
log.info("getUserList");
return userService.getUserList();
}
@PostMapping("/insert_user/{id}")
public User insertUser(@PathVariable Integer id ,
@RequestParam String name){
log.info("insertUser");
User user = new User();
user.setId(id);
user.setName(name);
return userService.insert(user);
}
@PutMapping("/update_user/{id}")
public User updateUser(@PathVariable Integer id ,
@RequestParam String name){
log.info("updateUser");
User user = new User();
user.setId(id);
user.setName(name);
return userService.update(user);
}
@DeleteMapping("/delete_user/{id}")
public User deleteUser(@PathVariable Integer id){
log.info("deleteUser");
User user = new User();
user.setId(id);
return userService.delete(user);
}
}
DemoApplication.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
run
demo $ ./gradlew bootRun
call
Chrome ARC
#GET
http://localhost:8080/users
#GET
http://localhost:8080/user/1
#POST
http://localhost:8080/insert_user/1
#application/x-www-form-urlencoded
name=insertname
#PUT
http://localhost:8080/update_user/1
#application/x-www-form-urlencoded
name=updatename
#DELETE
http://localhost:8080/delete_user/1
Discussion