개요
앞에서 설계한 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;
}
}
느낀점
이번 과제를 마치고 조금 더 스프링 부트 사용법에 익숙해지고 있는 것 같다. 중간에 오타로 인한 에러, @Valid 사용에 대해 힘듦이 있었지만, 검색을 통해서 잘 해결해나간 것 같다. 이외에도 Stream도 많이사용해보고 Builder도 많이 사용하고, JPA를 따라하면서 제네릭이랑 인터페이스도 활용해서 알뜰하게 잘 만든거 같다.
'부트캠프 > Dev' 카테고리의 다른 글
뉴스피드 프로젝트 1일차 (0) | 2024.09.04 |
---|---|
필터에서 예외처리 (0) | 2024.08.20 |
개인과제 구현 -1 (0) | 2024.08.13 |
스프링 입문 개인 프로젝트 시작 (0) | 2024.08.11 |
캠프 프로그램 팀프로젝트 회고록 (0) | 2024.08.08 |