부트캠프/Dev

개인과제 구현 -2

nameless1004 2024. 8. 16. 10:20

개요

앞에서 설계한 api 명세서와 erd를 가지고 개인 과제 구현을 해보자. 

api 명세서는 postman으로 다시 만들었다.
스케쥴
매니져

Service

서비스는 Controller에서 데이터를 받고 DB에서 데이터를 가져와서 가공 후 Controller에게 전달해주는 역할을 담당하고 있습니다.

package com.sparta.springasignment.schedule.service;

import com.sparta.springasignment.common.exception.InvalidIdException;
import com.sparta.springasignment.common.exception.MissmatchPasswordException;
import com.sparta.springasignment.schedule.dto.ScheduleDeleteDto;
import com.sparta.springasignment.schedule.dto.ScheduleRequestDto;
import com.sparta.springasignment.schedule.dto.ScheduleResponseDto;
import com.sparta.springasignment.schedule.entity.Schedule;
import com.sparta.springasignment.schedule.repository.ScheduleRepository;
import java.time.LocalDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.ExceptionHandler;

@Service
@RequiredArgsConstructor
public class ScheduleService {

    private final ScheduleRepository repository;

    // DB 저장
    public ScheduleResponseDto save(ScheduleRequestDto scheduleRequestDto) {
        Schedule schedule = Schedule.builder()
            .managerId(scheduleRequestDto.getManagerId())
            .password(scheduleRequestDto.getPassword())
            .contents(scheduleRequestDto.getContents())
            .createdTime(LocalDateTime.now())
            .updatedTime(LocalDateTime.now())
            .build();

        Long id = repository.save(schedule);

        schedule.setScheduleId(id);
        return ScheduleResponseDto.builder()
            .scheduleId(schedule.getScheduleId())
            .managerId(schedule.getManagerId())
            .password(schedule.getPassword())
            .contents(schedule.getContents())
            .createdTime(schedule.getCreatedTime())
            .updatedTime(schedule.getUpdatedTime())
            .build();
    }

    // 업데이트
    public ScheduleResponseDto updateSchedule(Long scheduleId,
        ScheduleRequestDto updateRequestDto) {

        Schedule target = repository.findById(scheduleId)
            .orElseThrow(() -> new InvalidIdException(scheduleId));

        if (!target.getPassword()
            .equals(updateRequestDto.getPassword())) {
            throw new MissmatchPasswordException();
        }

        target.setUpdatedTime(LocalDateTime.now());
        target.setContents(updateRequestDto.getContents());
        target.setManagerId(updateRequestDto.getManagerId());
        repository.update(target);

        return ScheduleResponseDto.builder()
            .scheduleId(target.getScheduleId())
            .managerId(target.getManagerId())
            .password(target.getPassword())
            .contents(target.getContents())
            .createdTime(target.getCreatedTime())
            .updatedTime(target.getUpdatedTime())
            .build();
    }

    // 삭제
    public ScheduleResponseDto delete(Long id, ScheduleDeleteDto deleteDto) {
        Schedule deleted = repository.findById(id)
            .orElseThrow(() -> new InvalidIdException(id));

        if (!deleted.getPassword()
            .equals(deleteDto.getPassword())) {
            throw new MissmatchPasswordException();
        }

        repository.delete(deleted);

        return ScheduleResponseDto.builder()
            .scheduleId(deleted.getScheduleId())
            .managerId(deleted.getManagerId())
            .password(deleted.getPassword())
            .contents(deleted.getContents())
            .createdTime(deleted.getCreatedTime())
            .updatedTime(deleted.getUpdatedTime())
            .build();
    }

    // 다건 조회
    public List<ScheduleResponseDto> findAllSchedules(String updatedTime, Long managerId) {

        List<Schedule> allManager = repository.findAllByFilter(updatedTime, managerId);
        return allManager.stream()
            .map(schedule -> {
                return ScheduleResponseDto.builder()
                    .scheduleId(schedule.getScheduleId())
                    .managerId(schedule.getManagerId())
                    .password(schedule.getPassword())
                    .contents(schedule.getContents())
                    .createdTime(schedule.getCreatedTime())
                    .updatedTime(schedule.getUpdatedTime())
                    .build();
            })
            .toList();
    }

    // 단건 조회
    public ScheduleResponseDto findScheduleById(Long id) {
        Schedule schedule = repository.findById(id)
            .orElseThrow(() -> new InvalidIdException(id));

        return ScheduleResponseDto.builder()
            .scheduleId(schedule.getScheduleId())
            .managerId(schedule.getManagerId())
            .password(schedule.getPassword())
            .contents(schedule.getContents())
            .createdTime(schedule.getCreatedTime())
            .updatedTime(schedule.getUpdatedTime())
            .build();
    }

    // 페이지 조회
    public List<ScheduleResponseDto> findSchedulsByPage(Integer pageNum, Integer pageSize) {
        List<Schedule> schedulesByPage = repository.findAllByPage(pageNum, pageSize);

        return schedulesByPage.stream()
            .map(schedule -> {
                return ScheduleResponseDto.builder()
                    .scheduleId(schedule.getScheduleId())
                    .managerId(schedule.getManagerId())
                    .password(schedule.getPassword())
                    .contents(schedule.getContents())
                    .createdTime(schedule.getCreatedTime())
                    .updatedTime(schedule.getUpdatedTime())
                    .build();
            })
            .toList();
    }

    @ExceptionHandler({IllegalArgumentException.class})
    public ResponseEntity<String> handle(Exception e) {
        return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
    }
}

Controller

스케쥴 컨트롤러와 매니저 컨트롤러를 구현하였고, api 명세서에 따라 매핑을 해주었습니다. 또한, 상태 코드를 반환하기 위해 ResponseEntity를 사용하였습니다.

package com.sparta.springasignment.schedule.controller;

import com.sparta.springasignment.schedule.dto.ScheduleDeleteDto;
import com.sparta.springasignment.schedule.dto.ScheduleRequestDto;
import com.sparta.springasignment.schedule.dto.ScheduleResponseDto;
import com.sparta.springasignment.schedule.service.ScheduleService;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Positive;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

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

    private final ScheduleService service;

    @GetMapping
    public ResponseEntity<List<ScheduleResponseDto>> getAllSchedule(
        @Positive @RequestParam(required = false) Long managerId,
        @RequestParam(required = false) @Pattern(regexp = "^\\d{4}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$") String updatedTime) {
        return new ResponseEntity<>(service.findAllSchedules(updatedTime, managerId),
            HttpStatus.OK);
    }

    @GetMapping("/{scheduleId}")
    public ResponseEntity<ScheduleResponseDto> getSchedule(
        @Positive @PathVariable Long scheduleId) {
        return new ResponseEntity<>(service.findScheduleById(scheduleId), HttpStatus.OK);
    }

    @PostMapping
    public ResponseEntity<ScheduleResponseDto> postSchedule(
        @Valid @RequestBody ScheduleRequestDto dto) {
        ScheduleResponseDto save = service.save(dto);
        return new ResponseEntity<>(save, HttpStatus.CREATED);
    }

    @PutMapping("/{scheduleId}")
    public ResponseEntity<ScheduleResponseDto> putSchedule(@Positive @PathVariable Long scheduleId,
        @Valid @RequestBody ScheduleRequestDto dto) {
        ScheduleResponseDto scheduleResponseDto = service.updateSchedule(scheduleId, dto);
        return new ResponseEntity<>(scheduleResponseDto, HttpStatus.OK);
    }

    @DeleteMapping("/{scheduleId}")
    public ResponseEntity<Void> deleteSchedule(@Positive @PathVariable Long scheduleId,
        @Valid @RequestBody ScheduleDeleteDto dto) {
        service.delete(scheduleId, dto);
        return ResponseEntity.ok()
            .build();
    }

    // page
    @GetMapping("/")
    public ResponseEntity<List<ScheduleResponseDto>> getAllSchedulesByPage(
        @Min(1) @RequestParam(defaultValue = "1") Integer page,
        @Min(1) @RequestParam(defaultValue = "1") Integer size) {
        List<ScheduleResponseDto> schedulsByPage = service.findSchedulsByPage(page, size);
        ResponseEntity<List<ScheduleResponseDto>> response = new ResponseEntity<>(schedulsByPage,
            HttpStatus.OK);
        return response;
    }

}

느낀점

깃허브

 

GitHub - Nameless1004/spring-basic-asignment

Contribute to Nameless1004/spring-basic-asignment development by creating an account on GitHub.

github.com

이번 과제를 마치고 조금 더 스프링 부트 사용법에 익숙해지고 있는 것 같다. 중간에 오타로 인한 에러, @Valid 사용에 대해 힘듦이 있었지만, 검색을 통해서 잘 해결해나간 것 같다. 이외에도 Stream도 많이사용해보고 Builder도 많이 사용하고, JPA를 따라하면서 제네릭이랑 인터페이스도 활용해서 알뜰하게 잘 만든거 같다.