[๐Ÿฆ] Spring MVC ๋ฏธ์…˜

day024ยท2024๋…„ 5์›” 21์ผ
post-thumbnail

4์ฃผ์ฐจ Spring MVC ๋ฏธ์…˜

์ดˆ๋ก์Šคํ„ฐ๋””๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ Spring MVC์— ๋Œ€ํ•ด์„œ ํ•™์Šตํ•ด๋ณด์•˜๋‹ค.
Spring์„ ์ฒ˜์Œ ์‚ฌ์šฉํ•˜๋‹ค๋ณด๋‹ˆ ์—ฌ๋Ÿฌ ๋ฌธ์ œ๋ฅผ ๊ฒช์—ˆ๋‹ค.
ํ•™์Šต ํ…Œ์ŠคํŠธ๋ฅผ ๋ณด๊ณ  ์™œ ๊ทธ๋Ÿฐ์ง€ ์ดํ•ด๋ชปํ•˜๊ณ  ๋„˜์–ด๊ฐ„ ๋ถ€๋ถ„์ด ๋” ๋งŽ์€ ๊ฒƒ ๊ฐ™๋‹ค. (์ง€๊ธˆ๋„...)
๋ฏธ์…˜์„ ์ง„ํ–‰ํ•˜๋ฉด์„œ ์˜๋ฌธ์„ ๊ฐ€์กŒ๋˜ ๋ถ€๋ถ„๊ณผ ๋ฐฐ์šด ๋ถ€๋ถ„์œ„์ฃผ๋กœ ์ •๋ฆฌ ํ–ˆ๋‹ค.

https://github.com/day024/spring-roomescape-playground/tree/day024

๐Ÿš€ Gradle์„ ์ด์šฉํ•˜์—ฌ ํ”„๋กœ์ ํŠธ๋ฅผ ๋นŒ๋“œํ•˜๊ณ  ์‹คํ–‰ํ•˜๊ธฐ

๋ฏธ์…˜์— ๋“ค์–ด๊ฐ€๊ธฐ ์•ž์„œ ์Šคํ”„๋ง์„ ์ฒ˜์Œ ์จ๋ณด๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ ์„ธํŒ…๋ถ€ํ„ฐ ์ง„ํ–‰ ํ•ด๋ณด์•˜๋‹ค.
์–ด๋–ค ๋ฌธ์ œ์ธ์ง€ ์Šคํ”„๋ง์ด ์ธ์‹์ด ์•ˆ๋˜๋Š” ์˜ค๋ฅ˜๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ•˜์˜€๋‹ค.

https://velog.io/@coastby/Spring ์ด๊ธ€์„ ํ†ตํ•ด์„œ ๊ฒจ์šฐ ํ•ด๊ฒฐํ•˜์˜€๋‹ค.
์ฒ˜์Œ์—๋Š” Gradle๋ฒ„์ „์ด ์•ˆ๋งž๋Š”๋‹ค๋Š” ์˜ค๋ฅ˜๊ฐ€ ๊ณ„์†๋ฐœ์ƒํ•ด์„œ Build,Execution,Deployment>gradle JVM ์„ค์ •์„ ๊ณ„์† ๋ณ€๊ฒฝํ•˜๋ฉด์„œ ๋ฒ„์ „์„ ๋ฐ”๊ฟ”๋ณด์•˜๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ด์   Cannot resolve symbol 'springframework ๋ผ๋Š” ๋ฌธ๊ตฌ๊ฐ€ ๊ณ„์† ๋–ด๊ณ  ๋ธ”๋กœ๊ทธ๋ฅผ ํ†ตํ•ด์„œ ํ•ด๊ฒฐํ–ˆ๋‹ค.
์–ด์งธ์„œ์ธ์ง€ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ์—ฌ์ „ํžˆ ๋˜‘๊ฐ™์€ ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜๋ณตํ–ˆ๋‹ค. ๋™์ผํ•˜๊ฒŒ Gradle์„ refresh ํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์ด ์„ฑ๊ณตํ–ˆ๋‹ค.

๐Ÿš€ 1๋‹จ๊ณ„ - ํ™ˆ ํ™”๋ฉด

์š”๊ตฌ์‚ฌํ•ญ:
ํ™ˆ ํ™”๋ฉด์กฐํšŒ / ์˜์กด์„ฑ ์ถ”๊ฐ€

์›น๊ด€๋ จ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

    implementation 'org.springframework.boot:spring-boot-starter-web'
  • Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์›น ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•œ ์˜์กด์„ฑ
  • Spring MVC๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
  • Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— Thymeleaf ํ…œํ”Œ๋ฆฟ ์—”์ง„์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•œ ์˜์กด์„ฑ
  • Thymeleaf๋Š” HTML ๊ธฐ๋ฐ˜์˜ ํ…œํ”Œ๋ฆฟ ์—”์ง„์œผ๋กœ, ์„œ๋ฒ„ ์‚ฌ์ด๋“œ์—์„œ HTML์„ ์ƒ์„ฑํ•˜๊ณ  ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•œ๋‹ค.

@Controller์™€ @GetMapping์„ ํ†ตํ•ด์„œ ์ง„ํ–‰ํ–ˆ๋‹ค.

package roomescape.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

    @GetMapping("/")
    public String home() {
        return "home";
    }
}

Annotation

์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด์„œ ์Šคํ”„๋ง์—์„œ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

1. @Controller

  • ํ•ด๋‹น ํด๋ ˆ์Šค๊ฐ€ "Controller"์ž„์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.
  • @Controller ์–ด๋…ธํ…Œ์ด์…˜์ด ์ง€์ •๋œ ํด๋ž˜์Šค๋ฅผ bean์œผ๋กœ ๋“ฑ๋ก๋œ๋‹ค. ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ Controller๋กœ ์‚ฌ์šฉ๋จ์„ Spring Framework์— ์•Œ๋ฆฐ๋‹ค.

2. @RequestMapping

  • ํŠน์ • url๋ถ€ํ„ฐ ๋“ค์–ด์˜จ ์š”์ฒญ์„ ์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์„œ๋“œ์— ๋งคํ•‘ ํ•œ๋‹ค.
  • @GetMapping, @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping

3. @GetMapping

  • HTTP Request ๋ฉ”์†Œ๋“œ ๊ฐ’์„ ๋งคํ•‘ํ•˜๊ธฐ ์œ„ํ•œ Annotation
  • @PathVariable ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด์„œ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•˜๊ธฐ๋„ ํ•œ๋‹ค. , @PathVariable ๋ฅผ ๋‹ค์ค‘์‚ฌ์šฉ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

๐Ÿš€ 2๋‹จ๊ณ„ - ์˜ˆ์•ฝ ์กฐํšŒ

์š”๊ตฌ์‚ฌํ•ญ:
์˜ˆ์•ฝ ์กฐํšŒ API๊ตฌํ˜„
์˜ˆ์•ฝ ํŽ˜์ด์ง€ ์š”์ฒญ๊ณผ ์˜ˆ์•ฝ ๋ชฉ๋ก ์กฐํšŒ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜์„ธ์š”.

  • reservation๋ฅผ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์€ 1๋‹จ๊ณ„ homeController์™€ ๊ฐ™๊ฒŒ ์ง„ํ–‰ํ•˜์˜€๋‹ค.
  • ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค๊ฐ€ ์—†์–ด ๋ฆฌ์ŠคํŠธ๋กœ ์ง„ํ–‰ํ•˜์˜€๋‹ค. ๋˜ํ•œ ์•„์ง ์ž…๋ ฅ์ด ๊ตฌํ˜„๋˜์ง€ ์•Š์•„ ํ…Œ์ŠคํŠธ ํ†ต๊ณผ๋ฅผ ์œ„ํ•œ ์ž„์˜ ์˜ˆ์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.
ResponseEntity.status(HttpStatus.OK).body(reservationList);
  • ResponseEntity๋ฅผ ์ƒ์„ฑ ํ•˜๊ณ  ์‘๋‹ต์˜ ์ƒํƒœ๋ฅผ HttpStatus.OK, ์ƒํƒœ์ฝ”๋“œ 200์œผ๋กœ ์„ค์ •ํ•œ๋‹ค. ์š”์ฒญ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์‹คํ–‰ ๋˜์—ˆ๋‹ค๋Š” ์˜๋ฏธ.
  • body(reservationList) ์˜ˆ์•ฝ ๋‚ด์šฉ์ด ๋‹ด๊ธด ๋ฆฌ์ŠคํŠธ๋ฅผ ์‘๋‹ต ๋ณธ๋ฌธ์œผ๋กœ ์ „๋‹ฌ
@Controller
public class ReservationController {
    private List<Reservation> reservations = new ArrayList<>();
	//์˜ˆ์•ฝ ๋ทฐ ๋ Œ๋”๋ง 
    @GetMapping("/reservation")
    public String reservation() {
        return "reservation";
    }
	//์˜ˆ์•ฝ ์ •๋ณด๋ฅผ ์กฐํšŒ
    @GetMapping("/reservations")
    public ResponseEntity<List<Reservation>> getReservations() {

        List<Reservation> reservationList = new ArrayList<>();
        reservationList.add(new Reservation(1, "๋ธŒ๋ผ์šด", "2023-01-01", "10:00"));
        reservationList.add(new Reservation(2, "๋ธŒ๋ผ์šด", "2023-01-02", "11:00"));

        return ResponseEntity.status(HttpStatus.OK).body(reservationList);
    }

Reservation class๋ฅผ ์ƒ์„ฑํ–ˆ๋‹ค. ์˜ˆ์•ฝ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ id, name, date, time์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” class์ด๋‹ค.

package roomescape.domain;

import java.time.LocalDateTime;

public class Reservation {
    private int id;
    private String name;
    private String date;
    private String time;

    public Reservation(int id, String name, String date, String time) {
        this.id = id;
        this.name = name;
        this.date = date;
        this.time = time;
    }

    public int getId() {
        return id;
    }

    public String getDate() {
        return date;
    }

    public String getName() {
        return name;
    }

    public String getTime() {
        return time;
    }
}

๐Ÿš€ 3๋‹จ๊ณ„ - ์˜ˆ์•ฝ ์ถ”๊ฐ€ / ์ทจ์†Œ

์š”๊ตฌ์‚ฌํ•ญ :
API ๋ช…์„ธ๋ฅผ ๋”ฐ๋ผ ์˜ˆ์•ฝ ์ถ”๊ฐ€ API ์™€ ์‚ญ์ œ API๋ฅผ ๊ตฌํ˜„

์˜ˆ์•ฝ ์ถ”๊ฐ€ API

id๋ฅผ ๋งŒ๋“ค๊ณ , ์ƒˆ ์˜ˆ์•ฝ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
์˜ˆ์•ฝ์„ ์ €์žฅํ•˜๊ณ  ResponseEntity๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

private final AtomicLong index = new AtomicLong(0); //์˜ˆ์•ฝ์„ ์œ„ํ•œ ID

@PostMapping("/reservations")
    public ResponseEntity<Reservation> addReservation(@RequestBody Reservation request) {
        long id = index.incrementAndGet();
        Reservation reservation = new Reservation(id, request.getName(), request.getDate(), request.getTime());
        reservations.add(reservation);

        URI location = URI.create("/reservations/" + id);

        return ResponseEntity.created(location).body(reservation);
    }

ํžŒํŠธ

...
public class ReservationController {

    private AtomicLong index = new AtomicLong(1);
    ...
    
    // AtomicLong ํ™œ์šฉ ์˜ˆ์‹œ
    reservations.add(new Reservation(index.incrementAndGet(), "๋ธŒ๋ผ์šด", "2023-01-01", "10:00"));
    
   ...

์˜ˆ์•ฝ ์ •๋ณด์˜ ์‹๋ณ„์ž๋ฅผ ์ƒ์„ฑํ•  ๋•Œ AtomicLong๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ํžŒํŠธ๋ฅผ ๋ฐ›์•˜๋‹ค.

AtomicLong

  • ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ long ๋ณ€์ˆ˜๋ฅผ ์ฆ๊ฐ€, ๊ฐ์†Œ ์‹œํ‚ด
  • ๋™์‹œ์„ฑ์„ ๋ณด์žฅํ•ด์ค€๋‹ค.
  • ์ฃผ์š” ๋ฉ”์„œ๋“œ : incrementAndGet(), decrementAndGet(), getAndIncrement(), getAndDecrement()
long id = index.incrementAndGet();

id ์ฆ๊ฐ์„ ์œ„ํ•ด์„œ incrementAndGet๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. ๋ฉ”์„œ๋“œ๋Š” AtomicLong์˜ ๊ฐ’์„ 1 ์ฆ๊ฐ€์‹œํ‚ค๊ณ , ์ฆ๊ฐ€๋œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ index ๋ณ€์ˆ˜์˜ ๊ฐ’์„ 1์”ฉ ์ฆ๊ฐ€์‹œํ‚ค๋ฉด์„œ ๊ทธ ๊ฐ’์„ id ๋ณ€์ˆ˜์— ํ• ๋‹นํ•œ๋‹ค.

์ฒ˜์Œ์—” id๋ฅผ ๊ทธ๋ƒฅ int๋กœ ์„ ์–ธํ•˜์˜€๋Š”๋ฐ AtomicLong์— ๋Œ€ํ•ด์„œ ํ•™์Šต์„ ํ•˜๋‹ˆ long์œผ๋กœ ์„ ์–ธํ•ด์•ผํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•„ ํ›„์— ์ˆ˜์ •ํ–ˆ๋‹ค.

reservations.add(reservation);

jvaa Collection์—์„œ ๋ฆฌ์ŠคํŠธ์— ์ •๋ณด์ถ”๊ฐ€๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.
ArrayList์˜ add()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. ์‚ญ์ œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค.

์˜ˆ์•ฝ ์‚ญ์ œ API

@DeleteMapping("/reservations/{id}")
    public ResponseEntity<Void> cancelReservation(@PathVariable long id) {
        Reservation reservation = reservations.stream()
                .filter(it -> Objects.equals(it.getId(), id))
                .findFirst()
                .orElseThrow(IllegalArgumentException::new);

        reservations.remove(reservation);

        return ResponseEntity.noContent().build(); // ์„ฑ๊ณต(204) ์ƒํƒœ ์ฝ”๋“œ ๋ฐ˜ํ™˜
    }
 reservations.remove(reservation);

ArrayList์˜ remove()๋ฅผ ํ†ตํ•ด์„œ ๋ฐ”๋กœ ์‚ญ์ œ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

ResponseEntity.noContent().build(); 

์„ฑ๊ณต์ ์œผ๋กœ ์˜ˆ์•ฝ์ด ์‚ญ์ œ ๋˜๋ฉด 204 ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์‚ญ์ œ ์ฒ˜๋ฆฌ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋˜์—ˆ์œผ๋‹ˆ ์‘๋‹ตํ•˜๋Š” ๋ณธ๋ฌธ์€ ์—†๋‹ค.


๐Ÿš€ 4๋‹จ๊ณ„ - ์˜ˆ์™ธ ์ฒ˜๋ฆฌ

์š”๊ตฌ ์‚ฌํ•ญ

  • ์˜ˆ์•ฝ ๊ด€๋ จ API ํ˜ธ์ถœ ์‹œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ ์ค‘ ์š”์ฒญ์˜ ๋ฌธ์ œ์ธ ๊ฒฝ์šฐ Status Code๋ฅผ 400์œผ๋กœ ์‘๋‹ต
    • ์˜ˆ์•ฝ ์ถ”๊ฐ€ ์‹œ ํ•„์š”ํ•œ ์ธ์ž๊ฐ’์ด ๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐInvalidRequest
    • ์‚ญ์ œ ํ•  ์˜ˆ์•ฝ์˜ ์‹๋ณ„์ž๋กœ ์ €์žฅ๋œ ์˜ˆ์•ฝ์„ ์ฐพ์„ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐnotfound

ํžŒํŠธ

@ExceptionHandler(NotFoundReservationException.class)
public ResponseEntity handleException(NotFoundReservationException e) {
    return ResponseEntity.badRequest().build();
}

ํžŒํŠธ๋กœ ์ฃผ์–ด์ง„ @ExceptionHandler๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋ฅผ ์ง„ํ–‰ํ•˜์˜€๋‹ค.

package roomescape;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import roomescape.exception.InvalidRequestException;

@ControllerAdvice
public class ReservationExceptionHandler {
    @ExceptionHandler(InvalidRequestException.class)
    public ResponseEntity handleInvalidRequestException(InvalidRequestException e) {
        return ResponseEntity.badRequest().build();
    }

}
package roomescape.exception;

public class InvalidRequestException extends RuntimeException {
    public InvalidRequestException(String message) {
        super(message);
    }
}
package roomescape.exception;

public class NotFoundReservationException extends ReservationException {
    public NotFoundReservationException(String message) {
        super(message);
    }
}

@ExceptionHandler , @ControllerAdvice

  1. @ExceptionHandler
  • @ExceptionHandler๋Š” ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.
  • @ControllerAdvice์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ชจ๋“  ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋ฅผ ์ „์—ญ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  1. @ControllerAdvice
    -๊ฐ ์ปจํŠธ๋กค๋Ÿฌ์— ๊ฐœ๋ณ„์ ์œผ๋กœ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•  ํ•„์š” ์—†์ด ์ค‘์•™์—์„œ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
    private final String INVALID_NAME_REQUEST_MESSAGE = "์ด๋ฆ„ ์ •๋ณด๊ฐ€ ๊ณต๋ฐฑ์ž…๋‹ˆ๋‹ค.";
    private final String INVALID_DATE_REQUEST_MESSAGE = "๋‚ ์งœ ์ •๋ณด๊ฐ€ ๊ณต๋ฐฑ์ž…๋‹ˆ๋‹ค.";
    private final String INVALID_TIME_REQUEST_MESSAGE = "์‹œ๊ฐ„ ์ •๋ณด๊ฐ€ ๊ณต๋ฐฑ์ž…๋‹ˆ๋‹ค.";

๋ฆฌ๋ทฐ๋ฅผ ๋ฐ›์€ ์ดํ›„ ๊ฐ ์˜ˆ์™ธ ๋ฌธ๊ตฌ๋“ค์€ ์ƒ์ˆ˜์ฒ˜๋ฆฌ๋ฅผ ์ง„ํ–‰ํ•ด์ฃผ์—ˆ๋‹ค.
๋ณ„๋„๋กœ class๋ฅผ ์ƒ์„ฑํ•œ ํ›„ ์‚ฌ์šฉํ•ด๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.
๋ฌธ๊ตฌ๋“ค์„ ์ƒ์ˆ˜์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ฉด ์ฝ”๋“œ ์ค‘๋ณต์ด ์ค„์–ด๋“ค๊ณ , ์ผ๊ด€์„ฑ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.


roomescape
ใ„ดcontroller
  ใ„ด homeController
  ใ„ด reservationController
ใ„ดdomain 
  ใ„ด Reservation
ใ„ดexception
  ใ„ดInvalidRequestException
  ใ„ดNotFoundReservationException
  ใ„ดReservationException
  ใ„ดReservationExceptionHandler

์šฐ์„  ๊ธฐ๋Šฅ๋งŒ์œผ๋กœ๋„ ๋‚ฏ์„ค์–ด ๊ตฌ์กฐ์— ๋Œ€ํ•œ ํฐ ๊ณ ๋ฏผ์—†์ด ์œ„์™€ ๊ฐ™์ด ์ง„ํ–‰ํ•˜์˜€๋‹ค. DTO ๊ตฌ์กฐ๋ฅผ ๋‹ค๋“ค ํ™œ์šฉํ•˜๊ธธ๋ž˜ ์ฐพ์•„๋ณด๊ฒŒ ๋˜์—ˆ๋‹ค.
Repository, Controller, Service, DTO์— ๋Œ€ํ•ด์„œ ์ƒ๊ฐํ•ด๋ณด๊ณ ๋Š” ์žˆ์ง€๋งŒ ์•„์ง ์ดํ•ด ํ•˜์ง€ ๋ชปํ–ˆ๋‹ค...
๊ทธ๋ž˜์„œ Spring ๊ตฌ์กฐ์— ๋Œ€ํ•ด์„œ ์ข€ ๋” ๊ณ ๋ฏผํ•ด๋ณด๊ณ  service์™€ Repository๋ฅผ ํ™œ์šฉํ•ด์„œ ๋‹ค์Œ ๋ฏธ์…˜์— ์ ์šฉํ•ด๋ณด๊ณ ์‹ถ๋‹ค.

+) ๋ฏธ์…˜์„ ์ง„ํ–‰ํ•˜๋ฉด์„œ pr์„ ๋ณด๋ƒˆ๋”๋‹ˆ xํ‘œ์‹œ๊ฐ€ ๋– ์„œ ์šฐ์„ ์€ ๋†”๋‘์—ˆ์—ˆ๋‹ค.
์•Œ๊ณ ๋ณด๋‹ˆ ์•„์ฃผ ๊ธฐ๋ณธ์ ์ธ ๊ฑธ ์žŠ๊ณ ์žˆ์—ˆ๋‹ค.

pr๋ณด๋‚ด๋Š” branch๋ฅผ base:main์œผ๋กœ ์„ค์ •ํ•ด๋‘์—ˆ๊ธฐ ๋•Œ๋ฌธ์— mergeํ•  ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ์˜€๋‹ค. base:day024๋กœ ๋ณ€๊ฒฝํ–ˆ๋‹ค.

์ด์ œ ์ถฉ๋Œ์ด ์—†๋Š” ์ƒํƒœ๋กœ ๋ฐ”๋€Œ์—ˆ๋‹ค!


๋ฏธ์…˜์— ์ฐธ๊ณ ํ•œ ์ž๋ฃŒ๋“ค

[Spring] Cannot resolve symbol'springframework'

Long ๊ณผ AtomicLong์€ ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ์„๊นŒ?
[JAVA] Atomic ๋ณ€์ˆ˜์™€ ๋™์‹œ์„ฑ ์ œ์–ด (AtomicInteger, AtomicLong, AtomicBoolean, AtomicReference)
[Spring] ์š”์ฒญ ๋ฐฉ์‹(@RequestMapping, @GetMapping, @PostMapping)
Spring Controller ์–ด๋…ธํ…Œ์ด์…˜๊ณผ ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…
[์Šคํ”„๋ง๋ถ€ํŠธ] @ExceptionHandler๋ฅผ ํ†ตํ•œ ์˜ˆ์™ธ์ฒ˜๋ฆฌ

[Spring] DTO๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ด์œ 
[Spring] ์Šคํ”„๋ง ํŒจํ‚ค์ง€ ๊ตฌ์กฐ, DAO, DTO, Entity, Repository ์— ๋Œ€ํ•˜์—ฌ, DTO๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 
[SpringMVC] SpringMVC ๊ตฌ์กฐ

profile
๊ฐœ๋ฐœํ•˜๋Š” ๊ฐ์ž

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