목차
요구 사항
유저를 생성, 조회, 수정, 삭제할 수 있습니다.
유저는 아래와 같은 필드를 가집니다.
- ✅ 유저명, 이메일, 작성일 , 수정일 필드
- ✅ 작성일, 수정일 필드는 JPA Auditing을 활용합니다.
연관관계 구현
- ✅ 일정은 이제 작성 유저명 필드 대신 유저 고유 식별자 필드를 가집니다.
요구 구현
요구 사항의 추가에 따른 API 명세서, ERD 추가
요구 사항의 변경에 따른 API 명세서, ERD 수정
UserController
더보기
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping
public ResponseEntity<CreateUserResponseDto> createUser(@RequestBody @Valid CreateUserRequestDto requestDto) {
CreateUserResponseDto createUserResponseDto = userService.saveUser(requestDto);
return new ResponseEntity<>(createUserResponseDto, HttpStatus.CREATED);
}
@GetMapping("/{id}")
public ResponseEntity<FindUserResponseDto> findUser(@PathVariable Long id) {
FindUserResponseDto userResponseDto = userService.findUserById(id);
return new ResponseEntity<>(userResponseDto, HttpStatus.OK);
}
@PatchMapping("/{id}")
public ResponseEntity<UpdateUserResponseDto> updateUser(
@PathVariable Long id,
@RequestBody UpdateUserRequestDto requestDto
) {
UpdateUserResponseDto updateUserResponseDto = userService.updateUser(id, requestDto);
return new ResponseEntity<>(updateUserResponseDto,HttpStatus.OK);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return new ResponseEntity<>(HttpStatus.OK);
}
}
UserService
더보기
public interface UserService {
CreateUserResponseDto saveUser(CreateUserRequestDto requestDto);
FindUserResponseDto findUserById(Long id);
UpdateUserResponseDto updateUser(Long id, UpdateUserRequestDto requestDto);
void deleteUser (Long id);
}
UserServiceImpl
더보기
@Service
public class UserServiceImpl implements UserService{
private final UserRepository userRepository;
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public CreateUserResponseDto saveUser(CreateUserRequestDto requestDto) {
User user = new User(requestDto.getUsername(), requestDto.getEmail());
User savedUser = userRepository.save(user);
return new CreateUserResponseDto(savedUser);
}
@Override
public FindUserResponseDto findUserById(Long id) {
User user = userRepository.findByIdOrElseThrow(id);
return new FindUserResponseDto(user);
}
@Override
public UpdateUserResponseDto updateUser(Long id, UpdateUserRequestDto requestDto) {
User user = userRepository.findByIdOrElseThrow(id);
if (requestDto.getUsername() != null) {
user.updateUsername(requestDto.getUsername());
}
if (requestDto.getEmail() != null) {
user.updateEmail(requestDto.getEmail());
}
return new UpdateUserResponseDto(user);
}
@Override
public void deleteUser(Long id) {
User user = userRepository.findByIdOrElseThrow(id);
userRepository.delete(user);
}
}
UserRepository
더보기
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
default User findByIdOrElseThrow(Long id) {
return findById(id).orElseThrow(
() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Does not exist id = " + id)
);
}
}
User
더보기
@Getter
@Entity
@Table(name = "user")
public class User extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String username;
private String email;
public User(String username, String email) {
this.username = username;
this.email = email;
}
public User() {
}
public void updateUsername(String username) {
this.username = username;
}
public void updateEmail(String email) {
this.email = email;
}
}
CreateUserRequestDto
더보기
@Getter
@AllArgsConstructor
public class CreateUserRequestDto {
@NotNull
private final String username;
@Email(message = "이메일 형식이 올바르지 않습니다")
private final String email;
}
CreateUserResponseDto
더보기
@Getter
public class CreateUserResponseDto {
private final Long id;
private final String username;
private final String email;
private final Date createdAt;
private final Date updatedAt;
public CreateUserResponseDto(User user) {
this.id = user.getId();
this.username = user.getUsername();
this.email = user.getEmail();
this.createdAt = user.getCreatedAt();
this.updatedAt = user.getUpdatedAt();
}
}
FindUserResponseDto
더보기
@Getter
public class FindUserResponseDto {
private final Long id;
private final String username;
private final String email;
public FindUserResponseDto(User user) {
this.id = user.getId();
this.username = user.getUsername();
this.email = user.getEmail();
}
}
UpdateUserRequestDto
더보기
@Getter
@AllArgsConstructor
public class UpdateUserRequestDto {
@NotNull
private final String username;
@Email(message = "잘못된 이메일 형식입니다.")
private final String email;
}
UpdateUserResponseDto
더보기
@Getter
public class UpdateUserResponseDto {
private final Long id;
private final String name;
private final String email;
public UpdateUserResponseDto(User user) {
this.id = user.getId();
this.name = user.getUsername();
this.email = user.getEmail();
}
}
"✅ 일정은 이제 작성 유저명 필드 대신 유저 고유 식별자 필드를 가집니다."에 대한 코드 변경
더보기
CreateScheduleRequestDto
@Getter
@AllArgsConstructor
public class CreateScheduleRequestDto {
@NotNull
private Long userId;
private String title;
private String content;
@NotNull
private String password;
}
- 변경 내용 : String username -> `Long userId`
CreateScheduleResponseDto
@Getter
public class CreateScheduleResponseDto {
private final Long id;
private final String title;
private final Long userId;
private final String content;
private final Date createdAt;
private final Date updatedAt;
public CreateScheduleResponseDto(Schedule schedule) {
this.id = schedule.getId();
this.title = schedule.getTitle();
this.userId = schedule.getUserId();
this.content = schedule.getContent();
this.createdAt = schedule.getCreatedAt();
this.updatedAt = schedule.getUpdatedAt();
}
}
- 변경 내용 : String username -> `Long userId`
FindScheduleResponseDto
@Getter
public class FindScheduleResponseDto {
private final Long id;
private final String title;
private final Long userId;
private final String content;
private final Date createdAt;
private final Date updatedAt;
public FindScheduleResponseDto(Schedule schedule) {
this.id = schedule.getId();
this.title = schedule.getTitle();
this.userId = schedule.getUserId();
this.content = schedule.getContent();
this.createdAt = schedule.getCreatedAt();
this.updatedAt = schedule.getUpdatedAt();
}
}
- 변경 내용 : String username -> `Long userId`
- 변경 내용 : this.username = schedule.getUsername() -> `this.userId = schedule.getUserId()`
Schedule
@Entity
@Table(name = "schedule")
@Getter
public class Schedule extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Long userId;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String content;
@Column(nullable = false)
private String password;
public Schedule() {}
public Schedule(Long userId, String title, String content, String password) {
this.userId = userId;
this.title = title;
this.content = content;
this.password = password;
}
public Schedule(Long id, Long userId, String title, String content) {
this.id = id;
this.userId = userId;
this.title = title;
this.content = content;
}
...
}
- 변경 내용 : String username -> `Long userId`
- 변경 내용 : this.username = username -> `this.userId = userId`
@Service
public class ScheduleServiceImpl implements ScheduleService{
private final ScheduleRepository scheduleRepository;
public ScheduleServiceImpl(ScheduleRepository scheduleRepository) {
this.scheduleRepository = scheduleRepository;
}
public CreateScheduleResponseDto saveSchedule(CreateScheduleRequestDto requestDto) {
if (requestDto.getUserId() == null || requestDto.getTitle() == null || requestDto.getContent() == null || requestDto.getPassword() == null) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "There is no content.");
}
Schedule schedule = new Schedule(requestDto.getUserId(), requestDto.getTitle(), requestDto.getContent(), requestDto.getPassword());
Schedule savedSchedule = scheduleRepository.save(schedule);
return new CreateScheduleResponseDto(savedSchedule);
}
...
}
- 변경 내용 : requestDto.getUsername -> `requestDto.getUserId()`
회고
전체적인 방식은 이전부터 계속 진행해왔던 방식이기 때문에 큰 어려움은 없었으나, 요구사항 추가 및 변경에 따른 API 명세서, ERD, 프로그래밍 코드를 추가 및 수정한는 것에 많은 시간이 소요되는 것을 느꼈습니다. 실무에서도 잦은 요구사항 변경 및 정해지지 않은 요구사항 등에 대한 변수가 있는데, 미리 경험해볼 수 있었던 시간이었습니다.
'Project' 카테고리의 다른 글
[Project] Lv_4 스케줄 프로젝트(심화) (0) | 2025.05.21 |
---|---|
[Project] Lv_3 스케줄 프로젝트(심화) (0) | 2025.05.20 |
[Project] Lv_1 스케줄 프로젝트(심화) (0) | 2025.05.19 |
[Project] Lv_0 스케줄 프로젝트(심화) (0) | 2025.05.19 |
[Project] Lv_6 스케줄 프로젝트 (0) | 2025.05.13 |