JaeWon's Devlog
article thumbnail
반응형

Vue + SpringBoot + Mysql 를 이용한 Todo 구현(1) - 프로젝트 구성하기

Vue + SpringBoot + Mysql 를 이용한 Todo 구현(2) - 프로젝트 환경 설정하기

Vue + SpringBoot + Mysql 를 이용한 Todo 구현(3) - Todo API 개발하기(1)

Vue + SpringBoot + Mysql 를 이용한 Todo 구현(5) - Todo 화면 개발하기(1) - 컴포넌트 구성

Vue + SpringBoot + Mysql 를 이용한 Todo 구현(6) - Todo 화면 개발하기(2) - Vuex 적용

(끝) Vue + SpringBoot + Mysql 를 이용한 Todo 구현(7) - Todo 화면 개발하기(3) - 화면 개발


이전 글에 이어서 service와 controller를 개발하고 postman 을 통해서 확인해보도록 하겠습니다.


3. Service 개발하기

- Service 폴더를 생성 후 아래에 TodoService.class 를 생성합니다.

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class TodoService {

    private final TodoRepository todoRepository;

    // Todo 작성
    @Transactional
    public Long save(Todo todo){
        todoRepository.save(todo);

        return todo.getId();
    }

    // Todo 전체 조회
    public List<Todo> findTodos(boolean orderState){
        return todoRepository.findAll(orderState);
    }

    // Todo 단건 조회
    public Todo findOne(Long todoId){
        return todoRepository.findOne(todoId);
    }

    // Todo 완료 상태 수정
    @Transactional
    public void updateTodoComplted(Long id, boolean completed) {
        Todo todo = todoRepository.findOne(id);

        todo.setCompleted(completed);
    }

    // Todo 삭제(DB 업데이트)
    @Transactional
    public void updateTodoUseYn(Long id) {
        Todo todo = todoRepository.findOne(id);

        todo.setUseYn("N");
    }

    // Todo 전체 삭제(DB 업데이트)
    @Transactional
    public int updateTodoAllClear() {
        return todoRepository.updateTodoAllClear();
    }
}

- 기본적으로 해당 클레스에 @Transactional 어노테이션을 걸어두고, readonly=true 로 기본적으로 설정합니다.(기본적으로 읽기만 가능하게 설정하여 무분별한 insert,update,delete를 막는다)

- 영속성 컨텍스트 전략을 통해서, 단건 업데이트의 경우에는 단건 조회하여 해당 데이터를 조회 후에 해당 값을 변경하여 관리합니다.

스프링 컨테이너는 트랜잭션 범위의 영속성 컨텍스트 전략을 기본으로 사용한다.
서비스 클래스에서 @Transactional을 사용할 경우, 해당 코드 내의 메서드를 호출할 때 영속성 컨텍스트가 생긴다는 뜻이다.
영속성 컨텍스트는 트랜잭션 AOP가 트랜잭션을 시작할 때 생겨나고, 메서드가 종료되어 트랜잭션 AOP가 트랜잭션을 커밋할 경우 영속성 컨텍스트가 flush되면서 해당 내용이 반영되고, 이후 영속성 컨텍스트 역시 종료된다.

4. Controller 개발하기

- controller 폴더를 생성 후 아래에 TodoForm.class 를 생성합니다.

@Getter
@Setter
public class TodoForm {

    @NotEmpty(message = "내용은 필수입니다.")
    private String item;

    private String date;

    private boolean completed;

    private String time;
}

- TodoForm 은 Request(요청)시에 전달받은 파라미터를 관리하는 클래스입니다.

- 따로 Model에 있는 파일과 구분한 이유는 추후 API 스펙이 변경될 시 해당 파일만 변경하고, Model은 그대로 사용이 가능하여 유지보수 측면에서 좋기 때문입니다.(자세한 내용은 김영한님의 강의 참고)

- 다음은, TodoController.class 를 생성합니다.

@RestController
@RequiredArgsConstructor
@Slf4j
public class TodoController {

    private final TodoService todoService;

    // Todo 등록
    @PostMapping("/todos/save")
    public String createJsonTodo(@RequestBody @Valid TodoForm form, BindingResult bindingResult){
        log.info("Post : Todo Save");

        return validation(form, bindingResult);
    }

    // Todo 목록
    @GetMapping("/todos/{orderState}")
    public List<Todo> list(@PathVariable("orderState") Boolean orderState){
        log.info("Get : Todos List");

        return todoService.findTodos(orderState);
    }

    // Todo 완료 상태 업데이트
    @PutMapping("/todos/{id}")
    public String updateTodo(
            @PathVariable("id") Long id,
            @RequestBody UpdateTodoRequest request
    ){
        log.info("Put : Todo update");

        todoService.updateTodoComplted(id, request.isCompleted());

        Todo findTodo = todoService.findOne(id);

        if(request.isCompleted() == findTodo.isCompleted()){
            return "ok";
        } else {
            return "fail";
        }
    }

    // Todo 삭제(DB 업데이트)
    @PutMapping("/todos/delete/{id}")
    public String deleteTodo(
            @PathVariable("id") Long id
    ){
        log.info("Delete : Todo Delete");

        todoService.updateTodoUseYn(id);

        Todo findTodo = todoService.findOne(id);

        if(findTodo.getUseYn().equals("N")){
            return "ok";
        } else {
            return "fail";
        }
    }

    @PutMapping("/todos/clear")
    public String clearAllTodo(){
        log.info("Clear : Todo All Clear");

        int result = todoService.updateTodoAllClear();

        if(result > 0){
            return "ok";
        } else {
            return "fail";
        }
    }

    // 요청 파라미터 validation 체크
    private String validation(@Valid @RequestBody TodoForm form, BindingResult bindingResult) {

        if(bindingResult.hasErrors()){
            return "todo error";
        }

        Todo todo = new Todo();
        todo.setItem(form.getItem());
        todo.setCompleted(form.isCompleted());
        todo.setDate(form.getDate());
        todo.setTime(form.getTime());
        todo.setWriteDate(LocalDateTime.now());
        todo.setUpdateDate(LocalDateTime.now());

        todoService.save(todo);

        return "ok";
    }

    @Data
    static class UpdateTodoRequest{

        private Long id;
        @NotEmpty
        private boolean completed;

    }
}

- Restful API 형식으로 개발을 해보았습니다.

  • PostMapping
    - Insert(저장) 시 사용.
    - @RequestBody를 TodoForm으로 받아 Todo에 다시 세팅하여 저장.
  • GetMapping : Select(조회) 시 사용
    - @PathVariable를 사용하여 조회 ID를 전달받아 조회.
  • PutMapping : Update(수정) 시 사용
    - @PathVariable를 사용하여 조회 ID를 전달받아 조회 후 수정.

5. PostMan을 통해 검증하기

- API 개발이 완료되었으니, PostMan을 통해서 검증을 해보도록 하겠습니다.

  • 저장(localhost:8787/todos/save)

  • 목록 조회(localhost:8787/todos/true or localhost:8787/todos/false)

  • 수정(localhost:8787/todos/2)

- API 개발이 완료되었습니다. 다음 글에서는 FrontEnd(Vue) 프로젝트 개발을 해보도록 하겠습니다.


참고

- https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-JPA-%ED%99%9C%EC%9A%A9-1/dashboard

- https://kafcamus.tistory.com/30

반응형
profile

JaeWon's Devlog

@Wonol

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!