

schedule 테이블의 기본키 입니다.user 엔티티를 조회를 위한 외래키입니다.varchar 형태로 데이터가 담깁니다. 데이터 크기가 클 경우는 Lob을 사용해야합니다.TimeStamp 형식으로 기록됩니다.TimeStamp 형식으로 기록됩니다.외래키입니다.양방향 연관관계를 위한 것입니다.User 테이블의 기본 키입니다.TimeStamp 형식으로 기록됩니다.TimeStamp 형식으로 기록됩니다.POST : /api/schedule

{
"username" : "user1",
"password" : "1234",
"todoList" : "today study spring",
"email" : "asdf@naver.com"
}
@PostMapping("/schedule")
public UUID addSchedule(@RequestBody RequestScheduleWithUserDto requestScheduleWithUserDto) {
return scheduleService.save(requestScheduleWithUserDto);
}
HttpBody에 담겨 있는 Json을 서비스 계층으로 전달해줍니다.@Transactional
public UUID save(RequestScheduleWithUserDto requestScheduleWithUserDto) {
UUID scheduleId = UUID.randomUUID();
UUID userId = UUID.randomUUID();
LocalDateTime now = LocalDateTime.now();
userRepository.add(scheduleId, userId, now, requestScheduleWithUserDto);
scheduleRepository.add(scheduleId, userId, now, requestScheduleWithUserDto);
return scheduleId;
}
UUID 를 공통적으로 생성합니다.userRepository, scheduleRepository 로 데이터를 담아서 전달해줍니다.@Transactional 은 원자성을 만족하기위한 코드입니다. 항상 User가 먼저 저장되어야 합니다.public void add(UUID scheduleId, UUID userId, LocalDateTime now, RequestScheduleWithUserDto requestScheduleWithUserDto) {
Schedule schedule = new Schedule(scheduleId, userId, requestScheduleWithUserDto.getTodoList(), now, now);
String sql = "insert into schedule(schedule_id, user_id, todo_list, created_at, updated_at) values (?, ?, ?, ?, ?)";
jdbcTemplate.update(sql, schedule.getScheduleId().toString(), schedule.getUserId().toString(), schedule.getTodoList(), schedule.getCreatedAt(), schedule.getUpdatedAt());
}
public void add(UUID scheduleId, UUID userId, LocalDateTime now, RequestScheduleWithUserDto dto) {
User user = new User(userId, scheduleId, dto.getUsername(), dto.getPassword(), dto.getEmail(), now, now);
String sql = "insert into user(user_id, schedule_id, username, password, email, created_at, updated_at) values(?, ?, ?, ?, ?, ?, ?)";
jdbcTemplate.update(sql, user.getUserId().toString(), user.getScheduleId().toString(), user.getUsername(), user.getPassword(), user.getEmail(), user.getCreatedAt(), user.getUpdatedAt());
}
jdbcTemplate 을 이용하여 데이터를 저장해줍니다.GET : /api/{scheduleId}

{
"scheduleId": "17953acc-5943-449c-9a2d-7a0c087cf1fe",
"userId": "93fae0ef-1ae9-48af-9e6b-f5f2c769bbfc",
"todoList": "today study spring",
"username": "user1",
"email": "asdf@naver.com",
"createdAt": "2024-09-26T21:46:45",
"updatedAt": "2024-09-26T21:46:45"
}
@GetMapping("/schedule/{scheduleId}")
public ResponseEntity<ResponseDetailsScheduleDto> getSchedule(@PathVariable String scheduleId) {
return ResponseEntity.ok(scheduleService.getTodoList(UUID.fromString(scheduleId)));
}
scheduleId를 쿼리 파라미터로 할당받아 서비스 계층으로 전달해줍니다. public ResponseDetailsScheduleDto getTodoList(UUID scheduleId) {
return scheduleRepository.findScheduleById(scheduleId);
}
public ResponseDetailsScheduleDto findScheduleById(UUID scheduleId) {
String sql = "select s.schedule_id, s.user_id, s.todo_list, u.username, u.email, s.created_at, s.updated_at from schedule s join user u on s.user_id = u.user_id where s.schedule_id = ?";
return jdbcTemplate.queryForObject(sql, new ScheduleDetailsRowMapper(), scheduleId.toString());
}
Join 을 통해 데이터를 가져온후 DTO 에 맵핑합니다.PUT : /api/{scheduleId}

{
"todoList" : "TIL 작성하기",
"password" : "1234"
}

today study spring 에서 TIL 작성하기 로 변경되었습니다.@PutMapping("/schedule/{scheduleId}")
public UUID updateSchedule(@PathVariable String scheduleId, @RequestBody UpdateTodoList updateTodoList) throws BadRequestException {
return scheduleService.updateSchedule(UUID.fromString(scheduleId), updateTodoList);
}
scheduleId 는 쿼리파라미터로 전달받습니다.todoList 와 비밀번호를 Http Body 를 통해서 전달받습니다.public UUID updateSchedule(UUID scheduleId, UpdateTodoList updateTodoList) throws BadRequestException {
String password = findUserById(scheduleId);
if (!password.equals(updateTodoList.getPassword())) {
throw new BadRequestException("비밀번호가 일치하지 않습니다.");
}
return scheduleRepository.update(scheduleId, updateTodoList);
}
스케쥴아이디를 통해 유저 정보를 가져옵니다.비밀번호를 확인하고 비밀번호가 맞지 않다면 BadRequestException 예외를 던져줍니다.public UUID update(UUID scheduleId, UpdateTodoList updateData) {
String sql = "update schedule set todo_list = ?, updated_at = ? where schedule_id = ?";
jdbcTemplate.update(sql, updateData.getTodoList(), LocalDateTime.now(), String.valueOf(scheduleId));
return scheduleId;
}
DELETE : /api/{scheduleId}

{
"password" : "1234"
}
@DeleteMapping("/schedule/{scheduleId}")
public void deleteSchedule(@PathVariable String scheduleId, @RequestBody Map<String, String> request) throws BadRequestException {
scheduleService.deleteSchedule(UUID.fromString(scheduleId), request.get("password"));
}
scheduleId를 전달받습니다.Map을 사용하여 값을 가져옵니다.HttpServletRequest.getParameter() 를 통해 가져와도 됩니다.@Transactional
public void deleteSchedule(UUID scheduleId, String requestPassword) throws BadRequestException {
String password = findUserById(scheduleId);
if (!password.equals(requestPassword)) {
throw new BadRequestException("비밀번호가 일치하지 않습니다.");
}
scheduleRepository.deleteScheduleById(scheduleId);
userRepository.deleteUser(scheduleId);
}
scheduleRepository와 userRepository를 호출하여 데이터 삭제를 진행시켜줍니다.public void deleteScheduleById(UUID scheduleId) {
String sql = "delete from schedule where schedule_id = ?";
jdbcTemplate.update(sql, scheduleId.toString());
}
GET : /api/schedules?limit={limit}&offset={offset}

[
{
"scheduleId": "c5994268-f0d2-4ac0-a82c-1742617cb99f",
"userId": "4445ec97-7582-4ebb-a207-5967529d8458",
"todoList": "today study spring cloud",
"username": "user5",
"createdAt": "2024-09-26T22:16:36",
"updatedAt": "2024-09-26T22:16:36"
},
{
"scheduleId": "75128456-10f7-499a-a3b5-6de77f043c09",
"userId": "052d5d9b-6607-456e-8a59-2b2c6390cf04",
"todoList": "today study spring AI",
"username": "user4",
"createdAt": "2024-09-26T22:16:28",
"updatedAt": "2024-09-26T22:16:28"
},
{
"scheduleId": "12fdc960-9824-4826-bdfb-bbba9c6941b3",
"userId": "3849e325-ef79-4608-babb-aa73393ad9d7",
"todoList": "today study spring batch",
"username": "user3",
"createdAt": "2024-09-26T22:16:20",
"updatedAt": "2024-09-26T22:16:20"
},
{
"scheduleId": "db606d7b-5856-4264-b0c9-905093f39bcc",
"userId": "c147acdb-b213-4f61-a523-12bfb4b5f7c8",
"todoList": "today study spring security",
"username": "user2",
"createdAt": "2024-09-26T22:16:14",
"updatedAt": "2024-09-26T22:16:14"
},
{
"scheduleId": "918e2248-29ca-412e-98e5-34afa83e36f4",
"userId": "659cadf6-b916-4563-a309-42c65a7ba0f5",
"todoList": "today study spring",
"username": "user1",
"createdAt": "2024-09-26T22:16:07",
"updatedAt": "2024-09-26T22:16:07"
}
]
5개의 게시글을 가져옵니다.@GetMapping("/schedules")
public ResponseEntity<List<ResponseScheduleDto>> getAllPost(@RequestParam(defaultValue = "10") int limit, @RequestParam(defaultValue = "1") int offset) {
return ResponseEntity.ok(scheduleService.getAllTodoList(limit, offset));
}
@RequestParam 옵션에 required = true 을 적용하여 무조건 limit, offset 을 받아줘도 되지만 defaultValue를 이용하여 입력받지 않더라도 기본적으로 첫번째 페이지부터 10개의 게시글을 가져옵니다.public List<ResponseScheduleDto> getAllTodoList(int limit, int offset) {
return scheduleRepository.findAllSchedule(limit, (offset - 1) * limit);
}
0부터 시작하기 때문에 offset = (offset - 1) * limit 를 적용해줍니다.public List<ResponseScheduleDto> findAllSchedule(int limit, int offset) {
String sql = "select s.schedule_id, u.user_id, s.todo_list, u.username, s.created_at, s.updated_at " +
"from schedule s join user u on s.user_id = u.user_id order by s.updated_at desc " +
"limit ? offset ?";
return jdbcTemplate.query(sql, new Object[]{limit, offset}, new ScheduleRowMapper());
}
🚫 비밀번호가 일치하지 않는 경우

@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BadRequestException.class)
public ResponseEntity<String> missMatch(BadRequestException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}
}
컨트롤러 어드바이스를 사용하면 개별 컨트롤러뿐만 아니라 전체 애플리케이션에 적용할 수 있습니다.BadRequestException 이 발생하면 HttpBody 에 에러메시지를 출력해줍니다.📖 톺아보기