TIL 31 [ Spring 일정관리 앱 Lv0 ~ 1, + 미니세션 ( 예외처리 ) ]

2025. 4. 2. 19:59·[내일배움캠프-Sparta]/Spring 6기
반응형

16:00 ~ 17:00 미니세션 ( 예외처리, 박성원 튜터님 )

📣 Spring 일정 관리앱 (JPA)

✅ Lv 0

API, ERD는 개발 과정에서도 계속 바뀔 수 있기 때문에 포스팅일 기준으로 나타내고 있습니다.

SQL문은 JPA가 작성해주기 때문에 따로 작성하지는 않았다.

 

일정 관리 API 명세서(v2)(일정)
일정 관리 API 명세서(v2)(유저)

ERD 다이어그램

✅ Lv 1 ( 일정 CRUD )

※ Entity와 Dto는 있다고 가정하고 작성하겠습니다.

프로젝트 Application에 @EnableJpaAuditing을 선언해주어야 한다.

@EnableJpaAuditing
@SpringBootApplication
public class SchedulerProjectV2Application {

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

}

Repository는 하나로 다룬다.

JpaRepository에 상속받으면서 관리되며, <"Entity", "식별자 타입"> 이 와야 한다.

default 메소드로 작성시 인터페이스 내 구현체를 작성할수 있으며, 처리를 통해 Optional로 예외처리를 하는경우를 생략하게 하여 코드량을 줄였다.

public interface ScheduleRepository extends JpaRepository<Schedule, Long> {

    // 실습 했던거 참고. (예외처리)
    default Schedule findByIdOrElseThrow(Long id) {
        return findById(id).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "존재하지 않는 id = " + id));
    }
}

⚡ 생성

Controller

@RestController
@RequestMapping("/api/schedules")
@RequiredArgsConstructor
public class ScheduleController {

    private final ScheduleService scheduleService;

    // 일정 생성
    @PostMapping
    public ResponseEntity<ScheduleResponseDto> addSchedule(@RequestBody CreateScheduleRequetsDto requetsDto) {

        ScheduleResponseDto responseDto = scheduleService.addSchedule(requetsDto.getTitle(), requetsDto.getUserName(), requetsDto.getContents());

        return new ResponseEntity<>(responseDto, HttpStatus.CREATED);
    }

Service ( Lv2 에 먼저 접근함.. )

// 일정 생성
@Override
public ScheduleResponseDto addSchedule(Long id, String title, String contents, String requetsDtoContents) {

    // 튜터님의 새로운 예외처리 방법 !! Optional 예외처리 하는법 대체
    Member member = memberRepository.findById(id).orElseThrow(
            () -> new RuntimeException("Not Found Member" + id)
    );

    Schedule schedule = new Schedule(title, contents, member);

    Schedule addSchdule = scheduleRepository.save(schedule);

    return new ScheduleResponseDto(addSchdule.getId(), addSchdule.getTitle(), addSchdule.getMember().getUserName() , addSchdule.getContents());
}

생성의 경우 id값이 없기때문에 데이터를 생성하겠다는 요청 값을 받아주며, 객체를 새로 생성하여 그 값을 저장하여 생성 할수 있다. 여기서 id값은 Member와 연관관계를 맺고 있기 때문에 Member의 id값을 불러오는 용도로 이해하면 된다.

⚡ 전체조회

Controller

// 일정 전체 조회
@GetMapping
public ResponseEntity<List<ScheduleResponseDto>> findAll() {

    List<ScheduleResponseDto> responseDtoList = scheduleService.findAll();

    return new ResponseEntity<>(responseDtoList,HttpStatus.OK);
}

Service

// 일정 전체 조회
@Override
public List<ScheduleResponseDto> findAll() {

    return scheduleRepository.findAll()
            .stream()
            .map(ScheduleResponseDto::toDto)
            .toList();
}

전체 조회 같은경우에는 보통 리스트 형태로 나타내는 것이 일반적이다. List<E> 를 활용하고, id값은 요청 받을 필요가 없다. 그래서 .findAll() 메소드를 활용해 모두다 부르며, stream() 형태로 만들고 .map(ScheduleResponse::toDto) 형태로 entity에 저장된 toDto 메소드를 불러와 그 결과값을 toList() 리스트 형태로 반환한다.

⚡ 단건조회

Controller

// 일정 단건 조회
@GetMapping("/{id}")
public ResponseEntity<ScheduleResponseDto> findAllById(@PathVariable Long id) {

    ScheduleResponseDto responseDto = scheduleService.findById(id);

    return new ResponseEntity<>(responseDto,HttpStatus.OK);
}

Service

// 일정 단건 조회
@Override
public ScheduleResponseDto findById(Long id) {

    Schedule findSchedule = scheduleRepository.findByIdOrElseThrow(id);

    return new ScheduleResponseDto(findSchedule.getId(), findSchedule.getTitle(), findSchedule.getMember().getUserName(), findSchedule.getContents());
}

단건 조회는 이미 저장되어 있는 데이터 id값을 조회해서 해당하는 id값을 변수로 저장하여 .get메소드를 이용해 하나의 필드를 다 불러 오는 씩으로 하였다.

⚡ 수정

Controller

// 일정 수정
@PutMapping("/{id}")
public ResponseEntity<String> update(
        @PathVariable Long id,
        @RequestBody UpdateRequestDto requestDto
) {
    String requestUpdate = scheduleService.update(id, requestDto.getTitle(), requestDto.getContents());

    return new ResponseEntity<>(requestUpdate,HttpStatus.OK);
}

Service

// 일정 수정
@Transactional // 도 가능함. ( 영속성 컨텍스트 ?? ) . . . 트랜잭션 단위를 잡는역할?
@Override
public String update(Long id, String title, String contents) {

    Schedule findSchedule = scheduleRepository.findByIdOrElseThrow(id);

    findSchedule.update(title,contents);

    //scheduleRepository.save(findSchedule);

    return "일정이 성공적으로 수정되었습니다.";
}

수정은 단건 조회와 마찬가지로 이미 저장되어있는  id값을 가져와서 변수로 저장한후 Schedule Entity의  update 메소드를 이용해서 변경하는 값을 만들어준다.  이때 2가지의 방법으로 나뉜다.

1.  @Transactional을 이용한 영속성 컨텍스트에서 변경감지라는 특성을 이용한 변경 방법

2. save 메소드를 이용해 직접 변경한값을 담아서 저장해준다.

⚡ 삭제

Controller

// 일정 삭제
@DeleteMapping("/{id}")
public ResponseEntity<String> delete(@PathVariable Long id) {

    String requestDelete = scheduleService.delete(id);

    return new ResponseEntity<>(requestDelete,HttpStatus.OK);
}

Service

// 일정 삭제
@Override
public String delete(Long id) {

    Schedule findSchedule = scheduleRepository.findByIdOrElseThrow(id);

    scheduleRepository.delete(findSchedule);

    return "일정이 성공적으로 삭제되었습니다.";
}

삭제가 제일 간단했다. 기존에 있던 Id값을 찾아서 delete 메소드로 삭제 처리해주면 간단하게 삭제 되었다.

💥 예외처리 (미니세션)

✅ Java에서의 예외처리 방식 (try - catch문, throws)

try-catch

  • try-catch 구문으로 예외를 처리하거나, throws 키워드로 상위 메서드로 예외를 던질 수 있습니다.
public String someMethod() {
    try {
        // 예외가 발생할 수 있는 코드
    } catch (Exception e) {
        // 예외 처리
    }
    return "Done";
}
  • 간단하지만, Spring MVC 같은 웹 애플리케이션에서 발생하는 예외를 획일적으로 다루기 어렵다는 단점이 있습니다.
  • 예외가 발생할 때마다 각각의 try-catch를 배치하면 코드가 복잡해지고, 에러 페이지 표시나 로깅, 공통된 에러 메시지 처리 등이 중구난방이 될 수 있습니다.

✅ Servlet 컨테이너와 Spring MVC 예외 처리 흐름

Servlet 컨테이너의 예외 처리

  • Spring MVC는 기본적으로 Servlet 기반에서 동작합니다.
  • 클라이언트(브라우저)가 요청을 보내면, Servlet 컨테이너(Tomcat, Jetty 등)가 해당 요청을 받고, 내부적으로 Spring DispatcherServlet이 이를 받아 Controller로 전달합니다.
  • Controller에서 예외가 발생하면 기본적으로 Spring 내부에서 이를 처리하거나, 더 이상 처리할 수 없는 경우 최종적으로는 Servlet 컨테이너가 에러 페이지를 보여주게 됩니다.

 

✅ @ExceptionHandler의 기본 개념

@ExceptionHanlder ?

  • Controller 내에서 특정 예외를 직접 핸들링하기 위한 Spring 애노테이션입니다.
  • 메서드에 붙여서, “이 메서드는 이러한 예외가 발생했을 때 동작해라!” 라고 알려주는 역할을 합니다.
@Controller
public class SampleController {

    @GetMapping("/test")
    public String testMethod() {
        // 예시로 NPE(NullPointerException)가 발생한다고 가정
        String data = null;
        int length = data.length(); // 여기서 예외 발생
        return "testView";
    }

    // NPE가 발생했을 때 처리하는 메서드
    @ExceptionHandler(NullPointerException.class)
    public String handleNullPointerException(NullPointerException e) {
        System.out.println("NullPointerException 발생: " + e.getMessage());
        return "error/nullPointerError";
        // "error/nullPointerError" 라는 뷰로 이동한다고 가정
    }
}

 

@ResponseStatus와 함께 쓰는 경우

  • 종종 예외에 따라 HTTP 상태 코드를 함께 변경해야 할 때가 있습니다.
  • 예: 404(Not Found), 400(Bad Request) 등을 명시적으로 표시하고 싶다면, @ResponseStatus 애노테이션을 사용할 수 있습니다.
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String handleIllegalArgumentException(IllegalArgumentException e) {
    return "error/badRequestError";
}

✅ 커스텀 예외(Custom Exception)와 @ExceptionHandler 연동

커스텀 예외를 만드는 이유

  • REST API나 웹 애플리케이션을 만들다 보면, 특정 상황에서만 발생하는 예외를 별도로 구분하고 싶을 때가 있습니다.
  • 예: “사용자 정보가 존재하지 않는다.”, “권한이 부족하다.” 등등, 비즈니스 로직에서 중요한 예외를 나타내기 위해 커스텀 예외를 만들 수 있습니다.
반응형

'[내일배움캠프-Sparta] > Spring 6기' 카테고리의 다른 글

TIL 33 [ 과제 끝 + 스탠다드반 ( 영속성 컨텍스트 ) ]  (0) 2025.04.04
TIL 32 [ Spring 일정관리 앱 Lv2~5 ]  (0) 2025.04.04
TIL 30 [ Spring ( Data JPA ), 스탠다드반 ( Optional ) ]  (0) 2025.04.01
TIL 29 [ Spring ( Filter, 객체와 RDB, JPA , 영속성 컨텍스트, Entity 제작 ) ]  (0) 2025.03.31
Spring ( Session, Token, JWT )  (0) 2025.03.30
'[내일배움캠프-Sparta]/Spring 6기' 카테고리의 다른 글
  • TIL 33 [ 과제 끝 + 스탠다드반 ( 영속성 컨텍스트 ) ]
  • TIL 32 [ Spring 일정관리 앱 Lv2~5 ]
  • TIL 30 [ Spring ( Data JPA ), 스탠다드반 ( Optional ) ]
  • TIL 29 [ Spring ( Filter, 객체와 RDB, JPA , 영속성 컨텍스트, Entity 제작 ) ]
dimenshun
dimenshun
한 소년의 개발 일기
    반응형
  • dimenshun
    Dev Life Notes
    dimenshun
  • 전체
    오늘
    어제
    • 분류 전체보기 (268)
      • CS (23)
        • 자료구조 (0)
        • 알고리즘 (0)
        • 컴퓨터 구조 (8)
        • 네트워크 (6)
        • 운영체제 (3)
        • DB ( + SQLD ) (5)
        • SW공학 (1)
      • 프로그래밍 (3)
        • Java (0)
        • Spring (0)
        • HTML,CSS (3)
        • JavaScript (0)
      • 개발 툴 (7)
        • Git(버전관리) (1)
        • Docker (3)
        • AWS (2)
        • JSP (1)
      • 코딩테스트(Algorithm) (125)
        • 백준 (6)
        • 프로그래머스 (119)
      • [내일배움캠프-Sparta] (110)
        • Spring 6기 (106)
        • KPT 회고 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    내일배움캠프
    spring
    AWS
    docker
    SQL
    배포
    Testcode
    알고리즘
    Python
    트랜잭션
    Til
    It
    코딩테스트
    web
    컴퓨터구조
    Java
    백엔드
    cs
    db
    네트워크
    개발자
    network
    메모리
    웹
    SQLD
    OS
    운영체제
    KPT
    CPU
    세션
  • hELLO· Designed By정상우.v4.10.3
dimenshun
TIL 31 [ Spring 일정관리 앱 Lv0 ~ 1, + 미니세션 ( 예외처리 ) ]
상단으로

티스토리툴바