Todo 리스트를 생성, 조회, 수정, 삭제할 수 있는 프로그램을 만들어보자.
- JDBC 사용
- DB를 연결해 지속적으로 데이터를 관리
- MVC 패턴에 추가적으로 Service Layer 와 Repository Layer 를 분리하여 유지보수와 확장성을 강화
0. API문서 작성
1. 일정 생성
할일, 작성자명, 비밀번호, 작성/수정일을 저장작성/수정일은 날짜와 시간을 모두 포함한 형태2. 전체 일정
3. 선택 일정 조회
4. 선택 일정 수정
할일, 작성자명 만 수정 가능비밀번호를 함께 전달합니다.작성일 은 변경할 수 없으며, 수정일 은 수정 완료 시, 수정한 시점으로 변경합니다.\5. 선택 일정 삭제
비밀번호를 함께 전달합니다.노션을 활용해서 작성했다.
각 기능별로 HttpMethod, URL, 요청&반환, 상태코드, 설명을 담았다.

각각이 맡고있는 기능을 확실하게 정리하고, 가독성을 높이기 위해
MVC 패턴을 기반으로 한 계층형 아키텍처(Layered Architecture) 패턴을 활용했다!

이렇게 하면 MVC 패턴에 추가적으로 Service Layer 와 Repository Layer 를 분리했기 때문에 유지보수와 확장성을 강화한 구조가 된다!
✅ 구조 정리
Controller: 사용자의 요청 받고 적절한 서비스 메서드 호출, 결과 응답으로 반환
→ @GetMapping, @PostMapping 등
Service: 컨트롤러에서 받은 요청을 처리
Repository: 데이터베이스와 상호작용하여 데이터 저장 & 조회
Entity: 데이터베이스의 테이블 구조를 정의
DTO: 클라이언트와 서버 사이에서 데이터를 주고받을 때
투두의 객체들을 정의하고 테이블을 만들어 관리하자
먼저 Spring DB에 todo 테이블을 만들었다.

id는 생성됨에 따라 자동으로 증가 - AUTO_INCREMENT
생성일과 업데이트 날짜가 자동으로 반영되어야하므로 CURRENT_TIMESTAMP
아까 만들었던 repository 패키지의 TodoRepository에 정의해주고 사용했다.
private final JdbcTemplate jdbcTemplate;
public JdbcTemplateTodoRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Getter
@AllArgsConstructor
public class Todo {
private String userName; //일정 등록한 사람 이름
private String password; //비번
private String todo; //할일 내용
@JsonFormat(pattern = "YYYY-MM-DD")
private Date doDate; //예정 날짜
private LocalDateTime createDate;
private LocalDateTime updateDate;
}
아까 DB에 정의했던 것처럼 객체들을 private로 정의해주고
@Getter @AllArgsConstructor로 Getter와 생성자를 자동 생성!
먼저 interface로 구조를 정의해주고
public interface TodoRepository {
void saveTodo(Todo todo);
}
이후에 Override해서 내부를 정의했다
@Repository
public class JdbcTemplateTodoRepository implements TodoRepository{
private final JdbcTemplate jdbcTemplate;
public JdbcTemplateTodoRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void saveTodo(Todo todo) {
String sql = "INSERT INTO todo (userName, password, todo, doDate, createDate, updateDate) VALUES (?,?,?,?,?,?) ";
jdbcTemplate.update(sql, todo.getUserName(), todo.getPassword(),
todo.getTodo(),todo.getDoDate(), todo.getCreateDate(), todo.getUpdateDate());
}
Todo의 getter를 사용해서 sql문을 만들고 jdbcTemplate를 활용해 update해주자!
[ RequestDto ]
@Getter
public class RequestDto {
private Long id;
private String userName; //일정 등록한 사람 이름
private String password; //비번
private String todo; //할일 내용
private Date doDate; //예정 날짜
private LocalDateTime createDate;
private LocalDateTime updateDate;
}
요청할 값들을 정의!
[ ResponseDto ]
@Getter
@AllArgsConstructor
public class ResponseDto {
private String userName; //일정 등록한 사람 이름
private String todo; //할일 내용
private Date doDate; //예정 날짜
private LocalDateTime createDate;
private LocalDateTime updateDate;
}
사용자에게 응답할(ResponseDto)를 정의한다.
사용자에게 노출할때는 비밀번호가 보이면 안되므로 pw를 제외하고 만든다.
serviceservie 패키지에 먼저 TodoService interface를 정의하고
public interface TodoService {
ResponseDto saveTodo(RequestDto dto);
}
TodoServiceImpl 클래스 파일에 implement해주자
@Service
public class ToDoServiceImpl implements TodoService{
private final TodoRepository todoRepository;
public ToDoServiceImpl(TodoRepository todoRepository) {
this.todoRepository = todoRepository;
}
@Override
public ResponseDto saveTodo(RequestDto dto) {
Todo todo = new Todo(dto.getUserName(), dto.getPassword(), dto.getTodo(), dto.getDoDate(), LocalDateTime.now(), LocalDateTime.now()); //투두 내역 받아서
todoRepository.saveTodo(todo); //레포지토리에 넘겨주자
return new ResponseDto(todo.getUserName(), dto.getTodo(), dto.getDoDate(), LocalDateTime.now(), LocalDateTime.now());
}
입력받은 todo의 내용들을 레포지토리에 전해주고,
response에도 저장스~
@RestController
@RequestMapping("/todos") //prefix
public class TodoController {
private final TodoService todoService;
public TodoController(TodoService todoService) { //생성자
this.todoService = todoService;
}
@PostMapping //투두 추가하는거니까 Post
public ResponseDto saveTodo(@RequestBody RequestDto dto){ //추가하라고 요청하기
return todoService.saveTodo(dto);
}
prefix url로 "/todos" 설정해주고
아까 만든 service를 가져온 후, savdTodo를 사용해주자
@RequestBody를 사용하면 요청 보내기 쌉가능이고 추가기능이니까 @PsotMapping 어노테이션을 사용하자
이렇게하면 포스트맨에서 잘 추가되는 모습을 확인할 수 있다!

마찬가지로 interface를 구현한 후 Override해준다
sql문을 작성하는데, 이때 비밀번호는 노출되면 안되므로 *이 아니라 직접 지정해준다
@Override
public List<ResponseDto> findAllTodo() {
String sql = "SELECT userName, todo, doDate, createDate, updateDate FROM todo";
return jdbcTemplate.query(sql, (rs, rowNum) ->
new ResponseDto(
rs.getString("userName"),
rs.getString("todo"),
rs.getDate("doDate"),
rs.getTimestamp("createDate").toLocalDateTime(),
rs.getTimestamp("updateDate").toLocalDateTime()
)
);
}
그리고 JdbcTemplate 의 query 를 사용해서 행별로 출력할 수 있도록 해주자(for문과 비슷하다~!)
service에서는 리스트로 받을 수 있도록 List<> 형태로 만들어주고 아까 레포에서 받은 것을 리턴해준다
@Override
public List<ResponseDto> findAllTodo() {
List<ResponseDto> allTodo = todoRepository.findAllTodo();
return allTodo;
}
마지막으로 컨트롤러에서 @GetMapping을 사용해 전체 일정을 가져와주면 완성!!
@GetMapping //전체 일정 가져오기
public List<ResponseDto> findAllTodo(){
return todoService.findAllTodo();
}
마찬가지로 레포에서 데이터 찾기 - 서비스에서 받아오기 - 컨트롤러가 실행할 수 있게 연결해주기 !!
@Override
public ResponseDto findOneTodo(Long id){
String sql = "SELECT * FROM todo WHERE id = ?";
return jdbcTemplate.queryForObject(sql, (rs, rowNum) ->
new ResponseDto(
rs.getString("userName"),
rs.getString("todo"),
rs.getDate("doDate"),
rs.getTimestamp("createDate").toLocalDateTime(),
rs.getTimestamp("updateDate").toLocalDateTime()
), id
);
}
id를 활용해서 찾아야하기 때문에 id를 인자로 넣어주자
여기서 위에 썼던 query queryForObject의 다른점은 다음과 같다
| query | queryForObject() |
|---|---|
| 여러 개의 결과(목록)를 조회할 때 사용 | 단일 결과(한 개의 행)를 조회할 때 사용 |
| 여러 개의 행을 리스트로 변환 | 결과가 반드시 하나여야 함 |
넘겨받자
@Override
public ResponseDto findTodoById(Long id) {
return todoRepository.findOneTodo(id);
}
마지막으로 사용자가 url을 통해 접근 가능하도록 GetMapping해주자
@PathVariable 어노테이션으로 알맞은 id 매칭하기
@GetMapping("/{id}") //선택 일정 가져오기
public ResponseDto findTodoById(@PathVariable Long id){
return todoService.findTodoById(id);
}
지금까지 데이터를 저장하고 조회하는 기능을 구현했다. 다음에는 수정하고 삭제해보자!