๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
  • ์žฅ์›์ต ๊ธฐ์ˆ ๋ธ”๋กœ๊ทธ
๐Ÿ’Š Java & Kotlin & Spring/- spring framework +

[Spring & Springboot] Generic์„ ์ด์šฉํ•˜์—ฌ ๋ชจ๋“  Request, Response์— Header์™€ CRUD ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌ์„ฑํ•ด๋ณด์ž.

by Wonit 2020. 8. 27.

์ด ์‹œ๋ฆฌ์ฆˆ๋Š” Spring์—์„œ Generic์„ ์ด์šฉํ•˜์—ฌ CRUD ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌ์„ฑํ•ด๋ณด์ž.์™€ ์ด์–ด์ง€๋Š” ๊ธ€ ์ž…๋‹ˆ๋‹ค.

  1. Generic(์ œ๋„ˆ๋ฆญ)์„ ํ•ต์‹ฌ๋งŒ ์ดํ•ดํ•ด๋ณด์ž.
  2. Spring์—์„œ Generic์„ ์ด์šฉํ•˜์—ฌ CRUD ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌ์„ฑํ•ด๋ณด์ž.

์ด ๊ธ€์€ ์‹ค์ „์— ๊ด€ํ•œ ๊ธ€์ด๊ณ  ์ œ๋„ˆ๋ฆญ์— ๋Œ€ํ•œ ์ด๋ก ์ด ๋ถ€์กฑํ•˜์‹  ๋ถ„๋“ค์€ 1๋ฒˆ ๋งํฌ๋ฅผ ํ†ตํ•ด ์ถฉ๋ถ„ํžˆ ์ˆ™์ง€ํ•˜๊ณ  ์˜ค์‹œ๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.


์ œ๋„ค๋ฆญ์„ ์‹ค์ „์—์„œ ์‚ฌ์šฉํ•ด๋ณด์ž.

์ง€๋‚œ ์‹œ๊ฐ„์— ๋ฐฐ์šด ์ œ๋„ค๋ฆญ์— ์ด์–ด์„œ ์ด์ œ ์‹ค์ „์—์„œ ์‚ฌ์šฉํ•ด๋ณด๊ธฐ ์œ„ํ•ด ํ™˜๊ฒฝ ๊ตฌ์„ฑ์„ ํ•ด๋ณด์ž.

Jpa + Springboot + Mysql ์—ฐ๋™์— ๋Œ€ํ•ด์„œ๋Š”

์šฐ๋ฆฌ๋Š” ๋ชจ๋“  Http ํ†ต์‹ ์— Header๋ผ๋Š” ๊ณตํ†ต ๋ถ€๋ถ„์ด ๋“ค์–ด๊ฐ€์•ผ ํ•˜๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ๋‹ค.

์›๋ž˜๋ผ๋ฉด request, response ์— setHeader๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํ—ค๋”๋ฅผ ๊ด€๋ฆฌํ•˜๊ฒ ์ง€๋งŒ ์ œ๋„ค๋ฆญ์˜ ์ดํ•ด๋ฅผ ์œ„ํ•ด ์ง์ ‘ Header๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ๋ชจ๋“  ์š”์ฒญ๊ณผ ์‘๋‹ต์— Header๋ฅผ ๋ถ™ํ˜€์„œ ์ž‘์„ฑํ•ด๋ณด์ž.

์ด๋Ÿฌํ•œ ๋ชจ๋ธ์„ ํ†ต์‹ ํ•˜๋ ค๊ณ  ํ•˜๋Š”๋ฐ ๋ชจ๋“  ํ†ต์‹ ์ด ์ด๋ฃจ์–ด์งˆ ๋•Œ ๋งˆ๋‹ค Header์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  ์š”๊ตฌํ•œ๋‹ค.

  • transaction_time (ํ†ต์‹  ์‹œ๊ฐ)
  • status (ํ†ต์‹  ์ƒํƒœ ์ฝ”๋“œ OK, ERROR)
  • description (์„ธ๋ถ€ ๋‚ด์šฉ:: ํ†ต์‹ ์ด ๋ฐœ์ƒํ•œ ์„œ๋ฒ„ ์ฃผ์ฒด)
  • data (๋ฐ์ดํ„ฐ)

๊ทธ๋Ÿผ ๋ชจ๋“  ํ†ต์‹ ์„ Header๋ผ๋Š” ํด๋ž˜์Šค์— ๋‹ด์•„์„œ Request์™€ Response๋ฅผ ์ˆ˜ํ–‰ํ•  ๊ฒƒ์ธ๋ฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ˜•์‹์˜ JSON์œผ๋กœ ํ†ต์‹ ์ด ์ด๋ฃจ์–ด์งˆ ๊ฒƒ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋ชจ๋“  ๋ชจ๋ธ๋งˆ๋‹ค CRUD๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ๊ณตํ†ต ๋ถ€๋ถ„์„ ๋ฌถ์–ด์ฃผ๋Š” CrudInterface ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋ชจ๋ธ์— ๊ด€ํ•œ Controller์—์„œ ํ†ต์‹ ์„ ์—ฐ๊ฒฐํ•ด๋ณด์ž.

Overview

์›๋ž˜๋Š” 3๊ฐœ์˜ ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค๋ฅผ ๋ชจ๋‘ ์ž‘์„ฑํ•ด์•ผ ๋งž๋Š” ๊ฒƒ ์ด์ง€๋งŒ ๊ฐ™์€ ์ฝ”๋“œ์˜ ๋ฐ˜๋ณต์ธ ์ž‘์—…์œผ๋กœ ํ•˜๋‚˜์˜ User์™€ ๊ด€๋ จ๋œ ์ž‘์—…์œผ๋กœ ๋Œ€์ฒดํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‹จ์ง€ ์ดํ•ด๋ฅผ ๋•๊ธฐ ์œ„ํ•ด ๋ถˆํ•„์š”ํ•œ ์ค‘๋ณต์„ ์ตœ์†Œํ™”ํ•˜๋Š” ๊ณผ์ •์ด์ง€ ํด๋ž˜์Šค๋ฅผ ๋œ ์ž‘์„ฑํ•œ๋‹ค๊ณ  ํ•ด์„œ ํฌ์ŠคํŒ…์˜ ์งˆ์ด ๋‚ฎ์•„์ง€๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ผ๊ณ  ํŒ๋‹จ๋˜์—ˆ์œผ๋ฉฐ ๋ชจ๋“  ์†Œ์Šค์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•˜์‹  ๋ถ„๋“ค์€ ๋Œ“๊ธ€์„ ๋‚จ๊ฒจ์ฃผ์„ธ์š” :)

์ผ๋‹จ ์–ด๋–ค ํŒจํ‚ค์ง€๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ๋จผ์ œ ํ™•์ธํ•ด๋ณด์ž.

  1. model
  2. controller
  3. service
  4. ifs

ํŒจํ‚ค์ง€

model
๋ชจ๋ธ ํŒจํ‚ค์ง€์—๋Š” Entity, Repository๋“ฑ๊ณผ ๊ฐ™์€ DB์— ๋งคํ•‘๋˜๊ฑฐ๋‚˜ ํ†ต์‹ ์˜ Body ๋ถ€๋ถ„์— ๋Œ€์‘ํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ ๋‹ด๊ธธ ํŒจํ‚ค์ง€์ด๋‹ค.
Entity, Repository๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค๊ฒŒ ๋  ๋„คํŠธ์›Œํฌ์— Header ๊ฐ์ฒด ๋˜ํ•œ model ํŒจํ‚ค์ง€์— ์กด์žฌํ•˜๊ฒŒ ๋œ๋‹ค.

controller
controller ํŒจํ‚ค์ง€๋Š” ์ž˜ ์•Œ๋””์‹ถ์ด controller๊ฐ€ ์œ„์น˜ํ•˜๊ฒŒ ๋  ํŒจํ‚ค์ง€์ด๋‹ค.

service
service ํŒจํ‚ค์ง€ ๋˜ํ•œ ์•Œ๋‹ค์‹ถ์ด controller์—์„œ ์‚ฌ์šฉํ•˜๊ฒŒ ๋  service logic์ด ๋ชจ์—ฌ์žˆ๋Š” ํŒจํ‚ค์ง€๋ผ๊ณ  ์ƒ๊ฐํ•ด๋‘์ž.

ifs
์ด ๋ถ€๋ถ„๊ณผ model ํŒจํ‚ค์ง€๊ฐ€ ์ด๋ฒˆ ํฌ์ŠคํŒ…์— ํ•ต์‹ฌ์ธ ๋…€์„๋“ค์ด๋‹ค.
์šฐ๋ฆฌ๋Š” ๋ชจ๋“  ์„œ๋น„์Šค ๋กœ์ง์—์„œ ๊ณตํ†ต๋˜๋Š” ๋ถ€๋ถ„, ์ฆ‰ CRUD๋ฅผ ํ•˜๋‚˜์˜ ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ์ƒ์†๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ๊ฐ•์ œํ™” ํ•  ๊ฒƒ์ด๋‹ค.
๊ทธ๋Ÿฐ ์˜๋ฏธ์—์„œ ifs ํŒจํ‚ค์ง€๋Š” CrudInterface๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์กด์žฌํ•  ์ธํ„ฐํŽ˜์ด์Šค ํŒจํ‚ค์ง€ ์ด๋‹ค.

ํด๋ž˜์Šค

ํด๋ž˜์Šค๋ฅผ ํŒจํ‚ค์ง€์˜ ํ•˜์œ„์— ์–ด๋–ค ํด๋ž˜์Šค๊ฐ€ ์žˆ์„์ง€ ๋จผ์ € ์ƒ๊ฐํ•ด๋ณด์ž.

๊ฐ€์žฅ ์‰ฌ์šด controller, service๋Š” ๋‹จ์ง€ ์ € ๋‘ ๋กœ์ง์˜ ํด๋ž˜์Šค๋งŒ ์žˆ์„ ๊ฒƒ์ด๋‹ˆ model์„ ์ค‘์ ์ ์œผ๋กœ ์ด์•ผ๊ธฐ ํ•ด๋ณด์ž.

model

  • entity : ์‹ค์ œ DB์™€ ๋งคํ•‘๋  JPA ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค
  • request : Header์— Data(Entity)๊ฐ€ ๊ฒฐํ•ฉ๋˜์–ด ์‹ค์ œ ํ†ต์‹ ์— ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” Request ํด๋ž˜์Šค
  • response : Request๊ฐ€ ์„œ๋น„์Šค ๋กœ์ง์— ์˜ํ•ด ๊ฐ€๊ณต๋œ Data๋ฅผ Header์™€ ๊ฒฐํ•ฉ๋œ Response ํด๋ž˜์Šค
  • header : ์š”์ฒญ์— ํ•„์š”ํ•œ Header ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ํด๋ž˜์Šค

์ด๋ ‡๊ฒŒ 4๊ฐ€์ง€๊ฐ€ ์œ„์น˜ํ•  ๊ฒƒ์ด๋‹ค.

JPA ๊ตฌ์„ฑ

๋จผ์ € ๊ฐ„๋‹จํ•œ ํ†ต์‹  ํ…Œ์ŠคํŠธ๋กœ JPA๋ฅผ ๊ตฌ์„ฑํ•ด๋ณด์ž.

User

package com.example.demo.model;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;

    private String password;
}

UserRepository

package com.example.demo.repository;

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

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

์ด์ œ ๊ฐ„๋‹จํ•œ JPA๋ฅผ ์ƒ์„ฑํ–ˆ๊ณ , controller, service์—์„œ CRUD๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด๋ณด์ž

๋„คํŠธ์›Œํฌ ๊ด€๋ จ ๊ฐ์ฒด ์ค€๋น„

UserRequest

package com.example.demo.model.network;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserRequest {
    private String account;
    private String password;
    private String name;
}

UserResponse

package com.example.demo.model.network;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserResponse {
    private String account;
    private String password;
    private String name;
}

์ด๋ ‡๊ฒŒ ๋‘ ๊ฐœ์˜ Request, Response ํด๋ž˜์Šค๋ฅผ ๊ฐ๊ฐ ์ƒ์„ฑํ•ด์ค€๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋Œ€๋ง์˜ Header ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•  ์ฐจ๋ก€

์—ฌ๊ธฐ์„œ ์ œ๋„ˆ๋ฆญ์ด ์–ด๋–ป๊ฒŒ ์“ฐ์ด๋ƒ?

๋ฐ”๋กœ ๊ณตํ†ต๋œ ๋ถ€๋ถ„์˜ Header์— ์‚ฌ์šฉํ•˜๋ฉด ์ œ๋„ˆ๋ฆญ์„ ์ข€ ๋” ์šฐ์•„ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.

Header ํด๋ž˜์Šค

Header ํด๋ž˜์Šค๋Š”

  • transaction_time (ํ†ต์‹  ์‹œ๊ฐ)
  • status (ํ†ต์‹  ์ƒํƒœ ์ฝ”๋“œ OK, ERROR)
  • description (์„ธ๋ถ€ ๋‚ด์šฉ:: ํ†ต์‹ ์ด ๋ฐœ์ƒํ•œ ์„œ๋ฒ„ ์ฃผ์ฒด)

๊ณผ ๊ฐ™์€ ๊ณตํ†ต ์ •๋ณด๋ฅผ ๊ฐ–๊ณ  ์žˆ๊ณ , ๋งค ์š”์ฒญ๊ณผ ์‘๋‹ต๋งˆ๋‹ค ์ •๋ณด๋ฅผ ๋„˜๊ฒจ์•ผ ํ•˜๋ฏ€๋กœ Header๋ผ๋Š” ํด๋ž˜์Šค์˜ ํ•„๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@SuppressWarnings("unchecked")
class Header {
    private LocalDateTime transaction_time;
    private String status;
    private String description
}

์—ฌ๊ธฐ์„œ ์ฒซ ๋ฒˆ์งธ ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ—ค๋”๋Š” ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ๊ฐ์‹ธ์•ผ ํ•˜๋ฏ€๋กœ Header ํด๋ž˜์Šค์—๋Š” UserApiRequest, UserApiResponse ํด๋ž˜์Šค์˜ ํƒ€์ž…๋งŒ ๋“ค์–ด์˜จ๋‹ค.
์ด๋Š” ์กฐ๊ธˆ ๋” ํ™•๋Œ€ํ•ด์„œ ํ•ด์„ํ•˜์ž๋ฉด ํ—ค๋”๋Š” ์–ด์ฐจํ”ผ ์š”์ฒญ๊ณผ ์‘๋‹ต์—๋งŒ ๊ด€์—ฌ๋ฅผ ํ•˜๋Š” ๋ฐ์ดํ„ฐ ๊ฐ์ฒด์ด๋ฏ€๋กœ 2๊ฐ€์ง€์˜ ํƒ€์ž…์ด ๋“ค์–ด์˜จ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋Ÿผ ์šฐ๋ฆฌ๋Š” ํƒ€์ž… ์ฒดํฌ๋ฅผ ์œ„ํ•ด ์ œ๋„ˆ๋ฆญ์ด๋ผ๋Š” ์„ ํƒ์ง€๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ธฐ์กด์˜ Header ํด๋ž˜์Šค์—์„œ ํƒ€์ž…์„ ๋ถ™ํ˜€์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ๋งŒ๋“ค์–ด๋ณด์ž.

package com.example.demo.model.network;

import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@SuppressWarnings("unchecked")
public class Header<T> {
    private LocalDateTime transaction_time;
    private String status;
    private String description;
}

์ฒซ ๋ฒˆ์จฐ์˜ ์ œ๋„ˆ๋ฆญ์„ ์‚ฌ์šฉํ•ด์„œ ์ปดํŒŒ์ผ ์‹œ์ ์— ํƒ€์ž…์„ ์ฒดํฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ–ˆ๋‹ค.

์ด์ œ Header์˜ ๊ธฐ๋Šฅ์„ ์™„๋ฒฝํ•˜๊ฒŒ ๋งŒ๋“ค์–ด๋ณด์ž.

์—ฌ๊ธฐ์„œ ๋ง ํ•˜๋Š” ์™„๋ฒฝํ•˜๊ฒŒ๋Š” ๋ชจ๋“  ์š”์ฒญ์— ํ†ต์‹  ์‹œ๊ฐ, ํ†ต์‹  ์ฝ”๋“œ, ์ถ”์‹ , ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ

Header ํด๋ž˜์Šค์—์„œ Static์œผ๋กœ ์š”์ฒญ์˜ ์„ฑ๊ณต๊ณผ ์‹คํŒจ ์—ฌ๋ถ€๋ฅผ OK, ERROR ๋ฉ”์„œ๋“œ๋กœ ๋ถ„๋ฆฌ์‹œ์ผœ๋ณด์ž.

๋ฉ”์„œ๋“œ๋ฅผ ์ œ๋„ค๋ฆญ ๋ฉ”์„œ๋“œ๋กœ ๋งŒ๋“ค์–ด์ฃผ๊ณ  ๋‹จ์ˆœ ์„ฑ๊ณต OK์™€ ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•˜๋Š” ์„ฑ๊ณต OK(T data) ๊ทธ๋ฆฌ๊ณ  ์‹คํŒจ ERROR() ์ด ์„ธ ๊ฐ€์ง€์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.

package com.example.demo.model.network;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@SuppressWarnings("unchecked")
public class Header<T> {
    private LocalDateTime transaction_time;
    private String status;
    private String description;

    private T data; // ์ œ๋„ค๋ฆญ ๋ฐ์ดํ„ฐ

    public static <T> Header<T> OK(){
        return (Header<T>)Header.builder()
                .transaction_time(LocalDateTime.now())
                .status("OK")
                .description("From UserApi")
                .build();
    }

    public static <T> Header<T> OK(T data) {
        return (Header<T>) Header.builder()
                .transaction_time(LocalDateTime.now())
                .status("Data-OK")
                .description("From UserAPI")
                .build();
    }

    public static <T> Header<T> ERROR() {
        return (Header<T>) Header.builder()
                .transaction_time(LocalDateTime.now())
                .status("ERROR")
                .description("From UserAPI")
                .build();
    }

}

๊ณตํ†ต ๋ถ€๋ถ„์„ ํ•˜๋‚˜์˜ Interface๋กœ

๊ณตํ†ต ๋ถ€๋ถ„์ธ CRUD๋ฅผ ํ•˜๋‚˜์˜ CrudInterface๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด CrudInterface ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

์—ฌ๊ธฐ์„œ๋„ ์ œ๋„ค๋ฆญ์„ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์„์ง€ ์ƒ๊ฐํ•ด๋ณด์ž.

์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•˜๋ฉด ํŠน์ • ๊ฐ์ฒด๋งŒ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ์ œํ•œํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ–ˆ๋‹ค.

๊ทธ๋Ÿผ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋“ค์ด CrudInterface๋ฅผ ์‚ฌ์šฉํ• ๊นŒ?

์ •๋‹ต์ด๋‹ค.
๋ฐ”๋กœ UserRequest, UserResponse, ItemRequest, ItemResponse, OrderRequest, OrderResponse๊ฐ€ ์žˆ๋‹ค.
ํ•˜์ง€๋งŒ ์ด ์š”์ฒญ๊ณผ ์‘๋‹ต ๊ฐ์ฒด๋“ค์€ ์„œ๋กœ ํ•จ๊ป˜ ์›€์ง์—ฌ์•ผ ํ•œ๋‹ค.
๋ฌด์Šจ ๋ง์ด๋ƒ๋ฉด Request๊ฐ€ ๋“ค์–ด์˜ค๋ฉด Response๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ๊ธฐ๋ณธ ๋งค์ปค๋‹ˆ์ฆ˜์ด๋‹ค.
์ด๋“ค ๋ชจ๋‘๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š” ์ œ๋„ค๋ฆญ์€ ๋ฐ”๋กœ <Request, Response>์ด๋‹ค. ๊ทธ๋Ÿผ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž

package com.example.demo.ifs;

public interface CrudInterface<Request, Response> {
    Response create(Request request);

    Response read(Long id);

    Response update(Request request);

    Response delete(Long id);
}

์—ฌ๊ธฐ์„œ ์ž ๊น, read()์™€ delete()๋Š” ์™œ request๊ฐ€ ์•„๋‹ˆ๋ผ ID ์ผ์ง€ ์ƒ๊ฐํ•ด๋ณด์ž.
์šฐ๋ฆฌ๋Š” ์‚ฌ์šฉ์ž์˜ ๊ฒ€์ƒ‰์— ๋Œ€ํ•œ ์š”์ฒญ์„ PathVariable ํ˜•ํƒœ๋กœ ๋ฐ›์„ ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์‚ฌ์‹ค์ƒ ์š”์ฒญ ๋ฐ์ดํ„ฐ์—๋Š” url์˜ ๊ฒฝ๋กœ๊ฐ€ ์‚ฌ์šฉ๋  ๊ฒƒ์ด๋ฏ€๋กœ ํ†ต์‹  ๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ Primitive ํ˜•ํƒœ์ด๋ฏ€๋กœ Long ํ˜•ํƒœ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์ด๋Ÿฐ ์‹์œผ๋กœ CRUD ๋ฉ”์„œ๋“œ๋งˆ๋‹ค ์š”์ฒญ๊ณผ ์‘๋‹ต์ด ์„œ๋กœ ์กด์žฌํ•˜๋Š” ํ˜•ํƒœ๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค.
ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ ๋ชจ๋“  ์š”์ฒญ๊ณผ ์‘๋‹ต์€ Header์— ์˜ํ•ด ๊ฐ์‹ธ์ ธ์•ผ ํ•œ๋‹ค๊ณ  ํ–ˆ์œผ๋ฏ€๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐ”๋€Œ๋Š”๊ฒŒ ๋”์šฑ ์ ์ ˆํ•˜๋‹ค.

package com.example.demo.ifs;

import com.example.demo.model.network.Header;

public interface CrudInterface<Request, Response> {
    Header<Response> create(Header<Request> request);

    Header<Response> read(Long id);

    Header<Response> update(Header<Request> request);

    Header delete(Long id);
}

๋งˆ์ง€๋ง‰ delete ๋ฉ”์„œ๋“œ์—๋Š” responseํ•  ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ž ์‹œ ๋บด๋‘์ž.

์ด์ œ ๋ชจ๋“  ์ค€๋น„๊ฐ€ ๋๋‚ฌ๋‹ค.

์‹ค์ œ ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค๋ฉด์„œ ์šฐ๋ฆฌ๊ฐ€ ์˜ˆ์ƒํ–ˆ๋˜ ์ฝ”๋“œ๊ฐ€ ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž.


Service ๊ตฌํ˜„

UserService

package com.example.demo.service;

import com.example.demo.ifs.CrudInterface;
import com.example.demo.model.network.Header;
import com.example.demo.model.network.UserRequest;
import com.example.demo.model.network.UserResponse;
import com.example.demo.repository.UserRepository;
import org.springframework.stereotype.Service;

@Service
public class UserService implements CrudInterface<UserRequest, UserResponse> {
    @Override
    public Header<UserResponse> create(Header<UserRequest> request) {
        return null;
    }

    @Override
    public Header<UserResponse> read(Header<UserRequest> request) {
        return null;
    }

    @Override
    public Header<UserResponse> update(Header<UserRequest> request) {
        return null;
    }

    @Override
    public Header delete(Header<UserRequest> request) {
        return null;
    }
}

์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ์„œ๋น„์Šค ์ฝ”๋“œ์— CrudInterface ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์ค€๋‹ค๋ฉด ์•„๋งˆ ์œ„์™€ ๊ฐ™์€ ์ƒํƒœ์˜ ์ฝ”๋“œ๊ฐ€ ๋‚˜ํƒ€๋‚˜๊ฒŒ ๋œ๋‹ค.

์ด์ œ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ณผ์ •๋งŒ ๋‚จ์•˜๋‹ค.

create ๋ฉ”์„œ๋“œ ์ž‘์„ฑ

create ๋ฉ”์„œ๋“œ ์ž‘์„ฑ์˜ ์ˆœ์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  1. request์—์„œ Data ๋ถ€๋ถ„ ๊ฐ€์ ธ์˜ค๊ธฐ
  2. Data๋ถ€๋ถ„์„ User ๊ฐ์ฒด์™€ ๋งคํ•‘
  3. Jpa ๋ ˆํฌ์ง€ํ† ๋ฆฌ save
  4. response ๋ฐ์ดํ„ฐ๋กœ ๋ฐ”๊พธ๊ธฐ
  5. Header์— Data ๋ถ€๋ถ„์„ response๋กœ ์ง€์ •
@Override
public Header<UserResponse> create(Header<UserRequest> request) {
    UserRequest userRequest = request.getData();

    User user = User.builder()
            .username(userRequest.getUsername())
            .password(userRequest.getPassword())
            .name((userRequest.getName()))
            .build();

    User newUser = userRepository.save(user);

    UserResponse userResponse = UserResponse.builder()
            .username(newUser.getUsername())
            .password(newUser.getPassword())
            .name(newUser.getName())
            .build();

    return Header.OK(userResponse);
}

read ๋ฉ”์„œ๋“œ ์ž‘์„ฑ

read ๋ฉ”์„œ๋“œ์˜ ์ž‘์„ฑ ์ˆœ์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  1. Path Variable์˜ ๊ฐ’์„ ํ† ๋Œ€๋กœ repository์— findById ์‹คํ–‰
  2. ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ Header๊ฐ€ ํฌํ•จ๋œ response๋กœ ๋ณ€๊ฒฝ

read ๋ฉ”์„œ๋“œ๋Š” ํฐ ํž˜์ด ํ•„์š”ํ•˜์ง€ ์•Š์ง€๋งŒ ์•ฝ๊ฐ„ ๊นŒ๋‹ค๋กœ์šธ ์ˆ˜ ์žˆ๋Š”๊ฒŒ, ๋žŒ๋‹ค์— ์ต์ˆ™ํ•˜์ง€ ์•Š์€ ์‚ฌ๋žŒ๋“ค์ด ์ดํ•ดํ•˜๊ธฐ ํž˜๋“  ์ฝ”๋“œ๊ฐ€ ๋‚˜์˜จ๋‹ค.
์ด๋ฒˆ์‹œ๊ฐ„์€ ๋žŒ๋‹ค์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ฏ€๋กœ ๋„˜์–ด๊ฐ€๊ฒ ์ง€๋งŒ ๋ธ”๋กœ๊ทธ์˜ ๋žŒ๋‹ค ๊ฒŒ์‹œ๊ธ€์„ ํ†ตํ•ด ํ•™์Šตํ•ด๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์€ ๊ฒฝํ—˜์ด ๋  ๊ฒƒ์ด๋‹ค.

๋Œ“๊ธ€