개인 포트폴리오/TodoList

TodoList 프로젝트 - Todo메인 API

roalwh 2023. 10. 18. 20:57

TodoList 웹 애플리케이션 - Todo메인 API

1. Todo메인 API

1-1. Entity

@Data 
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
// 데이터 베이스에 매핑
// Table을 추가하지 않거나 Entity에 이름을 지정 하지않은 경우 
// 자동으로 클래스의 이름을 테이블 이름으로 간주
@Table(name = "Todo")
public class TodoEntity {
    // 테이블의 기본키가 될 필드에 @Id 지정 
    // 커스텀 Generator 
    // id 자동생성
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid",strategy = "uuid")
    private String id; // 이 오브젝트의 아이디
    private String userId; // 이 오브젝트를 생성한 사용자의 아이디
    private String title; // Todo 타이틀(예: 운동하기)
    private boolean done; // true - todo를 완료한 경우(checked)
}
  • lombok 어노테이션을 사용함

  • @GenericGenerato로 커스텀Generator 생성,후 @GeneratedValue 를 이용하여 System-uuid를 활용한 Todo 글의 글 번호를 지정

1-2. Repository

@Repository
public interface TodoRepository extends JpaRepository<TodoEntity,String>{
    // select 
    // ?1은 메서드의 매개변수의 순서 위치다. 
    // @Query("select * from Todo t where t.userId=?1")
    //  findByUserId 스프링 데이터 JPA가 메서드 이름을 파싱해서
    //  SELECT * FROM TodoRepository WHERE userId = '{userId}'와 같은 쿼리를 작성해 실행
    //  메서드 이름은 쿼리, 매개변수는 쿼리의 where문에 들어갈 값을 의미
    List<TodoEntity> findByUserId(String userId);


}

1-3. Todo 생성 API

1) Controller

@RestController
@RequestMapping("todo")

public class TodoController {

    @Autowired
    private TodoService service; 

    // 등록
    @PostMapping
    public ResponseEntity<?> createTodo(@AuthenticationPrincipal String userId, @RequestBody TodoDTO dto) {
        try {
            // TodoEntity로 변환
            TodoEntity entity = TodoDTO.toEntity(dto);
            // id를 null로 초기화, 초기 생성시 id값이 없어야되기떄문
            entity.setId(null);
            // 로그인 없이 사용할 계정
            entity.setUserId(userId);
            // 서비스를 이용하여 Todo 엔티티 생성
            List<TodoEntity> entities = service.create(entity);
            // 자바 스트림을 이용하여 리턴된 엔티티를 TodoDTO 리스트로 변환
            List<TodoDTO> dtos = entities.stream().map(TodoDTO::new).collect(Collectors.toList());
            // 변환된 TodoDTO 리스트를 이용하여 ResponesDTO를 초기화
            ResponseDTO<TodoDTO> response = ResponseDTO.<TodoDTO>builder().data(dtos).build();
            // 초기화된 ResponesDTO를 리턴함
            return ResponseEntity.ok().body(response);
        } catch (Exception e) {
            // 예외가 있는경우 dto 대신 error 메시지를 넣어 리턴
            String error = e.getMessage();
            ResponseDTO<TodoDTO> response = ResponseDTO.<TodoDTO>builder().error(error).build();
            return ResponseEntity.badRequest().body(response);
        }
    }

2) Service

@Slf4j
@Service
public class TodoService {
    @Autowired
    private TodoRepository repository; 

    // Todo 생성 
    public List<TodoEntity> create(final TodoEntity entity) {
        // validations
        // 데이터를 검증
        validate(entity);
        // 데이터를 저장
        repository.save(entity);
        // 저장후 로그
        log.info("Entity Id : {} is saved.", entity.getId());

        return repository.findByUserId(entity.getUserId());
    }
    // 검증
    private void validate(final TodoEntity entity) {
        if (entity == null) {
            log.warn("Entity cannot be null.");
            throw new RuntimeException("Entity cannot be null.");
        }
        if (entity.getUserId() == null) {
            log.warn("Unknown user.");
            throw new RuntimeException("Unknown user.");
        }
    }

1-4. Todo 리스트 조회

1)Controller

    // 리스트 조회
    @GetMapping
    public ResponseEntity<?> retrieveTodoList(@AuthenticationPrincipal String userId) {
        // temporary user id
        // 서매스 메서드의 retrieve를 이용하여 Todo 리스트를 가져옴
        List<TodoEntity> entities = service.retrieve(userId);
        // 자바 스트림을 이용해 리턴된 엔티티 리스트를 TodoDTO 리스트로 변환
        List<TodoDTO> dtos = entities.stream().map(TodoDTO::new).collect(Collectors.toList());
        // 변환된 TodoDTO 리스트를 이용해 ResponseDTO를 초기화한다
        ResponseDTO<TodoDTO> response = ResponseDTO.<TodoDTO>builder().data(dtos).build();
        // ResponseDTO를 리턴
        return ResponseEntity.ok(response);
    }

2)Service

// Todo 리스트
    public List<TodoEntity> retrieve(final String userId){
        return repository.findByUserId(userId);
    }

1-5. Todo 수정

1)Controller

 /* post 로 json으로 값을 보낸후 생성된 값을 get으로 요청하여 리스트를 받는다. */
    // 수정
    @PutMapping
    public ResponseEntity<?> updateTodo(@AuthenticationPrincipal String userId, @RequestBody TodoDTO dto) {

        // dto를 entity로 변환 한다..
        TodoEntity entity = TodoDTO.toEntity(dto);
        // id를 temporaryUserId 로 초기화
        entity.setUserId(userId);
        // 서비스를 이용해 entity를 업데이트
        List<TodoEntity> entities = service.update(entity);
        // 자바 스트림을 통해 리턴된 엔ㄷ티티 리스트를 TodoDTO 리스트로 변환
        List<TodoDTO> dtos = entities.stream().map(TodoDTO::new).collect(Collectors.toList());
        // ResponseDTO 리스트를 이용하여 ResopnseDTO를 초기화
        ResponseDTO<TodoDTO> response = ResponseDTO.<TodoDTO>builder().data(dtos).build();
        // ResponseDTO 리턴
        return ResponseEntity.ok(response);
    }

2)Service

    // Todo 업데이트
    public List<TodoEntity> update(final TodoEntity entity){
        // 저장할 엔티티가 유효한지 확인
        validate(entity);
        // 검증된 엔티티 id 를 이용하여 TodoEntity를 가져옴
        final Optional<TodoEntity> original = repository.findById(entity.getId());
        // 반환된 TodoEntity가 존재하면 값을 새 entity 값으로 덮어 씌움
        if(original.isPresent()){
            final TodoEntity todo = original.get();
            todo.setTitle(entity.getTitle());
            todo.setDone(entity.isDone());
            // 데이터베이스에 새 값을 저장
            repository.save(todo);
        }
        // Retrieve Todo에서 만든 메서드를 이용하여 모든 Todo 리스트를 호출
        return retrieve(entity.getUserId());
    }

1-6. Todo 삭제

1)Controller

// 삭제
    @DeleteMapping
    public ResponseEntity<?> deleteTodo(@AuthenticationPrincipal String userId, @RequestBody TodoDTO dto) {
        try {
            // TodoEntity로 변환
            TodoEntity entity = TodoDTO.toEntity(dto);

            entity.setUserId(userId);
            // 서비스를 이용해 entity를 삭제
            List<TodoEntity> entities = service.delete(entity);
            // 자바 스트림을 이용해 리턴된 엔티티 리스트를 TodoDTO리스트로 변환한다
            List<TodoDTO> dtos = entities.stream().map(TodoDTO::new).collect(Collectors.toList());
            // 변환된 TOdoDTO 리스트를 이용해 ResponseDTO를 초기화 한다
            ResponseDTO<TodoDTO> response = ResponseDTO.<TodoDTO>builder().data(dtos).build();
            // ResponseDTO를 리턴
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            // 혹시 예외가 있는 경우 dto 대신 error에 메시지를 넣어 리턴한다
            String error = e.getMessage();
            ResponseDTO<TodoDTO> response = ResponseDTO.<TodoDTO>builder().error(error).build();
            return ResponseEntity.badRequest().body(response);
        }

    }

2)Service

    // Todo 삭제
    public List<TodoEntity> delete(final TodoEntity entity){
        // 저장할 엔티티가 유효한지 확인한다
        validate(entity);
        try{
            // 엔티티를 삭제함
            repository.delete(entity);
        } catch(Exception e){
            // exception 발생시 id와exception을 로깅
            log.error("error deleting entity", entity.getId(),e);
            //컨트롤러로 exception을 보낸다. 데이터베이스 내부 로직을 캡슐화하려면 e를 리턴하지 않고 새 exception 오브젝트를 리턴
            throw new RuntimeException("error deleting entity"+ entity.getId());
        }
        // 새 Todo리스트를 가져와 리턴
        return retrieve(entity.getUserId());
    }