할일
, 작성자명
,비밀번호
, 작성일
, 수정일
을 저장작성일
과 수정일
은 동일수정일 내림차순
으로 정렬하여 조회할일
만 수정 가능비밀번호
를 함께 전달수정일
을 수정완료 시점으로 변경비밀번호
가 맞아야 수정 가능이름
, 이메일
, 등록일
, 수정일
페이지 번호
, 페이지 크기
를 쿼리 파라미터로 받음작성자 이름
포함[Exception] 예외처리
@RestControllerAdvice
을 활용하여 공통 예외 처리비밀번호
가 일치하지 않을 때 예외 발생[Validated] 유효성 검사 및 기타 사항
@Validated
어노테이션 사용할일
은 최대 200자 이내로 제한, 필수값 처리비밀번호
는 필수값 처리현재 프로젝트에서 만족했고, 앞으로의 훈련기간에서 지속하고 싶은 부분을 작성했다.
현재 프로젝트에서 어려웠던 점과 아쉬웠던 점을 작성했다.
ResponseEntity<T>
너 T야???// [Controller] Schedule 생성 Controller
@PostMapping
public ResponseEntity<T> createSchedule(
@Valid @RequestBody ScheduleRequestDto requestDto,
BindingResult bindingResult) {
// ✅ 1-1. 유효성 검사 실패 시
if (bindingResult.hasErrors()) {
// 에러상태, 에러메시지를 저장하는 변수 선언
Map<String, String> errors = new HashMap<>();
// error 메시지를 저장
for (FieldError error : bindingResult.getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
}
// ✅ 1-2. Map<String, String> 타입을 반환
return ResponseEntity
.status(HttpStatus.BAD_REQUEST).body(errors);
}
// ✅ 2-1. 유효성 검사 성공시, scheduleService 실행
ScheduleResponseDto responseDto = scheduleService
.createSchedule(requestDto);
// ✅ 2-2. ResponseDto 타입을 반환
return ResponseEntity
.status(HttpStatus.CREATED).body(responseDto);
}
createSchedule
메서드의 반환타입은 T(제네릭) 인데Map<String, String>
이 반환되고,ResponseDto
타입이 반환된다..@RestContollerAdvice
어노테이션을 알기 전이라 고민이 되었다.@PostMapping
// ✅ ? 제네릭 와일드 사용
public ResponseEntity<?> createSchedule(
@Valid @RequestBody ScheduleRequestDto requestDto,
BindingResult bindingResult) {
....
}
ResponseEntity<?>
로 변경했다.<?>
는 모든 타입을 허용하는 제네릭 와일드카드라고 하며, 자유도가 높은 키워드이다.<? extends 상위타입>
으로@PostMapping
public ResponseEntity<ScheduleResponseDto> createSchedule(
@Validated(ScheduleRequestDto.OnCreate.class)
@RequestBody ScheduleRequestDto dto,
@ModelAttribute("validUserId") Long validUserId
){
// 생성된 일정 응답 객체 반환
return new ResponseEntity<>(scheduleService
.createSchedule(validUserId, dto), HttpStatus.CREATED);
}
@RestControllerAdvice
어노테이션으로 전역 예외처리 핸들링을 하였고, BindingResult
에러 핸들링 부분을 제거하였다.@Valid
대신에 @Validated
어노테이션을 사용하였다!일정 관리를 하면서 생성/수정/삭제할 때, 비밀번호를 받아서 관리하고 있다.
요구사항에 따로 암호화 부분은 없었지만, 그래도 해야 된다 생각하고 구현하게 되었다.
// 0. 선언
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// 1. 비밀번호 필드 암호화 로직
String encryptedPassword = passwordEncoder.encode(dto.getPassword());
// 2. 비밀번호 비교 로직
if (!passwordEncoder.matches(
dto.getPassword(), existSchedule.getPassword()))
{
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "비밀번호가 일치하지 않습니다.");
}
@Getter
public class ScheduleRequestDto {
@NotBlank(message = "할 일을 입력해주세요.")
private String todo;
@NotBlank(message = "비밀번호를 입력해주세요.")
private String password;
}
todo
필드를 받아야 한다..ScheduleDeleteRequestDto
를 만들어야 되나 고민했지만,@Getter
public class ScheduleRequestDto {
// ✅ 유효성 그룹 인터페이스 정의
// ✅ 3개로 구분 (Create, Update, Delete)
public interface OnCreate {}
public interface OnUpdate {}
public interface OnDelete {}
// ✅ todo 필드는 Create, Update 할 때, 필수 필드로 설정
@NotBlank(message = "할 일을 입력해주세요.", groups = {OnCreate.class, OnUpdate.class})
@Size(max = 200, message = "할 일은 200자 이내로 입력해주세요.", groups = {OnCreate.class, OnUpdate.class})
private String todo;
// ✅ pasword 필드는 Create, Update, Delete 할 때, 필수 필드로 설정
@NotBlank(message = "비밀번호를 입력해주세요.", groups = {OnCreate.class, OnUpdate.class, OnDelete.class})
@Size(max = 20, message = "비밀번호는 20자 이내로 입력해주세요.", groups = {OnCreate.class, OnUpdate.class})
private String password;
}
// Controller
@DeleteMapping("/{scheduleId}")
public ResponseEntity<ApiResponseDto> deleteSchedule(
@Validated(ScheduleRequestDto.OnDelete.class) @RequestBody ScheduleRequestDto dto,
@ModelAttribute("validUserId") Long validUserId,
@PathVariable Long scheduleId
){
// 프론트에게 응답메시지 보내기 위해 204(NO_CONTENT) 대신 200(OK) 반환
return new ResponseEntity<>(scheduleService.deleteSchedule(validUserId, scheduleId, dto.getPassword()), HttpStatus.OK);
}
🤔 @Validated, @Valid 둘 중 어떤 것을 사용하지?
- 그룹 기능이 필요하면 @Validated를 사용하고, 그렇지 않다면 더 편한 것을 사용한다고 한다. 팀에 사황에 따라 다르다고 한다!
- @Valid는 자바에서 제공하고, @Validated는 스프링에서 제공하는 어노테이션
- 둘을 사용했을 때 발생하는 예외도 다르다.
@Valid에 의한 예외 : MethodArgumentNotValidException
@Validated에 의한 예외 : ConstraintViolationException
다음 프로젝트에서 시도해볼 점들을 작성했다.