๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
  • ์žฅ์›์ต ๊ธฐ์ˆ ๋ธ”๋กœ๊ทธ
๐Ÿ“š ์‹œ๋ฆฌ์ฆˆ/- Jenkins์™€ Webhook์„ ์ด์šฉํ•œ CICD

[Webhook์„ ์ด์šฉํ•˜์—ฌ CI CD ๊ตฌ์„ฑํ•˜๊ธฐ] - ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœํ•˜๊ธฐ

by Wonit 2021. 8. 30.

ํ•ด๋‹น ๊ธ€์€ Jenkins์™€ Github Webhook์„ ์ด์šฉํ•œ CICD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์„ฑํ•˜๊ธฐ ์‹œ๋ฆฌ์ฆˆ ์ž…๋‹ˆ๋‹ค. ์ž์„ธํ•œ ์‚ฌํ•ญ์€ ์•„๋ž˜ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”!

 

๋งŒ์•ฝ ํ•ด๋‹น ์‹ค์Šต ๋‚ด์šฉ์˜ ์ฝ”๋“œ๊ฐ€ ๊ถ๊ธˆํ•˜๋‹ค๋ฉด ํ”„๋กœ์ ํŠธ ๊นƒํ—ˆ๋ธŒ ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

 

์ˆœ์„œ

  • ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ๋ฐ ์„ธํŒ…
  • Model ๊ฐœ๋ฐœ
  • Service ๊ฐœ๋ฐœ
  • Controller ๊ฐœ๋ฐœ
  • Filter ๊ฐœ๋ฐœ
  • ์ดˆ๊ธฐ data๋ฅผ ์œ„ํ•œ import.sql ์ž‘์„ฑ
  • ํ”„๋ก ํŠธ์™€ ๋ฐฑ E2E ์—ฐ๊ฒฐํ•˜๊ธฐ

 

๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœํ•˜๊ธฐ

 

์˜ค๋Š˜์€ CICD ํŒŒ์ดํ”„๋ผ์ธ์„ ์œ„ํ•ด์„œ ํ•„์š”ํ•œ ๋ฐฑ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•ด๋ณด๋ ค ํ•œ๋‹ค.

 

๋ฐฑ์—”๋“œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์‹œ๋ฆฌ์ฆˆ ์‹œ์ž‘์— ์–ธ๊ธ‰ํ•˜์˜€๋“ฏ Spring Boot ๋ฅผ ์ด์šฉํ•  ๊ฒƒ์ด๋‹ค.

 

Spring Boot ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜์กด์„ฑ๋“ค์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ˆ ๋ฏธ๋ฆฌ ํ•ด๋‹น ์˜์กด์„ฑ์„ ๋ณด๊ณ  ์–ด๋–ค ํ๋ฆ„์ด๊ฒ ๊ตฌ๋‚˜~ ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž.

 

  • Spring boot Web
  • Spring Data JPA
  • H2 Databse
  • Lombok
    • java ์ƒ์‚ฐ์„ฑ์„ ์œ„ํ•œ ์˜์กด์„ฑ
  • ModelMapper
    • Dto to Entity ๋ณ€ํ™˜์„ ์œ„ํ•œ ๋งคํผ

 

1. ํ”„๋กœ์ ํŠธ ์…์„ฑ ๋ฐ ์„ธํŒ…ํ•˜๊ธฐ

 

ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ์„ ์œ„ํ•ด์„œ ์ด์ „์— Frontend ๋ฅผ ๊ฐœ๋ฐœํ•œ Git ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๊ฐ€์„œ backend ๋ผ๋Š” ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  Spring Initializer ๋ฅผ ์ด์šฉํ•˜์—ฌ Backend ๋ผ๋Š” Spring Boot Project๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

 

๋‚˜๋Š” Intellij ๋ฅผ ์ด์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— IDE GUI๋ฅผ ์ด์šฉํ•ด์„œ ์„ธํŒ…ํ–ˆ์ง€๋งŒ Intellij ์—†์ด vscode ๋‚˜ ์ดํด๋ฆฝ์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด Spring Initializer ์—์„œ ์ง์ ‘ zip ํŒŒ์ผ๋กœ ๋‚ด๋ ค๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

 

๋Œ€์ถฉ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜์กด์„ฑ๋งŒ ๊ฐ€์ง€๊ฒŒ ํ•˜๋ฉด๋œ๋‹ค.

 

 

์–ด๋–ค ๊ณผ์ •์„ ๊ฑฐ์น˜๋˜ ์šฐ๋ฆฌ์˜ Git Repository์— /backend ๋ผ๋Š” ๋””๋ ‰ํ† ๋ฆฌ์— ์œ„์น˜์‹œ์ผœ์ฃผ๋ฉด ๋œ๋‹ค.

 

์ถ”๊ฐ€ ์˜์กด์„ฑ ModelMapper ์ถ”๊ฐ€ํ•˜๊ธฐ ๋ฐ Bean ์ฃผ์ž…

 

ModelMapper ๋Š” ๋Œ€ํ‘œ์ ์œผ๋กœ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” user lib ์ด๋‹ค.

 

์ฃผ๋กœ ํด๋ž˜์Šค๊ฐ„ Converting ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š”๋ฐ, ์šฐ๋ฆฌ์˜ ๊ฒฝ์šฐ์—๋Š” DTO๋ฅผ ์ด์šฉํ•ด์„œ ๋„คํŠธ์›Œํฌ ํ†ต์‹  ๊ฐ์ฒด๋ฅผ ์ •์˜ํ•œ๋‹ค.

 

๋งŒ์•ฝ Spring Converter ์— ์˜ํ•ด์„œ ์š”์ฒญ์ด Json Raw ํƒ€์ž…์ด๋ผ๋ฉด ObjectMapper๊ฐ€ ์ด๋ฅผ DTO๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š”๋ฐ, ์—ฌ๊ธฐ๊นŒ์ง€๋Š” Spring์ด ํ•ด์ฃผ๊ณ  ์šฐ๋ฆฌ๋Š” ๋ฐ”๊ฟ”์ง„ DTO๋ฅผ ๋˜ JPA ๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก Entity๋กœ ์ปจ๋ฒ„ํŒ…์„ ํ•ด์•ผํ•œ๋‹ค.

 

์ด ๊ณผ์ •์—์„œ ModelMapper ๊ฐ€ ์‚ฌ์šฉ๋œ๋‹ค.

 

๊ทธ๋ž˜์„œ ModelMapper๋ฅผ build.gradle ์— ์˜์กด์„ฑ ์ถ”๊ฐ€๋ฅผ ํ•ด์ฃผ์ž

 

dependencies {
  implementation 'org.modelmapper:modelmapper:2.1.1'
}

 

๊ทธ๋ฆฌ๊ณ  gradle ํ”„๋กœ์ ํŠธ๋ฅผ reload ํ•œ ๋’ค, ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ Bean ์œผ๋กœ ๋“ฑ๋ก์‹œ์ผœ์•ผ ํ•œ๋‹ค.

 

@SpringBootApplication
public class JenkinsCicdTodoCIApplication {

    public static void main(String[] args) {
        SpringApplication.run(JenkinsCicdTodoApplication.class, args);
    }

    @Bean
    public ModelMapper modelMapper() {
        return new ModelMapper();
    }
}

 

ํ•ด๋‹น application ์˜ main ํ•จ์ˆ˜ ์•„๋ž˜์— Bean ์œผ๋กœ ๋“ฑ๋ก์‹œํ‚ค๊ธฐ ์œ„ํ•œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์ž

 

application.yml ์œผ๋กœ ์™ธ๋ถ€ ์„ค์ • ๊ด€๋ฆฌํ•˜๊ธฐ

 

๋งŒ์•ฝ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ž˜ ์ƒ์„ฑ๋˜์—ˆ๋‹ค๋ฉด Spring ์˜ ์™ธ๋ถ€ ์„ค์ •์„ ์กฐ์ž‘ํ•ด๋ณด์ž

 

์™ธ๋ถ€ ์„ค์ •์€ ๋ณดํ†ต application.properties ํŒŒ์ผ์—์„œ ํ•˜๊ฒŒ ๋œ๋‹ค.

 

ํ•˜์ง€๋งŒ properties ํŒŒ์ผ์€ ๊ฐ€๋…์„ฑ์ด ์ข‹์ง€ ๋ชปํ•˜๊ธฐ ๋–„๋ฌธ์— ๊ฐœ์ธ์ ์œผ๋กœ๋Š” yml ํƒ€์ž…์˜ ์„ค์ • ํŒŒ์ผ์„ ์ข‹์•„ํ•œ๋‹ค.

 

resources ๋””๋ ‰ํ† ๋ฆฌ ์•„๋ž˜์— ์žˆ๋Š” application.properties ํŒŒ์ผ์„ ์‚ญ์ œํ•˜๊ณ  application.yml ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜์ž!

๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ช…์‹œํ•ด์ค€๋‹ค.

 

spring:
  h2:
    console:
      path: /h2-console
      enabled: true
      settings:
        web-allow-others: true
  datasource:
    driver-class-name: org.h2.Driver
    username: sa
    password:
    url: jdbc:h2:mem:todo
  jpa:
    hibernate:
      ddl-auto: create-drop

 

ํ•ด๋‹น ์‹œ๋ฆฌ์ฆˆ๋Š” Spring๊ณผ JPA ์— ๋Œ€ํ•œ ์„ค๋ช…์ด ์•„๋‹ˆ๋ฏ€๋กœ ๊ฐ„๋žตํžˆ๋งŒ ๋ณด๊ณ  ๋„˜์–ด๊ฐ€์ž๋ฉด,

 

  • H2 DB๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • ์›น์—์„œ H2 DB ์ฝ˜์†”์— ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•œ๋‹ค
  • DB์— ๋“ค์–ด๊ฐˆ ๋ฐ์ดํ„ฐ๋Š” in memory ์—์„œ ๊ด€๋ฆฌ๋œ๋‹ค.
  • ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๊ฐ€ ddl ์„ ์•ฑ์„ ์‹คํ–‰์‹œํ‚ค๋ฉด create ํ•˜๊ณ  ์•ฑ์ด ์ข…๋ฃŒ๋˜๋ฉด drop ํ•œ๋‹ค

 

์ด์ œ ํ™˜๊ฒฝ ์„ค์ •์ด ์™„๋ฃŒ๋˜์—ˆ์œผ๋‹ˆ ์šฐ๋ฆฌ์˜ ์•ฑ์„ ๊ตฌ๋™์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ํด๋ž˜์Šค๋“ค์„ ๋ฏธ๋ฆฌ ๋งŒ๋“ค๊ณ  ์‹œ์ž‘ํ•˜์ž.

 

๋‹ค์Œ๊ณผ ๊ฐ™์€ ํด๋ž˜์Šค๋“ค์„ ๋งŒ๋“ค์–ด์ฃผ๋ฉด ๋œ๋‹ค.

 

 

  • CorsFilter.java : CORS Filter
  • JenkinsCicdTodoApplication.java : Application Entrypoints
  • Todo.java : JPA Entity
  • TodoController.java : API Endpoints
  • TodoRepository.java : Repository
  • TodoRequestData.java : DTO
  • TodoService.java : Business Layer's Logic

2. Model ๊ฐœ๋ฐœํ•˜๊ธฐ

 

Model ์€ Layered Architecture ์—์„œ Model Layer ์— ํ•ด๋‹นํ•˜๋Š” ์ฝ”๋“œ๋“ค์„ ์˜๋ฏธํ•œ๋‹ค.

 

์—ฌ๊ธฐ์„œ ๊ตฌํ˜„ํ•ด์•ผํ•  ๊ฒƒ๋“ค์€ 3๊ฐœ์ด๋‹ค.

 

  1. JPA Entity
  2. Repository
  3. DTO

 

์‚ฌ์‹ค์ƒ Repository ๋Š” JpaRepository ๋ฅผ extendsํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ํฌ๊ฒŒ ํ•ด์•ผํ•  ๊ฒƒ๋“ค์€ ์—†๋‹ค.

 

๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์ž.

 

// Todo.java
@Entity @Setter @Getter
@NoArgsConstructor
@AllArgsConstructor
public class Todo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String content;
}

// TodoRepository.java
public interface TodoRepository extends JpaRepository<Todo, Long> {
}

// TodoRequestData.java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TodoRequestData {
    private String content;
}

 

DTO ์— ํฌํ•จ๋˜๋Š” ๋ฐ์ดํ„ฐ๋Š” content๋งŒ ์กด์žฌํ•œ๋‹ค.

 

์–ด์ฐจํ”ผ Repository ์—์„œ Entity๋ฅผ ์ €์žฅํ•  ๋•Œ, GenerationType ์„ IDENTITY๋กœ ์„ค์ •ํ•ด์คฌ๊ธฐ ๋•Œ๋ฌธ์— ๋‚ด๋ถ€์ ์œผ๋กœ AUTO_INCREMENTS๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค.

 

3. Service ๊ฐœ๋ฐœํ•˜๊ธฐ

 

Service๋Š” Controller ์—์„œ ๋“ค์–ด์˜จ DTO๋‚˜ ์š”์ฒญ์„ ๋ฐ›๊ณ , Repository๋กœ DB๋กœ ์กฐํšŒํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

 

์ฆ‰, Layered Architecture ์—์„œ View Layer์™€ Model ์‚ฌ์ด์— ์œ„์น˜ํ•˜๋Š” layer ๋กœ ์ดํ•ดํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค

 

@Service
@Transactional
public class TodoService {
    private final TodoRepository todoRepository;
    private final ModelMapper modelMapper;

    public TodoService(TodoRepository todoRepository, ModelMapper modelMapper) {
        this.todoRepository = todoRepository;
        this.modelMapper = modelMapper;
    }

    /**
     * ๋ชจ๋“  todo item ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
     *
     * @return List
     */
    public List<Todo> getTodos() {
        return todoRepository.findAll();
    }

    /**
     * content ๋ฅผ ๋ฐ›๊ณ  todo ๋ฅผ ์ €์žฅํ•œ๋‹ค.
     *
     * @param todoRequestData
     * @return ์ƒ์„ฑ๋œ Todo
     */
    public Todo createTodo(TodoRequestData todoRequestData) {
        return todoRepository.save(modelMapper.map(todoRequestData, Todo.class));
    }

    /**
     * id ๋ฅผ ๋ฐ›๊ณ  todo ๋ฅผ ์‚ญ์ œํ•œ๋‹ค.
     *
     * @param todoId todo id
     * @return ์‚ญ์ œ๋œ todo ์˜ id
     */
    public Long deleteTodo(Long todoId) throws Exception {
        Optional<Todo> optionalTodo = todoRepository.findById(todoId);

        if(optionalTodo.isEmpty()) {
            throw new Exception();
        }

        todoRepository.delete(optionalTodo.get());
        return todoId;
    }
}

 

Controller ์—์„œ

 

์›๋ž˜๋ผ๋ฉด Entity ๋กœ ๋ณ€ํ™˜๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋˜ DTO๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•˜์ง€๋งŒ ๊ทธ๋ƒฅ Entity ๋กœ ๋ฐ˜ํ™˜ํ–ˆ๋‹ค ใ…Žใ…Ž

 

4. Controller ๊ฐœ๋ฐœํ•˜๊ธฐ

 

์ด์ œ API ์„œ๋ฒ„์˜ Endpoint ์ธ Controller ๋ฅผ ๊ฐœ๋ฐœํ•ด๋ณด์ž.

 

@RestController
@RequestMapping(value = "/api/todos", produces = "application/json")
public class TodoController {
    private final TodoService todoService;

    public TodoController(TodoService todoService) {
        this.todoService = todoService;
    }

    @GetMapping
    public ResponseEntity<List<Todo>> getTodos() {
        return ResponseEntity.ok().body(todoService.getTodos());
    }

    @PostMapping
    public ResponseEntity<Todo> createTodo(@RequestBody TodoRequestData todoRequestData) {
        return ResponseEntity
                .status(HttpStatus.CREATED)
                .body(todoService.createTodo(todoRequestData));
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Long> deleteTodo(@PathVariable Long id) throws Exception {
        return ResponseEntity
                .status(HttpStatus.ACCEPTED)
                .body(todoService.deleteTodo(id));
    }
}

 

๋ชจ๋“  API์˜ Response ๋กœ๋Š” ResponseEntity ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•˜๊ณ  ResponseEntity.status์™€ ResponseEntity.body ๋กœ ๋ฐ์ดํ„ฐ์™€ ์ƒํƒœ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•œ๋‹ค.

 

5. CORS Filter ๊ฐœ๋ฐœํ•˜๊ธฐ

 

CORS ๋Š” ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ๋ฅผ ๋‚˜๋ˆ„๋Š” 3-tier ์•„ํ‚คํ…์ณ์—์„œ ์ค‘์š”ํ•œ ๋ณด์•ˆ ์š”์†Œ์ด๋‹ค.

 

CORS์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์„ค๋ช…์€ ํ•ด๋‹น ๋ธ”๋กœ๊ทธ์˜ OPTIONS ํ—ค๋”์™€ Preflight ๊ทธ๋ฆฌ๊ณ  CORS ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋‚˜๋Š” ๋ชจ๋“  ์š”์ฒญ์— ํŠน์ • ๋„๋ฉ”์ธ๋งŒ ํ—ˆ์šฉํ•˜๋Š” OPTIONS ํ—ค๋”๋ฅผ ๋ฐ˜ํ™˜ํ•  Filter๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ๋‹ค.

 

CORS๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์—๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”๋ฐ, CORS ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” 3๊ฐ€์ง€ ๋ฐฉ๋ฒ• ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods","*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept, Authorization");


        if("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        }else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void destroy() {

    }
}

 

์›๋ž˜๋ผ๋ฉด ์™ธ๋ถ€ ์„ค์ • ํŒŒ์ผ๋กœ ๋”ฐ๋กœ ๋นผ์„œ HOST PC์˜ IP๋ฅผ ๋ช…์‹œํ•ด์•ผ ํ•˜์ง€๋งŒ ์ผ๋‹จ์€ ๊ฐ„๋‹จํ•œ Jenkins ๊ตฌ์„ฑ์„ ์œ„ํ•ด์„œ * ์™€์ผ๋“œ์นด๋“œ๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ ์ด๋Š” ๋ณด์•ˆ์ ์œผ๋กœ ๋งค์šฐ ์ทจ์•ฝํ•˜๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ด์ œ ๋ชจ๋“  API ๊ฐœ๋ฐœ์ด ๋๋‚ฌ๋‹ค!

 

๋‚จ์€ ๊ฒƒ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ–ˆ์„ ๋•Œ, ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ๋ฅผ ์‹ฌ์–ด์ฃผ๋Š” import.sql ๋งŒ ๋งŒ๋“ค๊ณ  ํ”„๋ก ํŠธ์—”๋“œ์™€ ์—ฐ๋™ํ•ด๋ณด๋„๋ก ํ•˜์ž

 

6. ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ์œ„ํ•œ import.sql ์ž‘์„ฑํ•˜๊ธฐ

 

import.sql ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํ–‰ํ•˜๋Š” ์‹œ์ ์— ํ•ด๋‹น ํŒŒ์ผ์— ์žˆ๋Š” ์ฟผ๋ฆฌ๋ฌธ์„ ์‹คํ–‰์‹œํ‚จ๋‹ค.

 

์šฐ๋ฆฌ๋Š” JPA์˜ ddl-auto ์†์„ฑ์„ ํ†ตํ•ด์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋™์ž‘ํ•˜๋Š” ์‹œ์ ์— DDL ๋ฌธ๋งŒ ์‹คํ–‰ํ•˜๋„๋ก ํ–ˆ๋‹ค.

 

๊ทธ๋Ÿผ ๊ฒฐ๊ตญ DB ํ…Œ์ด๋ธ”์—๋Š” ๋น„์–ด์žˆ๋Š” ๋ฐ์ดํ„ฐ๋งŒ ์žˆ์„ ๊ฒƒ์ด๊ณ , Front ์—์„œ DB์— ์ €์žฅํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๋งค๋ฒˆ ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

 

์ด ๊ณผ์ •์„ ์—†์• ๊ณ  ์ž๋™ํ™” ์‹œํ‚ค๊ธฐ ์œ„ํ•ด์„œ ๋‚˜๋Š” ์ฃผ๋กœ import.sql ์„ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ์ด์šฉํ•œ๋‹ค.

 

import.sql ์„ ์ด์šฉํ•ด์„œ ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ฃผ์ž

 

 

import.sql ์€ /resources ๋””๋ ‰ํ† ๋ฆฌ ์•„๋ž˜์— ์œ„์น˜์‹œ์ผœ์ฃผ๋ฉด ๋œ๋‹ค.

 

INSERT INTO todo(content) VALUES ('๋ฆฌ๋•์Šค ํ•™์Šตํ•˜๊ธฐ');
INSERT INTO todo(content) VALUES ('Greedy ์•Œ๊ณ ๋ฆฌ์ฆ˜ 5๋ฌธ์ œ ํ’€๊ธฐ');
INSERT INTO todo(content) VALUES ('Jenkins Backend ๊ตฌ์„ฑํ•˜๊ธฐ');
INSERT INTO todo(content) VALUES ('๋ชจ๋‹ˆํ„ฐ ์ฒญ์†Œ');
INSERT INTO todo(content) VALUES ('๋ธ”๋กœ๊ทธ ํฌ์ŠคํŒ… ์ค€๋น„ํ•˜๊ธฐ');
INSERT INTO todo(content) VALUES ('Effective Java ์ฝ๊ธฐ');

 

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

 

ํ”„๋ก ํŠธ์™€ ์—ฐ๋™ํ•ด๋ณด์ž.

 

ํ”„๋ก ํŠธ์—”๋“œ์™€ E2E ์—ฐ๋™ํ•˜๊ธฐ

 

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

 

์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•œ ๋ฐฑ์—”๋“œ์˜ API ๋ฅผ ํ™•์ธํ•ด๋ณด์ž.

 

  • GET /api/todos : ํˆฌ๋‘ ๋ฆฌ์ŠคํŠธ์˜ ๋ชจ๋“  ํˆฌ๋‘๋ฅผ ์กฐํšŒํ•œ๋‹ค.
  • POST /api/todos : ํˆฌ๋‘ ๋ฆฌ์ŠคํŠธ์— ํˆฌ๋‘๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
  • DELETE /api/todos/{id} : ํˆฌ๋‘ ๋ฆฌ์ŠคํŠธ์— ํŠน์ • ํˆฌ๋‘๋ฅผ ์‚ญ์ œํ•œ๋‹ค

 

ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ ์œ„์น˜ํ•ด์žˆ๋Š” /frontend ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๊ฐ€์„œ npm start ๋ช…๋ น์„ ์ˆ˜ํ–‰ํ•˜์ž

 

๊ทธ๋Ÿผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด API ์š”์ฒญ์ด ์‹คํŒจํ•  ๊ฒƒ์ด๋‹ค.

 

 

์ด๋Š” ๋‹น์—ฐํžˆ ๋ฐฑ์—”๋“œ๊ฐ€ ๋Œ์•„๊ฐ€์ง€ ์•Š๊ณ  ์žˆ์œผ๋‹ˆ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๊ณ  /backend ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๊ฐ€์„œ ๋ฐฑ์—”๋“œ๋ฅผ ์‹คํ–‰์‹œ์ผœ์ฃผ์ž

 

๊ทธ๋ฆฌ๊ณ  ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ๋‹ค์‹œ ์ƒˆ๋กœ๊ณ ์นจ ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด Data Fetching ์ด ์ž˜ ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

์ด์ œ CICD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์„ฑ์„ ์œ„ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ์˜ ์ค€๋น„๋Š” ๋ชจ๋‘ ๋๋‚ฌ๋‹ค.

 

๋‹ค์Œ ์‹œ๊ฐ„์—๋Š” ์ง์ ‘ EC2๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋ฉฐ Jenkins๋ฅผ ์„ค์น˜ํ•ด๋ณด๋„๋ก ํ•˜์ž!

 

๋Œ“๊ธ€