24.08.24

윤지현·2024년 8월 24일

TIL

목록 보기
49/75

오늘의 루틴

  • 개인과제 3단계 완료 및 4~5단계 시도 (O)
  • 강의 최소 4개는 듣기 (O)
  • 공부한 내용 복습 (O)

이번에는 3단계를 마무리 작업했다.

  • 5단계 : 유저 CRUD

🔻 조건

  • 유저를 저장, 단건 조회, 전체 조회, 수정, 삭제할 수 있습니다.
    • 유저는 유저명, 이메일, 작성일, 수정일 필드를 갖고 있습니다.
  • 일정은 이제 작성 유저명 필드 대신 유저 고유 식별자 필드를 가집니다.
  • 일정을 작성한 유저는 추가로 일정 담당 유저들을 배치할 수 있습니다.
    • 유저와 일정은 N:M 관계입니다. (@ManyToMany 사용 금지!)

유저를 관리하기 위해 User 엔티티를 생성하고 user와 todo테이블을 연관관계를 생성하기 위해 중간 테이블을 생성하기 위한 UserTodo 엔티티를 생성한다.


1. User.java

@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "user")
public class User extends Timestamped {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "username", nullable = false)
    private String username;

    @Column(name = "email", nullable = false)
    private String email;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<UserTodo> userTodos = new HashSet<>();

    public User(UserRequestDto requestDto) {
        this.username = requestDto.getUsername();
        this.email = requestDto.getEmail();
    }

    public void update(UserRequestDto requestDto) {
        this.username = requestDto.getUsername();
        this.email = requestDto.getEmail();
    }
}

2. UserTodo.java

@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "user_todo")
public class UserTodo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "todo_id")
    private Todo todo;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;
}

user 테이블에 대한 dto, 3 Layer Architecture를 만든다.


1. UserRequestDto.java

@Getter
public class UserRequestDto {
    private String username;
    private String email;
}

2. UserResponseDto.java

@Getter
public class UserResponseDto {
    private Long id;
    private String username;
    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime modifiedAt;

    public UserResponseDto(User user) {
        this.id = user.getId();
        this.username = user.getUsername();
        this.email = user.getEmail();
        this.createdAt = user.getCreatedAt();
        this.modifiedAt = user.getModifiedAt();
    }
}

3. UserController.java

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

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping("/user")
    public ResponseEntity<UserResponseDto> createUser(@RequestBody UserRequestDto userRequestDto) {
        return ResponseEntity.status(HttpStatus.CREATED).body(userService.createUser(userRequestDto));
    }

    @GetMapping("/user/{id}")
    public ResponseEntity<UserResponseDto> getUser(@PathVariable Long id) {
        return ResponseEntity.status(HttpStatus.OK).body(userService.getUser(id));
    }

    @GetMapping("/user")
    public ResponseEntity<List<UserResponseDto>> getAllUser() {
        return ResponseEntity.status(HttpStatus.OK).body(userService.getAllUser());
    }

    @PutMapping("/user/{id}")
    public ResponseEntity<UserResponseDto> updateUser(@PathVariable Long id, @RequestBody UserRequestDto userRequestDto) {
        return ResponseEntity.status(HttpStatus.OK).body(userService.updateUser(id, userRequestDto));
    }

    @DeleteMapping("/user/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
    }
}

4. UserService.java

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;

    @Transactional
    public UserResponseDto createUser(UserRequestDto userRequestDto) {
        User user = new User(userRequestDto);

        User newUser = userRepository.save(user);

        return new UserResponseDto(newUser);
    }

    public UserResponseDto getUser(Long id) {
        User user = findUser(id);

        return new UserResponseDto(user);
    }

    public List<UserResponseDto> getAllUser() {
        List<User> users = userRepository.findAll();
        return users.stream().map(UserResponseDto::new).collect(Collectors.toList());
    }

    @Transactional
    public UserResponseDto updateUser(Long id, UserRequestDto userRequestDto) {
        User user = findUser(id);

        user.update(userRequestDto);

        userRepository.save(user);

        return new UserResponseDto(user);
    }

    @Transactional
    public void deleteUser(Long id) {
        User user = findUser(id);

        userRepository.delete(user);
    }

    private User findUser(Long id) {
        return userRepository.findById(id).orElseThrow(() ->
                new IllegalArgumentException("선택한 유저가 존재하지 않습니다."));
    }
}

5. UserTodoRepository.java

public interface UserTodoRepository extends JpaRepository<UserTodo, Long> {
    void deleteByTodo(Todo todo);
    UserTodo findByTodoAndUser(Todo todo, User user);
}

user, todo와 연결하고 있는 user_todo 테이블에도 등록되기 위하여 repositroy를 만들고, todo와 관련된 코드도 수정한다.


1. Todo.java

Todo 엔티티에 추가

@OneToMany(mappedBy = "todo", cascade = CascadeType.REMOVE, orphanRemoval = true)
    private Set<UserTodo> userTodos = new HashSet<>();

2. TodoController.java

존재하는 일정에 담당 유저 추가하기 위한 메서드 생성

    @PostMapping("/todo/{id}/users")
    public ResponseEntity<TodoResponseDto> addUsersToTodo(@PathVariable Long id, @RequestBody Map<String, List<Long>> request) {
        List<Long> userIds = request.get("userIds");
        TodoResponseDto updatedTodo = todoService.addUsersToTodo(id, userIds);
        return ResponseEntity.ok(updatedTodo);
    }

3. TodoService.java

userTodoRepository에도 저장한다.

@Transactional
    public TodoResponseDto createTodo(TodoRequestDto requestDto) {
        // User Entity 조회
        User user = findUser(requestDto.getUserId());

        // RequestDto -> Entity
        Todo todo = new Todo(requestDto);

        // DB 저장
        Todo newTodo = todoRepository.save(todo);

        // UserTodo 관계 설정
        UserTodo userTodo = new UserTodo();
        userTodo.setTodo(newTodo);
        userTodo.setUser(user);
        userTodoRepository.save(userTodo);

        // 추가 담당 유저 설정
        for (Long additionalUserId : requestDto.getUserIds()) {
            User additionalUser = findUser(additionalUserId);
            UserTodo additionalUserTodo = new UserTodo();
            additionalUserTodo.setTodo(newTodo);
            additionalUserTodo.setUser(additionalUser);
            userTodoRepository.save(additionalUserTodo);
        }

        return new TodoResponseDto(newTodo);
    }

    @Transactional
    public TodoResponseDto addUsersToTodo(Long todoId, List<Long> userIds) {
        // 해당 일정 조회
        Todo todo = findTodo(todoId);

        // 추가 담당 유저 설정
        for (Long userId : userIds) {
            User user = findUser(userId);
            UserTodo userTodo = new UserTodo();
            userTodo.setTodo(todo);
            userTodo.setUser(user);

            // 중복된 담당 유저 추가 방지
            if (userTodoRepository.findByTodoAndUser(todo, user) == null) {
                userTodoRepository.save(userTodo);
            }
        }

        return new TodoResponseDto(findTodo(todoId));
    }

4. UserRequestDto.java

@Getter
public class UserRequestDto {
    private String username;
    private String email;
}

5. UserResponseDto.java

@Getter
public class UserResponseDto {
    private Long id;
    private String username;
    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime modifiedAt;

    public UserResponseDto(User user) {
        this.id = user.getId();
        this.username = user.getUsername();
        this.email = user.getEmail();
        this.createdAt = user.getCreatedAt();
        this.modifiedAt = user.getModifiedAt();
    }
}

잘 실행이 된다!

profile
첫 시작

0개의 댓글