나만의 일정 관리 앱 서버 만들기 JDBC

앞고기랑 소금·2024년 8월 19일

스파르타 TIL

목록 보기
23/43

23일차

API 명세서

기능MethodURLRequestResponse
일정 작성POST/api/schedule요청 body작성정보
일정 전체조회GET/api/schedule-일정전체 정보
선택한 일정 조회GET/api/schedule/{id}요청 query선택한 일정 정보
일정 목록 조회GET/api/schedule요청 param일정 목록 정보
일정 수정PUT/api/schedule/update요청 body일정 수정 정보
일정 삭제DELETE/api/schedule/delete요청 body-

ERD

schedule
id (pk)
toDo
name
password
dateTime

schedule.sql

create table schedule
(
    id       bigint auto_increment
        primary key,
    toDo     varchar(500) not null,
    name     varchar(255) not null,
    password varchar(255) not null,
    dateTime varchar(255) not null
);

Schedule.java

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.time.LocalDateTime;

@Getter
@Setter
@NoArgsConstructor
public class Schedule {
    private long id;
    private String toDo;
    private String name;
    private String password;
    private String dateTime;

    public Schedule(ScheduleRequestDTO requestDTO) {
        this.toDo = requestDTO.getToDo();
        this.name = requestDTO.getName();
        this.password = requestDTO.getPassword();
        this.dateTime = requestDTO.getDateTime();
    }
}

ScheduleRequestDTO.java

import lombok.Getter;

import java.time.LocalDateTime;

@Getter
public class ScheduleRequestDTO {
    private Long id;
    private String toDo;
    private String name;
    private String password;
    private String dateTime;

    public void setDateTime(String dateTime) {
        this.dateTime = dateTime;
    }
}

ScheduleResponseDTO.java

import lombok.Getter;

import java.time.LocalDateTime;

@Getter
public class ScheduleResponseDTO {
    private long id;
    private String toDo;
    private String name;
    private String password;
    private String dateTime;

    public ScheduleResponseDTO(Schedule schedule) {
        this.id = schedule.getId();
        this.toDo = schedule.getToDo();
        this.name = schedule.getName();
        this.password = schedule.getPassword();
        this.dateTime = schedule.getDateTime();
    }

    public ScheduleResponseDTO(Long id, String toDo, String name, String password, String dateTime) {
        this.id = id;
        this.toDo = toDo;
        this.name = name;
        this.password = password;
        this.dateTime = dateTime;
    }
}

ScheduleController.java

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.web.bind.annotation.*;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.LocalDateTime;
import java.util.*;

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

    private final JdbcTemplate jdbcTemplate;

    public ScheduleController(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @PostMapping("/schedule")
    public ScheduleResponseDTO creatSchedule(@RequestBody ScheduleRequestDTO requestDTO) {
        // RequestDto -> Entity
        // 할일, 담당자명, 비밀번호, 작성/수정일을 저장
        // 기간 정보는 날짜와 시간을 모두 포함한 형태
        // 최초 입력간에는 수정일은 작성일과 동일
        requestDTO.setDateTime(String.valueOf(LocalDateTime.now()));
        Schedule schedule = new Schedule(requestDTO);

        // 각 일정의 고유 식별자(ID)를 자동으로 생성하여 관리
        KeyHolder keyHolder = new GeneratedKeyHolder(); // 기본 키를 반환받기 위한 객체

        // DB 저장
        String sql = "INSERT INTO schedule (toDo, name, password, dateTime) VALUES (?, ?, ?, ?)";
        jdbcTemplate.update( con -> {
                    PreparedStatement preparedStatement = con.prepareStatement(sql,
                            Statement.RETURN_GENERATED_KEYS);

                    preparedStatement.setString(1, schedule.getToDo());
                    preparedStatement.setString(2, schedule.getName());
                    preparedStatement.setString(3, schedule.getPassword());
                    preparedStatement.setString(4, schedule.getDateTime());
                    return preparedStatement;
                },
                keyHolder);

        // DB Insert 후 받아온 기본키 확인
        Long id = keyHolder.getKey().longValue();
        schedule.setId(id);

        // Entity -> ResponseDto
        ScheduleResponseDTO scheduleResponseDTO = new ScheduleResponseDTO(schedule);

        return scheduleResponseDTO;
    }

    // 등록된 일정의 정보를 반환 받아 확인
    @GetMapping("/schedule")
    public List<ScheduleResponseDTO> getSchedule() {
        // DB 조회
        String sql = "SELECT * FROM schedule";

        return jdbcTemplate.query(sql, scheduleRowMapper());
    }

    // 선택한 일정 단건의 정보를 조회
    @GetMapping("/schedule/{id}")
    public ScheduleResponseDTO findId(@PathVariable Long id) {
        // 해당 schedule이 DB에 존재하는지 확인
        Schedule schedule = findById(id);
        if(schedule != null) {
            // schedule id로 조회
            String sql = "SELECT * FROM schedule WHERE id = ?";
            return jdbcTemplate.queryForObject(sql, scheduleRowMapper(), id);
        } else {
            throw new IllegalArgumentException("선택한 일정은 존재하지 않습니다.");
        }
    }

    @GetMapping("/schedule/find")
    public List<ScheduleResponseDTO> findDateTimeName(@RequestParam(required = false) String dateTime, @RequestParam(required = false)String name) {
        String sql ="";
        if (dateTime != null && name != null) {
            sql = "SELECT * FROM schedule WHERE dateTime LIKE ? AND name = ? ORDER BY dateTime DESC";
            dateTime = dateTime + "%";
            return jdbcTemplate.query(sql, scheduleRowMapper(), dateTime, name);
        } else if (dateTime != null && name == null) {
            sql = "SELECT * FROM schedule WHERE dateTime LIKE ? ORDER BY dateTime DESC";
            dateTime = dateTime + "%";
            return jdbcTemplate.query(sql, scheduleRowMapper(), dateTime);
        } else if (dateTime == null && name != null) {
            sql = "SELECT * FROM schedule WHERE name = ? ORDER BY dateTime DESC";
            return jdbcTemplate.query(sql, scheduleRowMapper(), name);
        } else {
            throw new IllegalArgumentException("Param을 작성해주세요.");
        }
    }
    @PutMapping("/schedule/update")
    public ScheduleResponseDTO updateSchedule(@RequestBody ScheduleRequestDTO requestDTO) {
        // 해당 메모가 DB에 존재하는지 확인
        Schedule schedule = findById(requestDTO.getId());
        if(schedule != null) {
            if (schedule.getPassword().equals(requestDTO.getPassword())) {
                // schedule 내용 수정
                String sql = "UPDATE schedule SET name = ?, toDo = ?, dateTime = ? WHERE id = ?";
                jdbcTemplate.update(sql, requestDTO.getName(), requestDTO.getToDo(), String.valueOf(LocalDateTime.now()), requestDTO.getId());

                sql = "SELECT * FROM schedule WHERE id = ?";
                return jdbcTemplate.queryForObject(sql, scheduleRowMapper(), requestDTO.getId());
            } else {
                throw new IllegalArgumentException("비밀번호가 일치하지 않습니다.");
            }
        } else {
            throw new IllegalArgumentException("선택한 일정은 존재하지 않습니다.");
        }
    }

    @DeleteMapping("/schedule/delete")
    public String deleteSchedule(@RequestBody ScheduleRequestDTO requestDTO) {
        // 해당 schedule이 DB에 존재하는지 확인
        Schedule schedule = findById(requestDTO.getId());
        if(schedule != null) {
            if (schedule.getPassword().equals(requestDTO.getPassword())) {
                // memo 삭제
                String sql = "DELETE FROM schedule WHERE id = ?";
                jdbcTemplate.update(sql, requestDTO.getId());

                return "일정 삭제 완료";
            } else {
                throw new IllegalArgumentException("비밀번호가 일치하지 않습니다");
            }
        } else {
            throw new IllegalArgumentException("선택한 일정은 존재하지 않습니다.");
        }
    }

    private Schedule findById(Long id) {
        // DB 조회
        String sql = "SELECT * FROM schedule WHERE id = ?";

        return jdbcTemplate.query(sql, resultSet -> {
            if(resultSet.next()) {
                Schedule schedule = new Schedule();
                schedule.setToDo(resultSet.getString("toDo"));
                schedule.setName(resultSet.getString("name"));
                schedule.setPassword(resultSet.getString("password"));
                schedule.setDateTime(resultSet.getString("dateTime"));
                return schedule;
            } else {
                return null;
            }
        }, id);
    }
    private RowMapper<ScheduleResponseDTO> scheduleRowMapper() {
        return((rs, rowNum) -> {
            // SQL 의 결과로 받아온 schedule 데이터들을 ScheduleResponseDTO 타입으로 변환해줄 메서드
            Long id = rs.getLong("id");
            String toDo = rs.getString("toDo");
            String name = rs.getString("name");
            String password = rs.getString("password");
            String dateTime = rs.getString("dateTime");
            return new ScheduleResponseDTO(id, toDo, name, password, dateTime);
        });
    }
}import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.web.bind.annotation.*;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.LocalDateTime;
import java.util.*;

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

    private final JdbcTemplate jdbcTemplate;

    public ScheduleController(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @PostMapping("/schedule")
    public ScheduleResponseDTO creatSchedule(@RequestBody ScheduleRequestDTO requestDTO) {
        // RequestDto -> Entity
        // 할일, 담당자명, 비밀번호, 작성/수정일을 저장
        // 기간 정보는 날짜와 시간을 모두 포함한 형태
        // 최초 입력간에는 수정일은 작성일과 동일
        requestDTO.setDateTime(String.valueOf(LocalDateTime.now()));
        Schedule schedule = new Schedule(requestDTO);

        // 각 일정의 고유 식별자(ID)를 자동으로 생성하여 관리
        KeyHolder keyHolder = new GeneratedKeyHolder(); // 기본 키를 반환받기 위한 객체

        // DB 저장
        String sql = "INSERT INTO schedule (toDo, name, password, dateTime) VALUES (?, ?, ?, ?)";
        jdbcTemplate.update( con -> {
                    PreparedStatement preparedStatement = con.prepareStatement(sql,
                            Statement.RETURN_GENERATED_KEYS);

                    preparedStatement.setString(1, schedule.getToDo());
                    preparedStatement.setString(2, schedule.getName());
                    preparedStatement.setString(3, schedule.getPassword());
                    preparedStatement.setString(4, schedule.getDateTime());
                    return preparedStatement;
                },
                keyHolder);

        // DB Insert 후 받아온 기본키 확인
        Long id = keyHolder.getKey().longValue();
        schedule.setId(id);

        // Entity -> ResponseDto
        ScheduleResponseDTO scheduleResponseDTO = new ScheduleResponseDTO(schedule);

        return scheduleResponseDTO;
    }

    // 등록된 일정의 정보를 반환 받아 확인
    @GetMapping("/schedule")
    public List<ScheduleResponseDTO> getSchedule() {
        // DB 조회
        String sql = "SELECT * FROM schedule";

        return jdbcTemplate.query(sql, scheduleRowMapper());
    }

    // 선택한 일정 단건의 정보를 조회
    @GetMapping("/schedule/{id}")
    public ScheduleResponseDTO findId(@PathVariable Long id) {
        // 해당 schedule이 DB에 존재하는지 확인
        Schedule schedule = findById(id);
        if(schedule != null) {
            // schedule id로 조회
            String sql = "SELECT * FROM schedule WHERE id = ?";
            return jdbcTemplate.queryForObject(sql, scheduleRowMapper(), id);
        } else {
            throw new IllegalArgumentException("선택한 일정은 존재하지 않습니다.");
        }
    }

    @GetMapping("/schedule/find")
    public List<ScheduleResponseDTO> findDateTimeName(@RequestParam(required = false) String dateTime, @RequestParam(required = false)String name) {
        String sql ="";
        if (dateTime != null && name != null) {
            sql = "SELECT * FROM schedule WHERE dateTime LIKE ? AND name = ? ORDER BY dateTime DESC";
            dateTime = dateTime + "%";
            return jdbcTemplate.query(sql, scheduleRowMapper(), dateTime, name);
        } else if (dateTime != null && name == null) {
            sql = "SELECT * FROM schedule WHERE dateTime LIKE ? ORDER BY dateTime DESC";
            dateTime = dateTime + "%";
            return jdbcTemplate.query(sql, scheduleRowMapper(), dateTime);
        } else if (dateTime == null && name != null) {
            sql = "SELECT * FROM schedule WHERE name = ? ORDER BY dateTime DESC";
            return jdbcTemplate.query(sql, scheduleRowMapper(), name);
        } else {
            throw new IllegalArgumentException("Param을 작성해주세요.");
        }
    }
    @PutMapping("/schedule/update")
    public ScheduleResponseDTO updateSchedule(@RequestBody ScheduleRequestDTO requestDTO) {
        // 해당 메모가 DB에 존재하는지 확인
        Schedule schedule = findById(requestDTO.getId());
        if(schedule != null) {
            if (schedule.getPassword().equals(requestDTO.getPassword())) {
                // schedule 내용 수정
                String sql = "UPDATE schedule SET name = ?, toDo = ?, dateTime = ? WHERE id = ?";
                jdbcTemplate.update(sql, requestDTO.getName(), requestDTO.getToDo(), String.valueOf(LocalDateTime.now()), requestDTO.getId());

                sql = "SELECT * FROM schedule WHERE id = ?";
                return jdbcTemplate.queryForObject(sql, scheduleRowMapper(), requestDTO.getId());
            } else {
                throw new IllegalArgumentException("비밀번호가 일치하지 않습니다.");
            }
        } else {
            throw new IllegalArgumentException("선택한 일정은 존재하지 않습니다.");
        }
    }

    @DeleteMapping("/schedule/delete")
    public String deleteSchedule(@RequestBody ScheduleRequestDTO requestDTO) {
        // 해당 schedule이 DB에 존재하는지 확인
        Schedule schedule = findById(requestDTO.getId());
        if(schedule != null) {
            if (schedule.getPassword().equals(requestDTO.getPassword())) {
                // memo 삭제
                String sql = "DELETE FROM schedule WHERE id = ?";
                jdbcTemplate.update(sql, requestDTO.getId());

                return "일정 삭제 완료";
            } else {
                throw new IllegalArgumentException("비밀번호가 일치하지 않습니다");
            }
        } else {
            throw new IllegalArgumentException("선택한 일정은 존재하지 않습니다.");
        }
    }

    private Schedule findById(Long id) {
        // DB 조회
        String sql = "SELECT * FROM schedule WHERE id = ?";

        return jdbcTemplate.query(sql, resultSet -> {
            if(resultSet.next()) {
                Schedule schedule = new Schedule();
                schedule.setToDo(resultSet.getString("toDo"));
                schedule.setName(resultSet.getString("name"));
                schedule.setPassword(resultSet.getString("password"));
                schedule.setDateTime(resultSet.getString("dateTime"));
                return schedule;
            } else {
                return null;
            }
        }, id);
    }
    private RowMapper<ScheduleResponseDTO> scheduleRowMapper() {
        return((rs, rowNum) -> {
            // SQL 의 결과로 받아온 schedule 데이터들을 ScheduleResponseDTO 타입으로 변환해줄 메서드
            Long id = rs.getLong("id");
            String toDo = rs.getString("toDo");
            String name = rs.getString("name");
            String password = rs.getString("password");
            String dateTime = rs.getString("dateTime");
            return new ScheduleResponseDTO(id, toDo, name, password, dateTime);
        });
    }
}

회고

  • 주석 아직도 잘 안달아둠
    > 먼저 주석으로 작업할 기능들 작성해두고 코드작성하자
  • 3 Layer Architecture 계층분리 안함
    > 더 시간들여 공부하자
  • 주어진 조건을 제대로 안읽어서 뜯어고치느라 오래걸림
    > 설계할때 제대로 조건을 꼼꼼히 읽고 작업하자

https://github.com/ironshine/ScheduleJdbc

0개의 댓글