[TIL] ๐Ÿ› ๏ธ์ผ์ •๊ด€๋ฆฌ ํ•„์ˆ˜ ์„ค๊ณ„/ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

YJinยท2025๋…„ 3์›” 25์ผ

[๋‚ด๋ฐฐ์บ  Spring 6๊ธฐ_TIL]

๋ชฉ๋ก ๋ณด๊ธฐ
16/56

API ์„ค๊ณ„

๐Ÿ”— ๐Ÿ“„ Schedule Project API ๋ฌธ์„œ


ERD ์„ค๊ณ„




DB ์ƒ์„ฑ

์„ค์ •

application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/database_name
spring.datasource.username=name
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.sql.init.schema-locations=classpath:schema_file
spring.sql.init.mode=always

์Šคํ‚ค๋งˆ

CREATE DATABASE IF NOT EXISTS schedule;
USE schedule;
CREATE TABLE IF NOT EXISTS event
(
    id           BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '๊ณ ์œ  ์‹๋ณ„์ž',
    task         VARCHAR(50),
    created_time TIMESTAMP   NOT NULL COMMENT '์ƒ์„ฑ ๋‚ ์งœ',
    edited_time  TIMESTAMP   NOT NULL COMMENT '์ˆ˜์ •๋œ ๋‚ ์งœ',
    owner        VARCHAR(25) NOT NULL COMMENT '์ž‘์„ฑ์ž๋ช…',
    password     VARCHAR(25) NOT NULL COMMENT '๋น„๋ฐ€๋ฒˆํ˜ธ'
);



ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

DB ๊ตฌ์„ฑ

๐Ÿ“Œ ๋ฌธ์ œ

โ›” ๋ฌธ์ œ

์Šคํ”„๋ง๋ถ€ํŠธ ์•ฑ ์‹คํ–‰ ์‹œ, ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€ ๋ฐœ์ƒํ•˜๋ฉฐ ์‹คํ–‰์ด ๋˜์ง€ ์•Š์Œ.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Failed to execute SQL script statement #2 of class path resource [schedule.sql]: CREATE TABLE event ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '๊ณ ์œ  ์‹๋ณ„์ž', task VARCHAR(50), created_time TIMESTAMP NOT NULL COMMENT '์ƒ์„ฑ ๋‚ ์งœ', edited_time TIMESTAMP NOT NULL COMMENT '์ˆ˜์ •๋œ ๋‚ ์งœ', owner VARCHAR(25) NOT NULL COMMENT '์ž‘์„ฑ์ž๋ช…', password VARCHAR(25) NOT NULL COMMENT '๋น„๋ฐ€๋ฒˆํ˜ธ' )
...
Caused by: java.sql.SQLSyntaxErrorException: Table 'event' already exists

โ“ ์›์ธ

๊ธฐ์กด SQL ๋ฌธ

USE schedule;
CREATE TABLE event
(
    id           BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '๊ณ ์œ  ์‹๋ณ„์ž',
    task         VARCHAR(50),
    created_time TIMESTAMP   NOT NULL COMMENT '์ƒ์„ฑ ๋‚ ์งœ',
    edited_time  TIMESTAMP   NOT NULL COMMENT '์ˆ˜์ •๋œ ๋‚ ์งœ',
    owner        VARCHAR(25) NOT NULL COMMENT '์ž‘์„ฑ์ž๋ช…',
    password     VARCHAR(25) NOT NULL COMMENT '๋น„๋ฐ€๋ฒˆํ˜ธ'
);
Caused by: java.sql.SQLSyntaxErrorException: Table 'event' already exists

์—๋Ÿฌ ๋ฉ”์„ธ์ง€ ๋ถ„์„ ๊ฒฐ๊ณผ, ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค๋ ค๊ณ  ํ•ด์„œ ๋ฌธ์ œ ๋ฐœ์ƒ

  • ๊ธฐ์กด์—๋Š” main/resource ์•„๋ž˜์— ์Šคํ‚ค๋งˆ ํŒŒ์ผ์„ ์œ„์น˜ํ•˜๋„๋ก ํ–ˆ์Œ.

    • ์ง€์‹œ ์‚ฌํ•ญ๋Œ€๋กœ ์Šคํ‚ค๋งˆ sql ํŒŒ์ผ์„ ์ตœ์ƒ์œ„ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๊ฒฝ๋กœ ์˜ฎ๊ฒจ๋„ ๋™์ผ
    • ์—๋Ÿฌ ๋ฉ”์„ธ์ง€ ์‚ดํŽด๋ณด๋‹ˆ ๊ฒฝ๋กœ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ์—ˆ์Œ์„ ํŒŒ์•…
  • ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํ…Œ์ด๋ธ”์„ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๋ ค๊ณ  ํ•ด์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•จ.

  • App ์‹คํ–‰ ์ด์ „์— DB ์—ฐ๊ฒฐ ์„ค์ •ํ•˜๋ฉด์„œ ํ…Œ์ด๋ธ”์ด ์ƒ์„ฑ๋œ ๊ฒƒ์ด ์›์ธ์œผ๋กœ ํŒŒ์•…


โ— ํ•ด๊ฒฐ

  • CREATE TABLE๊ณผ CREATE DATABASE ์•ž์— IF NOT EXISTS ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ํ•ด๊ฒฐ


ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰

๐Ÿ“Œ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’ ์ „๋‹ฌ

โ›” ๋ฌธ์ œ
API ์š”์ฒญ ํ…Œ์ŠคํŠธ ์ค‘ ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€์™€ ํ•จ๊ป˜ 400 BAD REQUEST ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ ๋ฐ›์Œ.

2025-03-25T15:25:17.962+09:00  WARN 17340 --- [Schedule] [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation]

โ“ ์›์ธ

  • ์š”์ฒญ ์ฒ˜๋ฆฌ ํ›„ ์‘๋‹ต ์‹œ, ResponseDTOโžก๏ธjson ๋ณ€ํ™˜ ๊ณผ์ •์—์„œ(json ํŒŒ์‹ฑ) ๊ฐ’ ์„ธํŒ…์ด ๋˜์ง€ ์•Š์Œ.
  • ResponseDTO์— @Getter ์–ด๋…ธํ…Œ์ด์…˜์ด ์—†์–ด ๊ฐ’์„ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†์—ˆ์Œ.

โ— ํ•ด๊ฒฐ

  • @Getter ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ ํ•ด๊ฒฐ

๐Ÿ’ญ ๊ทธ ์™ธ

  • Postman์œผ๋กœ API ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜์˜€์œผ๋‚˜ ๋ฌธ์ œ ๋ฐœ์ƒ ์ง€์ ์„ ์ •ํ™•ํ•˜๊ฒŒ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€์ ์ธ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋‚˜ ์—๋Ÿฌ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  ๋А๋‚Œ.
  • ๊ทธ๋Ÿฌ๋‚˜ ์‹œ๊ฐ„์ด ์—†์–ด System.out.println์œผ๋กœ ์ˆ˜๋™ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰, ๋น„ํšจ์œจ์ ์ธ ํ…Œ์ŠคํŠธ ๋ฐฉ์‹์ด๋ผ๊ณ  ํŒ๋‹จ.

  • JUnit์€ HTTP ์š”์ฒญ์ด ์•„๋‹Œ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ๋กœ ํ…Œ์ŠคํŒ…์ด ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— API ํ…Œ์ŠคํŠธ์—๋Š” ์ ์ ˆํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ.
  • MockMvc๋ฅผ ํ™œ์šฉํ•˜๋ฉด Postman์ฒ˜๋Ÿผ ์ปจํŠธ๋กค๋Ÿฌ ๋‹จ๋ถ€ํ„ฐ ์‹ค์ œ HTTP ์š”์ฒญ์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜์—ฌ ํ…Œ์ŠคํŒ…์ด ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ํ•จ. ์ด์— ๋Œ€ํ•ด ์ถ”๊ฐ€ ํ•™์Šตํ•  ๊ณ„ํš.



๐Ÿ“Œ ๋™์ผ HTTP ๋ฉ”์†Œ๋“œ/์—”๋“œํฌ์ธํŠธ API ์ถฉ๋Œ

โ›” ๋ฌธ์ œ
API ์š”์ฒญ ํ…Œ์ŠคํŠธ ์ค‘ ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€์™€ ํ•จ๊ป˜ ์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœ์— ์‹คํŒจ.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Ambiguous mapping. Cannot map 'eventController' method 
org.example.schedule.controller.EventController#findAllEvents()
to {GET [/events]}: There is already 'eventController' bean method
org.example.schedule.controller.EventController#findAllEventsByOwnerOrEditedTime(String, Timestamp, Timestamp) mapped.
...
Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'eventController' method 
org.example.schedule.controller.EventController#findAllEvents()
to {GET [/events]}: There is already 'eventController' bean method
org.example.schedule.controller.EventController#findAllEventsByOwnerOrEditedTime(String, Timestamp, Timestamp) mapped.

โ“ ์›์ธ

Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'eventController' method 
  • ์ค‘๋ณต๋œ ๋งตํ•‘(Ambiguous mapping)์œผ๋กœ ์ธํ•ด ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์–ด๋–ค ๋ฉ”์†Œ๋“œ๋ฅผ ๋งตํ•‘ํ•  ์ง€ ๊ฒฐ์ •ํ•  ์ˆ˜ ์—†์Œ.

  // ์ „์ฒด ์กฐํšŒ
  @GetMapping
  List<EventResponseDTO> findAllEvents() {
    return eventService.findAllEvents();
  }

  // ์กฐ๊ฑด ์ผ์น˜ ์ผ์ •๋“ค ์กฐํšŒ (์ˆ˜์ • ๋‚ ์งœ, ์ž‘์„ฑ์ž๋ช…)
  @GetMapping
  List<EventResponseDTO> findAllEventsByOwnerOrEditedTime(
      @RequestParam String owner,
      @RequestParam Timestamp startDate,
      @RequestParam Timestamp endDate) {
    return eventService.findAllEventsByOwnerOrEditedTime(owner, startDate, endDate);
  }
  • ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ๋ถ€๋ถ„์˜ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด ๋™์ผ ๊ฒฝ๋กœ, ๋™์ผ HTTP ๋ฉ”์†Œ๋“œ(GET ์š”์ฒญ)์ด์ง€๋งŒ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๋‹ค๋ฆ„.
  • ๊ทธ๋Ÿฌ๋‚˜ Spring MVC๋Š” HTTP ์š”์ฒญ ๋งคํ•‘ ์‹œ ๊ฒฝ๋กœ์™€ HTTP ๋ฉ”์†Œ๋“œ(GET, POST etc.)์œผ๋กœ ๋ฉ”์†Œ๋“œ ๋งตํ•‘์„ ๊ตฌ๋ถ„ํ•œ๋‹ค.
  • ์ฆ‰, ํŒŒ๋ผ๋ฏธํ„ฐ ์œ ๋ฌด๋Š” ๋ฉ”์†Œ๋“œ ๋งตํ•‘์˜ ๊ธฐ์ค€์ด ๋˜์ง€ ์•Š๋Š”๋‹ค.

โ— ํ•ด๊ฒฐ

  • ์—”๋“œํฌ์ธํŠธ(๊ฒฝ๋กœ)๋ฅผ ๋‹ค๋ฅด๊ฒŒ ํ•˜์—ฌ ๋ฉ”์†Œ๋“œ ๋งตํ•‘์ด ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋„๋ก ํ•จ.


๐Ÿ“Œ API - ๋‚ ์งœ ํŒŒ๋ผ๋ฏธํ„ฐ ์ฒ˜๋ฆฌ

โ›” ๋ฌธ์ œ

  • API ์š”์ฒญ ํ…Œ์ŠคํŠธ ์ค‘ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฉ”์„ธ์ง€์™€ ํ•จ๊ป˜ Timestamp startDate ํŒŒ๋ผ๋ฏธํ„ฐ ์ฒ˜๋ฆฌ์— ์‹คํŒจํ•จ.
.MethodArgumentTypeMismatchException: Method parameter 'startDate': Failed to convert value of type 'java.lang.String' to required type 'java.sql.Timestamp'; Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam java.sql.Timestamp] for value [2025-03-21T00:00:00]]

โ“ ์›์ธ

Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam java.sql.Timestamp]
  • String ์—์„œ Timestamp ํƒ€์ž… ๋ณ€ํ™˜์— ์‹คํŒจํ–ˆ์Œ.
  • 2025-03-03 ๊ณผ ๊ฐ™์ด ๋‚ ์งœ ํฌ๋งท์— ๋งž์ถฐ์„œ ์š”์ฒญ์„ ๋ณด๋ƒˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋ณ€ํ™˜์ด ์ด๋ฃจ์–ด์ง€์ง€ ์•Š์Œ.

โ— ํ•ด๊ฒฐ

1์ฐจ ์‹œ๋„

  • ๋‚ ์งœ ํŒŒ๋ผ๋ฏธํ„ฐ์— @DateTimeFormat ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ ๋‚ ์งœ ํฌ๋งท์œผ๋กœ ์ธ์‹๋˜๋„๋ก ํ•จ.
  • ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ์ „ํžˆ ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ String์œผ๋กœ ์ธ์‹ ๋จ.

2์ฐจ

  • Timestamp ํƒ€์ž…์€ @DateTimeFormat ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด๋„ ์ธ์‹์ด ์•ˆ๋œ๋‹ค.
  • ๋”ฐ๋ผ์„œ @DateTimeFormat ์–ด๋…ธํ…Œ์ด์…˜์ด ์ง€์›ํ•˜๋Š” ํƒ€์ž…๋“ค (Date, LocalTime, LocalDateTime) ์ค‘์—์„œLocalDateTime์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์—ฌ ๋ฌธ์ œ ํ•ด๊ฒฐ.


DTO-Entity ๋ณ€ํ™˜ ๋‹ด๋‹น ๋ ˆ์ด์–ด

๐Ÿ“Œ ๋ฌธ์ œ

โ›” ๋ฌธ์ œ


โ“ ์›์ธ


โ— ํ•ด๊ฒฐ

โœ…๋ฐฉ๋ฒ• 1) sc.nextLine() ์œผ๋กœ ๊ฐœํ–‰๋ฌธ์ž ์ œ๊ฑฐ

๐Ÿ” ๊ธฐ์กด์˜ ์ฝ”๋“œ๋ฅผ ๋ฉ”์†Œ๋“œ๋กœ ๋ถ„๋ฆฌ

โœ… ๋”ฐ๋ผ์„œ ์ผ๋ถ€ ๋กœ์ง์„ ๋ฉ”์†Œ๋“œ๋กœ ๋ถ„๋ฆฌ

โœ”๏ธ ์ฝ”๋“œ๊ฐ€ ๊ตฌ์กฐ์ ์œผ๋กœ ๋” ๊น”๋”ํ•ด์ง€๋ฉฐ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์šฉ์ด
โŒ ๋ฉ”์†Œ๋“œ ๋ถ„๋ฆฌํ–ˆ์Œ์—๋„ ์˜คํžˆ๋ ค ์ฝ”๋“œ๊ฐ€ ๋” ๋ณต์žกํ•ด ๋ณด์ด๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Œ

๐Ÿ’ญ ๋ฉ”์†Œ๋“œ ์—ญํ• ์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์ด ์ง๊ด€์ ์ด์ง€ ์•Š์„ ๊ฐ€๋Šฅ์„ฑ

์–ด๋ ค์šด์ ?

์ผ์ • ์—…๋ฐ์ดํŠธ ํ• ๋•Œ ์—…๋ฐ์ดํŠธ ์‹œ์ ์„ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์—์„œ ์ฒ˜๋ฆฌํ•  ๋•Œ now()๋กœ ์ฐ์–ด์„œ ์—…๋ฐ์ดํŠธํ•˜๊ฒŒ ํ–ˆ๋Š”๋ฐ.. ์ด๋ ‡๊ฒŒ ํ•ด๋„ ๋˜๋Š”์ง€? ์ด๊ฒƒ๋„ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด๋‹ˆ๊นŒ ์„œ๋น„์Šค ๋ ˆ์ด์–ด์—์„œ ๊ฐ’์„ ๋ฏธ๋ฆฌ ๋„˜๊ฒจ์ฃผ์–ด์•ผํ•˜๋Š”์ง€ ์•„๋‹ˆ๋ฉด ๋‚˜์ค‘์— JPA๋ฅผ ์“ฐ๊ฒŒ ๋œ๋‹ค๋ฉด @LastModifiedDate < ๊ฐ™์€ ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒŒ ์ข‹์€์ง€

์ฐธ๊ณ 

https://browndwarf.tistory.com/48

profile
๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ๋„ ๋ฝ์ด๋‹ค

0๊ฐœ์˜ ๋Œ“๊ธ€