๐ก PURPOSE
๊ฐ์ธ ํ๋ก์ ํธ๋ฅผ ์งํํ๋ ค๊ณ ํ์ผ๋ ์ค์ค๋ก ์๊ฐํ๊ธฐ์ ์์ง api ์์ฑ์ ๋ํด ๋ง์ด ๋ถ์กฑํ ๊ฒ ๊ฐ์ ์ด๋์๋ถํฐ ์์ํด์ผํ ์ง ๋ชจ๋ฅด๊ฒ ์ด์ ์ผ๋จ jpa์ ๋ํ ๊ธฐ์ด์ ์ธ ์ง์์ ์๊ธฐ ์ํด ๊ณต๋ถํ ๊ฒ์ ๋ณต์ตํ ๊ฒธ ํฌ์คํ ํด๋ณด๊ฒ ๋ค.
๐ก STUDY LIST
# Subject 2 : Spring JPA๋ฅผ ํตํ CRUD ๊ตฌํํ๊ธฐ
1. ์ฌ์ฉ์ ์ธ์ฆ (31~35)
2. ์ฌ์ฉ์ ์ธ์ฆ (2) (36~42)
3. ์ฌ์ฉ์ ์ธ์ฆ ํ ํฐ ๋ฐํ (43~47)
4. ์ฌ์ฉ์ ๊ด๋ฆฌ (48~55)
5.์ฌ์ฉ์ ๊ด๋ฆฌ (2) ํต๊ณ (56~60)
๐ก CONTENTS
(31) ์ฌ์ฉ์ ๋ฑ๋ก์ ์ ๋ ฅ๊ฐ์ด ์ ํจํ์ง ์์ ๊ฒฝ์ฐ ์์ธ๋ฅผ ๋ฐ์์ํค๋ ๊ธฐ๋ฅ
- ์ ๋ ฅ๊ฐ ์ด๋ฉ์ผ(ID), ์ด๋ฆ, ๋น๋ฐ๋ฒํธ, ์ฐ๋ฝ์ฒ
- ์ฌ์ฉ์ ์ ์ ์๋ฌ ๋ชจ๋ธ์ ์ด์ฉํ์ฌ ์๋ฌ๋ฅผ ๋ฆฌํด
/*
user/dto/UserDto.java ์์ฑ
*/
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class UserDto {
@Email(message = "์ด๋ฉ์ผ ํ์์ ๋ง๊ฒ ์
๋ ฅํด ์ฃผ์ธ์.")
@NotBlank(message = "์ด๋ฉ์ผ์ ํ์ ํญ๋ชฉ ์
๋๋ค.")
private String email;
@NotBlank(message = "์ด๋ฆ์ ํ์ ํญ๋ชฉ ์
๋๋ค.")
private String userName;
@Size(min = 4, message = "๋น๋ฐ๋ฒํธ๋ 4์ ์ด์ ์
๋ ฅํด์ผ ํฉ๋๋ค.")
@NotBlank(message = "๋น๋ฐ๋ฒํธ๋ ํ์ ํญ๋ชฉ ์
๋๋ค.")
private String password;
@Size(max = 20, message = "์ฐ๋ฝ์ฒ๋ ์ต๋ 20์ ์ดํ๋ก ์
๋ ฅํด์ผ ํฉ๋๋ค.")
@NotBlank(message = "์ฐ๋ฝ์ฒ๋ ํ์ ํญ๋ชฉ ์
๋๋ค.")
private String phone;
}
/*
user/controller/UserController.java ์์ฑ
*/
@RestController
public class UserController {
@PostMapping("/api/user")
public ResponseEntity<?> addUser(@RequestBody @Valid UserDto userDto, Errors errors) {
List<ResponseError> responseErrorList = new ArrayList<>();
if (errors.hasErrors()) {
errors.getAllErrors().forEach((e) -> {
responseErrorList.add(ResponseError.of((FieldError) e));
});
return new ResponseEntity<>(responseErrorList, HttpStatus.BAD_REQUEST);
}
return ResponseEntity.ok().build();
}
}
(32) ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ ๋ ฅ๋ฐ์์ ์ ์ฅํ๋ API
- ์ ๋ ฅ๊ฐ : ์ด๋ฉ์ผ(์ ์ผํ ๊ฐ ํ์ธ), ์ด๋ฆ, ๋น๋ฐ๋ฒํธ, ์ฐ๋ฝ์ฒ, ๊ฐ์ ์ผ (ํ์ฌ์ผ์)
/*
user/entity/User.java ์์ฑ
*/
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column
private String email;
@Column
private String userName;
@Column
private String password;
@Column
private String phone;
@Column
private LocalDateTime regDate;
}
/*
user/repository/UserRepository.java ์์ฑ
*/
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
@RequiredArgsConstructor
@RestController
public class UserController {
private final UserRepository userRepository;
@PostMapping("/api/user")
public ResponseEntity<?> addUser(@RequestBody @Valid UserDto userDto, Errors errors) {
List<ResponseError> responseErrorList = new ArrayList<>();
if (errors.hasErrors()) {
errors.getAllErrors().forEach((e) -> {
responseErrorList.add(ResponseError.of((FieldError) e));
});
return new ResponseEntity<>(responseErrorList, HttpStatus.BAD_REQUEST);
}
User user = User.builder()
.email(userDto.getEmail())
.userName(userDto.getUserName())
.password(userDto.getPassword())
.phone(userDto.getPhone())
.regDate(LocalDateTime.now())
.build();
userRepository.save(user);
return ResponseEntity.ok().build();
}
}
(33) ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์์ ํ๋ API
- ์ฌ์ฉ์ ์ ๋ณด๊ฐ ์๋ ๊ฒฝ์ฐ UserNOtFoundException ๋ฐ์
- ์์ ์ ๋ณด๋ ์ฐ๋ฝ์ฒ๋ง ์์ ๊ฐ๋ฅ, ์์ ์ผ์๋ ํ์ฌ ๋ ์ง
- ์๋ฌ๋ฉ์์ง๋ "์ฌ์ฉ์ ์ ๋ณด๊ฐ ์์ต๋๋ค."
/*
user/dto/UserUpdateDto.java ์์ฑ
*/
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class UserDto {
@Size(max = 20, message = "์ฐ๋ฝ์ฒ๋ ์ต๋ 20์ ์ดํ๋ก ์
๋ ฅํด์ผ ํฉ๋๋ค.")
@NotBlank(message = "์ฐ๋ฝ์ฒ๋ ํ์ ํญ๋ชฉ ์
๋๋ค.")
private String phone;
}
/*
user/entity/User.java์ ์นผ๋ผ ์ถ๊ฐ
*/
@Column
private LocalDateTime regDate;
@RequiredArgsConstructor
@RestController
public class UserController {
private final UserRepository userRepository;
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<String> handlerUserNotFoundException(UserNotFoundException exception) {
return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
}
@PutMapping("/api/user/{id}")
public ResponseEntity<?> updateUser(@PathVariable Long id,
@RequestBody @Valid UserUpdateDto userUpdateDto, Errors errors) {
List<ResponseError> responseErrorList = new ArrayList<>();
if (errors.hasErrors()) {
errors.getAllErrors().forEach((e) -> {
responseErrorList.add(ResponseError.of((FieldError) e));
});
return new ResponseEntity<>(responseErrorList, HttpStatus.BAD_REQUEST);
}
User user = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("์ฌ์ฉ์ ์ ๋ณด๊ฐ ์์ต๋๋ค."));
user.setPhone(userUpdateDto.getPhone());
user.setUpdateDate(LocalDateTime.now());
userRepository.save(user);
return ResponseEntity.ok().build();
}
}
(34) ์ฌ์ฉ์ ์ ๋ณด ์กฐํ (๊ฐ์ ํ ์์ด๋์ ๋ํ)์ ๊ธฐ๋ฅ์ ์ํํ๋ API
- ๋ค๋ง ๋ณด์์ ๋น๋ฐ๋ฒํธ์ ๊ฐ์ ์ผ, ํ์์ ๋ณด ์์ ์ผ์ ๋ด๋ฆฌ์ง ์๋๋ค.
/*
user/dto/UserResponseDto.java ์์ฑ
*/
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class UserResponseDto {
private long id;
private String email;
private String userName;
private String phone;
public static UserResponseDto of(User user) {
return UserResponseDto.builder()
.id(user.getId())
.userName(user.getUserName())
.phone(user.getPhone())
.email(user.getEmail())
.build();
}
}
@RequiredArgsConstructor
@RestController
public class UserController {
private final UserRepository userRepository;
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<String> handlerUserNotFoundException(UserNotFoundException exception) {
return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
}
@GetMapping("/api/user/{id}")
public UserResponseDto getUser(@PathVariable Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("์ฌ์ฉ์ ์ ๋ณด๊ฐ ์์ต๋๋ค."));
UserResponseDto userResponseDto = UserResponseDto.of(user);
return userResponseDto;
}
}
(35) ๋ด๊ฐ ์์ฑํ ๊ณต์ง์ฌํญ ๋ชฉ๋ก์ ๋ํ API ์์ฑ
- ๋ค๋ง ๋ณด์์ ์ญ์ ์ผ๊ณผ ์ญ์ ์ ์์ด๋๋ ๋ด๋ฆฌ์ง ์์
- ์์ฑ์์ ๋ณด๋ฅผ ๋ชจ๋ ๋ด๋ฆฌ์ง ์๊ณ , ์์ฑ์์ ์์ด๋์ ์ด๋ฆ๋ง ๋ด๋ฆผ
/*
notice/entity/Notice.java์ ์นผ๋ผ ์ถ๊ฐ
*/
@JoinColumn
@ManyToOne
private User user;
/*
notice/repository/NoticeRepository.java์ ์ถ๊ฐ
*/
List<Notice> findByUser(User user);
/*
notice/dto/NoticeResponseDto.java ์์ฑ
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NoticeResponseDto {
private long id;
private long regUserId;
private String regUserName;
private String title;
private String contents;
private LocalDateTime regDate;
private LocalDateTime updateDate;
private int hits;
private int likes;
public static NoticeResponseDto of(Notice notice) {
return NoticeResponseDto.builder()
.id(notice.getId())
.title(notice.getTitle())
.contents(notice.getContents())
.regDate(notice.getRegDate())
.regUserId(notice.getUser().getId())
.regUserName(notice.getUser().getUserName())
.updateDate(notice.getUpdateDate())
.hits(notice.getHits())
.likes(notice.getLikes())
.build();
}
}
@RequiredArgsConstructor
@RestController
public class UserController {
private final UserRepository userRepository;
private final NoticeRepository noticeRepository;
@GetMapping("/api/user/{id}/notice")
public List<NoticeResponseDto> userNotice(@PathVariable Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("์ฌ์ฉ์ ์ ๋ณด๊ฐ ์์ต๋๋ค."));
List<Notice> noticeList = noticeRepository.findByUser(user);
List<NoticeResponseDto> noticeResponseDtoList = new ArrayList<>();
noticeList.stream().forEach((e) -> {
noticeResponseDtoList.add(NoticeResponseDto.of(e));
});
return noticeResponseDtoList;
}
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<String> handlerUserNotFoundException(UserNotFoundException exception) {
return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
}
]
(36) ์ฌ์ฉ์ ๋ฑ๋ก์ ์ด๋ฏธ ์กด์ฌํ๋ ์ด๋ฉ์ผ(์ ์ผ)์ธ ๊ฒฝ์ฐ ์์ธ๋ฅผ ๋ฐ์์ํค๋ API
- ๋์ผํ ์ด๋ฉ์ผ์ ๊ฐ์ ๋ ํ์์ ๋ณด๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ ExistEmailException
/*
exception/ExistsEmailException.java ์์ฑ
*/
public class UserNotFoundException extends RuntimeException{
public UserNotFoundException(String message) {
super(message);
}
}
/*
user/repository/UserRepository.java์ ์ถ๊ฐ
*/
int countByEmail(String email);
@RequiredArgsConstructor
@RestController
public class UserController {
private final UserRepository userRepository;
private final NoticeRepository noticeRepository;
@PostMapping("/api/user")
public ResponseEntity<?> addUser(@RequestBody @Valid UserDto userDto, Errors errors) {
List<ResponseError> responseErrorList = new ArrayList<>();
if (errors.hasErrors()) {
errors.getAllErrors().forEach((e) -> {
responseErrorList.add(ResponseError.of(e));
});
return new ResponseEntity<>(responseErrorList, HttpStatus.BAD_REQUEST);
}
if (userRepository.countByEmail(userDto.getEmail()) > 0) {
throw new ExistsEmailException("์ด๋ฏธ ์กด์ฌํ๋ ์ด๋ฉ์ผ์
๋๋ค.");
}
User user = User.builder()
.email(userDto.getEmail())
.userName(userDto.getUserName())
.phone(userDto.getPhone())
.password(userDto.getPassword())
.regDate(LocalDateTime.now())
.build();
userRepository.save(user);
return ResponseEntity.ok().build();
}
@ExceptionHandler(ExistsEmailException.class)
public ResponseEntity<String> handlerExistsEmailException(ExistsEmailException exception) {
return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
}
}
(37) ์ฌ์ฉ์ ๋น๋ฐ๋ฒํธ๋ฅผ ์์ ํ๋ API
- ์ด์ ๋น๋ฐ๋ฒํธ์ ์ผ์นํ๋ ๊ฒฝ์ฐ ์์
- ์ผ์นํ์ง ์๋๊ฒฝ์ฐ PasswordNotMatchExeption ๋ฐ์
- ๋ฐ์๋ฉ์์ง๋ "๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค."
/*
user/dto/UserPasswordDto.java ์์ฑ
*/
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class UserPasswordDto {
@NotBlank(message = "ํ์ฌ ๋น๋ฐ๋ฒํธ๋ ํ์ ํญ๋ชฉ ์
๋๋ค.")
private String password;
@Size(min = 4, max = 20, message = "์ ๊ท ๋น๋ฐ๋ฒํธ๋ 4-20์ฌ์ด์ ๊ธธ์ด๋ก ์
๋ ฅํด ์ฃผ์ธ์.")
@NotBlank(message = "์ ๊ท ๋น๋ฐ๋ฒํธ๋ ํ์ ํญ๋ชฉ ์
๋๋ค.")
private String newPassword;
}
/*
user/repository/UserRepository.java์ ์ถ๊ฐ
*/
Optional<User> findByIdAndPassword(Long id, String password);
/*
exception/UserNotFoundException.java ์์ฑ
*/
public class UserNotFoundException extends RuntimeException{
public UserNotFoundException(String message) {
super(message);
}
}
@RequiredArgsConstructor
@RestController
public class UserController {
private final UserRepository userRepository;
private final NoticeRepository noticeRepository;
@PatchMapping("/api/user/{id}/password")
public ResponseEntity<?> updateUserPassword(@PathVariable Long id, @RequestBody UserPasswordDto userPasswordDto, Errors errors) {
List<ResponseError> responseErrorList = new ArrayList<>();
if (errors.hasErrors()) {
errors.getAllErrors().forEach((e) -> {
responseErrorList.add(ResponseError.of(e));
});
return new ResponseEntity<>(responseErrorList, HttpStatus.BAD_REQUEST);
}
User user = userRepository.findByIdAndPassword(id, userPasswordDto.getPassword())
.orElseThrow(() -> new PasswordNotMatchException("๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค."));
user.setPassword(userPasswordDto.getNewPassword());
userRepository.save(user);
return ResponseEntity.ok().build();
}
@ExceptionHandler(PasswordNotMatchException.class)
public ResponseEntity<String> handlerPasswordNotMatchException(PasswordNotMatchException exception) {
return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
}
}
(38) ํ์๊ฐ์ ์ ๋น๋ฐ๋ฒํธ๋ฅผ ์ํธํํ์ฌ ์ ์ฅํ๋ API
@RequiredArgsConstructor
@RestController
public class UserController {
private final UserRepository userRepository;
private final NoticeRepository noticeRepository;
private String getEncryptPassword(String password) {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
return bCryptPasswordEncoder.encode(password);
}
@PostMapping("/api/user")
public ResponseEntity<?> addUser(@RequestBody @Valid UserDto userDto, Errors errors) {
List<ResponseError> responseErrorList = new ArrayList<>();
if (errors.hasErrors()) {
errors.getAllErrors().forEach((e) -> {
responseErrorList.add(ResponseError.of(e));
});
return new ResponseEntity<>(responseErrorList, HttpStatus.BAD_REQUEST);
}
if (userRepository.countByEmail(userDto.getEmail()) > 0) {
throw new ExistsEmailException("์ด๋ฏธ ์กด์ฌํ๋ ์ด๋ฉ์ผ์
๋๋ค.");
}
String encryptPassword = getEncryptPassword(userDto.getPassword());
User user = User.builder()
.email(userDto.getEmail())
.userName(userDto.getUserName())
.phone(userDto.getPhone())
.password(encryptPassword)
.regDate(LocalDateTime.now())
.build();
userRepository.save(user);
return ResponseEntity.ok().build();
}
}
(39) ์ฌ์ฉ์ ํ์ ํํด ๊ธฐ๋ฅ์ ๋ํ API
- ํ์์ ๋ณด๊ฐ ์กด์ฌํ์ง ์์ ๊ฒฝ์ฐ ์์ธ์ฒ๋ฆฌ
- ๋ง์ฝ, ํ์์ด ๊ฒ์ํ์ ๊ธ์ ์ด ๊ฒฝ์ฐ๋ ํ์์ญ์ ๊ฐ ๋์ง ์์
@RequiredArgsConstructor
@RestController
public class UserController {
private final UserRepository userRepository;
private final NoticeRepository noticeRepository;
@DeleteMapping("/api/user/{id}")
public ResponseEntity<?> deleteUser(@PathVariable Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("์ฌ์ฉ์ ์ ๋ณด๊ฐ ์์ต๋๋ค."));
try {
userRepository.delete(user);
} catch (DataIntegrityViolationException e) {
String message = "์ ์ฝ์กฐ๊ฑด์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์์ต๋๋ค.";
return new ResponseEntity<>(message, HttpStatus.BAD_REQUEST);
} catch (Exception e) {
String message = "ํ์ ํํด ์ค ๋ฌธ์ ๊ฐ ๋ฐ์ํ์์ต๋๋ค.";
return new ResponseEntity<>(message, HttpStatus.BAD_REQUEST);
}
return ResponseEntity.ok().build();
}
}
(40) ์ฌ์ฉ์ ์์ด๋(์ด๋ฉ์ผ)์ ์ฐพ๋ API
- ์ด๋ฆ๊ณผ ์ ํ๋ฒํธ์ ํด๋นํ๋ ์ด๋ฉ์ผ์ ์ฐพ๋๋ค.
๋๊ธ