๐Ÿšง

[JPA๋กœ REST API ๋งŒ๋“ค๊ธฐ] DB ์—ฐ๋™ ๋ฐ JPA Repository ์‚ฌ์šฉํ•ด Service ์ˆ˜์ •

purpplee 2021. 11. 25. 15:30

DB์—ฐ๋™

build.gradle

mariadb ์™€ jpa ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋ฏ€๋กœ ์ฃผ์„์ฒ˜๋ฆฌ ํ•ด๋‘์—ˆ๋˜ jpa ๋ฅผ ์ฃผ์„ ํ•ด์ œํ•˜๊ณ  ์•„๋ž˜์ฒ˜๋Ÿผ ์ž…๋ ฅํ•œ๋‹ค.

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'

	//jpa
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    
      //mariadb
	runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
}

 

์ˆ˜์ • ํ›„ gradle ์„ refresh ํ•ด์ค€๋‹ค.

 

src/main/resources/application.properties

ํ•ด๋‹น ๊ฒฝ๋กœ์˜ properties ํŒŒ์ผ์— db ์ ‘์† ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค. ๊ฐ ์„ค์ • ์ •๋ณด๋Š” ์ฝ”๋“œ ๋ฐ‘์— ์ ์–ด๋‘์—ˆ๋‹ค.

spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://localhost:3306/todolist
spring.datasource.username=root
spring.datasource.password=1234

#JPA
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
  • spring.jpa.hibernate.ddl-auto=update
    • db์— ์ƒ์„ฑ๋˜์ง€ ์•Š์€ ํ…Œ์ด๋ธ”, ์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.
  • spring.jpa.show-sql=true
    • jpa ๊ฐ€ ๋‚ ๋ฆฌ๋Š” sql๋ฌธ์„ ๋ณด์—ฌ์ค€๋‹ค
  • spring.jpa.properties.hibernate.format_sql=true
    • ๋ณด์—ฌ์ฃผ๋Š” sql ๋ฌธ์„ ๊น”๋”ํ•˜๊ฒŒ ํฌ๋งคํŒ…ํ•ด์ค€๋‹ค.

 

Entity ์ƒ์„ฑ

/todo/model/TodoITem.java

๋‚ด์šฉ์„ ์•„๋ž˜์ฒ˜๋Ÿผ ์ˆ˜์ •ํ•ด์ค€๋‹ค. @Entity ๋Š” ์ž๋ฐ” ๊ฐ์ฒด๋ฅผ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ table ๊ณผ ๋งคํ•‘์‹œํ‚ฌ ์ˆ˜ ์žˆ๋„๋ก jpa์˜ entity ๋กœ ์„ ์–ธํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค. DB์— ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•˜์ง€ ์•Š์•„๋„ JPA Hibernate ๊ฐ€ ์•„๋ž˜ ๋‚ด์šฉ์„ ์ฐธ๊ณ ํ•ด create ๋ฌธ์„ ์‹คํ–‰ํ•ด์ค€๋‹ค.

id ์˜ ํƒ€์ž…์„ ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ํƒ€์ž… long ์ด ์•„๋‹Œ ๋ž˜ํผ ํƒ€์ž…์ธ Long ์œผ๋กœ ์„ ์–ธํ•˜๋Š” ์ด์œ ๋Š” null ์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. auto_increment ๋Š” id ๊ฐ’์ด ์—†์„ ๋•Œ ์ž๋™์œผ๋กœ ๋„ฃ์–ด์ฃผ๋Š” ์˜ต์…˜์ธ๋ฐ, long ์˜ default ๊ฐ’์€ 0์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ’์ด ์žˆ๋‹ค๊ณ  ๋ณด๊ฒŒ ๋œ๋‹ค. Long ์˜ default ๊ฐ’์€ Null ๋กœ ์ •ํ™•ํ•˜๊ฒŒ ๊ฐ’์ด ์—†๋‹ค๊ณ  ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋˜๋„๋ก jpa ์—์„œ pk ๋Š” Nullable ํ•œ ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ์“ฐ๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋œ๋‹ค.
package com.todolist.tutorial.todo.model;

import lombok.*;
import javax.persistence.*;

@Entity                 //jpa entity ๋กœ ์„ ์–ธ
@Table(name="todos")    //table ์ •๋ณด
@Getter @Setter         //getter, setter ๋ฉ”์†Œ๋“œ
@NoArgsConstructor      //์ธ์ž ์—†๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž
@AllArgsConstructor     //๋ชจ๋“  ์ธ์ž ๊ฐ€์ง€๋Š” ์ƒ์„ฑ์ž
@Builder                //๋นŒ๋” ํŒจํ„ด์œผ๋กœ ์ƒ์„ฑํ•˜๊ฒŒ ํ•ด์คŒ.
public class TodoItem {
    @Id     //pk ํ•„๋“œ. ๋ฐ˜๋“œ์‹œ ํ•„์š”,
    @Column(name="id", nullable = false)    //ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ๊ณผ ๋งคํ•‘
    @GeneratedValue(strategy = GenerationType.IDENTITY) //auto increment
    private Long id;

    @Column(name="title", nullable = false, length = 100)
    private String title;

    @Column(name="done", nullable = false)
    private boolean done;
}

 

Repository ์ƒ์„ฑ

/todo/model/TodoItemRepository.interface

JpaRepository ์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์ƒ์†๋ฐ›๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ ๋‹ค. ๋ชธ์ฒด๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•„๋„, Hibernate ๊ฐ€ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋ฏ€๋กœ ์ด ํ•œ ์ค„์ด๋ฉด ๋œ๋‹ค.

package com.todolist.tutorial.todo.model;

import org.springframework.data.jpa.repository.JpaRepository;

public interface TodoItemRepository extends JpaRepository<TodoItem, Long> {

}

 

๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณต๋˜๋Š” Jpa ๋ฉ”์†Œ๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

method return description
findAll() List<T> search
findById Optinal<T> search
deleteById(T id) void delete
save(T entity) T insert, update

 

Service ์— Repository ์ถ”๊ฐ€

/todo/TodoItemService.java

์„œ๋น„์Šค์— ์œ„์—์„œ ๋งŒ๋“  Repository ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์•„๋ž˜์™€ ๊ฐ™์ด ๋‚ด์šฉ์„ ๋ณ€๊ฒฝํ•˜์ž. ์ฐธ๊ณ ๋กœ, getById() ๋Š” Optional ์„ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ orElseThrow() ๋ฅผ ๋ถ™์—ฌ์ฃผ์—ˆ๋‹ค.  ์ด์ „์— ์„œ๋น„์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ์ปจํŠธ๋กค๋Ÿฌ์— ์ถ”๊ฐ€ํ•  ๋•Œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ,  Repository ์˜ ์˜์กด์„ฑ์„ ์ž๋™์œผ๋กœ ์ฃผ์ž…๋ฐ›๊ธฐ ์œ„ํ•ด @Autowired ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ฃผ์—ˆ๋‹ค.

Optional ๊ฐ์ฒด๋Š” NullPointerException ๋ฅผ ์†์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด T ํƒ€์ž…์˜ ๊ฐ์ฒด๋“ค์„ ๊ฐ์‹ธ์ฃผ๋Š” Wrapper ํด๋ž˜์Šค๋‹ค. ๋ณต์žกํ•œ ์กฐ๊ฑด๋ฌธ ์—†์ด orElsethrow ๋ฉ”์†Œ๋“œ ๋“ฑ์œผ๋กœ null exception ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
package com.todolist.tutorial.todo;

import com.todolist.tutorial.todo.model.TodoItem;
import com.todolist.tutorial.todo.model.TodoItemRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TodoItemService {
    @Autowired
    private TodoItemRepository todoRepo;

    public List<TodoItem> getTodos() {
        List<TodoItem> todos = todoRepo.findAll();

        if(!todos.isEmpty()) return todoRepo.findAll();
        else throw new IllegalArgumentException("no such data");
    }

    public TodoItem getTodoById(final Long id) {
        return todoRepo.findById(id).orElseThrow(()-> new IllegalArgumentException("no such data"));
    }

    public TodoItem createTodo(final TodoItem createTodoItem) {
        if(createTodoItem == null) throw new IllegalArgumentException("todo item cannot be null");
        return todoRepo.save(createTodoItem);
    }

    public TodoItem updateTodo(final long id, final TodoItem updateTodoItem) {
        TodoItem todoItem = getTodoById(id);
        todoItem.setTitle(updateTodoItem.getTitle());
        todoItem.setDone(updateTodoItem.isDone());

        return todoRepo.save(todoItem);
    }

    public void deleteTodoById(final Long id) {
        todoRepo.deleteById(id);
    }
}

 

๋ฐ˜์‘ํ˜•