Spring
JDBC Templete을 이용한 일정 관리 서버 CRUD 구현
김예나
2025. 1. 27. 18:07
Server 구조
일정 생성
- ScheduleRequestDto을 이용하여 생성 정보를 요청
- 생성 날짜(created_at)와 수정 날짜(updated_at)는 서버의 Repository단에서 LocalDateTime.now()를 사용하여 값을 넣어줌
@Override
public ScheduleResponseDto saveSchedule(Schedule schedule) {
SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
jdbcInsert.withTableName("schedule").usingGeneratedKeyColumns("id");
Map<String, Object> parameters = new HashMap<>();
parameters.put("content", schedule.getContent());
parameters.put("author", schedule.getAuthor());
parameters.put("password", schedule.getPassword());
parameters.put("created_at", LocalDateTime.now());
parameters.put("updated_at", LocalDateTime.now());
Number key = jdbcInsert.executeAndReturnKey(new MapSqlParameterSource(parameters));
return new ScheduleResponseDto(key.longValue(), schedule.getContent(), schedule.getAuthor(), schedule.getCreateDate(), schedule.getModifiedDate());
}
전체 일정 조회하기
- 수정일과 작성자명을 바탕으로 조회하라는 조건이 있었기 때문에 쿼리 파라미터로 각각의 정보를 받음
@GetMapping
public ResponseEntity<List<ScheduleResponseDto>> findAllSchedules(
@RequestParam("author") String author,
@RequestParam("updated_at") String modifiedDate
){
return new ResponseEntity<>(scheduleService.findAllSchedules(author, modifiedDate), HttpStatus.OK);
}
고민했던 점
조회 결과가 "조건 중 한 가지만을 충족하거나, 둘 다 충족을 하지 않을 수도, 두 가지를 모두 충족할 수도 있습니다." 라고 명시되어 있었다
- 조건 중 한가지나 둘 다 충족하는 경우는 쿼리에서 수정일이랑 작성자명을 가지고 where절이랑 or조건을 사용하여 해결
- 둘 다 충족하지 않는 경우 또한 where절이랑 or조건 이랑 not조건을 사용해서 해결
이렇게 쿼리를 2개 만들고 조회 api도 2개로 나눠서 만들라는 의미인지 고민을 했다.
(그래서 튜터님한테 여쭤봤는데 api는 하나여야 한다고 하셨다😅)
하지만 사실 저 조건을 충족하려면 단지 select id, content, author, created_at, updated_at from schedule 이렇게 쿼리를 날리면 되지 않나라는 고민에 휩쌓이게 됐다.
하지만 저렇게 쿼리를 날리면 수정일과 작성자명의 조건이 아예 필요 없어지는 것 같아서 일단 과제 조건에 맞게 결과를 내면서 수정일과 작성자명을 사용하는 쿼리를 입력해서 조회하는 걸로 결정했다.
@Override
public List<ScheduleResponseDto> findScheduleByAuthorOrModifiedDate(String author, String modifiedDate) {
return jdbcTemplate.query(
"select id, content, author, created_at, updated_at from schedule " +
"where author = ? || date(updated_at) = ? || author != ? || date(updated_at) != ? order by updated_at desc",
scheduleRowMapper(), author, modifiedDate, author, modifiedDate);
}
일정 단건 조회하기
- Path를 사용하여 해당 id값에 해당하는 일정을 조회하도록 구현
@Override
public Schedule findScheduleByIdOrElseThrow(Long id) {
List<Schedule> result = jdbcTemplate.query("select * from schedule where id = ?", scheduleRowMapperV2(), id);
return result.stream().findAny().orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Does not exist id = " + id));
}
public RowMapper<Schedule> scheduleRowMapperV2(){
return new RowMapper<Schedule>() {
@Override
public Schedule mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Schedule(
rs.getLong("id"),
rs.getString("content"),
rs.getString("author"),
rs.getTimestamp("created_at").toLocalDateTime(),
rs.getTimestamp("updated_at").toLocalDateTime()
);
}
};
}
일정 수정하기
- Path로 수정할 일정의 key값을 받고, ScheduleRequestDto를 통해서 수정할 내역을 요청받음
@PatchMapping("/{id}")
public ResponseEntity<ScheduleResponseDto> updateSchedule(@PathVariable Long id, @RequestBody ScheduleRequestDto requestDto) {
return new ResponseEntity<>(scheduleService.updateSchedule(id, requestDto.getPassword(), requestDto.getContent(), requestDto.getAuthor()), HttpStatus.OK);
}
- key값을 통해서 수정할 엔티티의 비밀번호와 ScheduleRequestDto에서 입력받은 비밀번호와 일치하는지 확인함.
@Override
public Schedule findSchedulePasswordByIdOrElseThrow(Long id) {
List<Schedule> result = jdbcTemplate.query("select * from schedule where id = ?", scheduleRowMapperV3(), id);
return result.stream().findAny().orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Does not exist id = " + id));
}
public RowMapper<Schedule> scheduleRowMapperV3(){
return new RowMapper<Schedule>() {
@Override
public Schedule mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Schedule(
rs.getLong("id"),
rs.getString("content"),
rs.getString("author"),
rs.getString("password"),
rs.getTimestamp("created_at").toLocalDateTime(),
rs.getTimestamp("updated_at").toLocalDateTime()
);
}
};
}
- 만약 일치하지 않는다면 HttpStatus.BAD_REQUEST 로 응답
@Override
public ScheduleResponseDto updateSchedule(Long id, String password, String content, String author) {
// 수정할 일정의 비밀번호 조회
Schedule schedule = scheduleRepository.findSchedulePasswordByIdOrElseThrow(id);
if (!schedule.getPassword().equals(password)){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "비밀번호가 일치하지 않습니다");
}
int updatedRow = scheduleRepository.updateSchedule(id, content, author);
if (updatedRow == 0) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "수정된 데이터가 없습니다");
}
Schedule updatedSchedule = scheduleRepository.findScheduleByIdOrElseThrow(id);
return new ScheduleResponseDto(updatedSchedule);
}
일정 삭제하기
- Path로 수정할 일정의 key값을 받아서 삭제
- 수정 또한 update사용!
@Override
public int deleteSchedule(Long id) {
return jdbcTemplate.update("delete from schedule where id = ?", id);
}