January 07, 2021
IntelliJ
Spring boot 2.4.1
Gradle
๊ด๋ จ๋ชจ๋ : h2, spring-boot-starter-data-jpa
์ง๋ ํฌ์คํธ์์ ์ํฐํฐ๊น์ง๋ง ๋ง๋ค์๋ค. ์ฌ๊ธฐ์ CRUD ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ธฐ ์ํด์ ๋ ํ์งํ ๋ฆฌ๊ฐ ํ์ํ๋ค.
๊ฐ๋จํ๊ฒ ๋งํ์๋ฉด, ๋ง๋ค๊ณ ์ ํ๋ ํ ์ด๋ธ ํ๋๋น ์ํฐํฐ ํด๋์ค ํ๋์ ๋ ํ์งํ ๋ฆฌ ํด๋์ค ํ๋๊ฐ ํ์ํ๋ค.
๊ทธ๋ฆฌ๊ณ ์ด ๋ชจ๋๋ฅผ ์ปจํธ๋กคํ ์ปจํธ๋กค๋ฌ๋ฅผ ํ๋ ๋ง๋ค์ด์ผํ๋ค.
๋จผ์ UserJpaController
๋ผ๋ ์ปจํธ๋กค๋ฌ ํด๋์ค๋ฅผ ๋ง๋ค์๋ค. ์ด๊ฒ ๊ธฐ๋ณธ ํ์ด๋ค.
@RestController
@RequestMapping("/jpa")
public class UserJpaController {
@Autowired
private UserRepository userRepository;
}
๊ทธ๋ฆฌ๊ณ ์ํฐํฐ์ธ User
ํด๋์ค๋ ์๋์ ๊ฐ์ด ์์ฑํ๋ค.
@Table
๋ก ํ
์ด๋ธ ์ด๋ฆ์ ์ค์ ํ ์ ์๋ค.
@Entity
๋ก ์ํฐํฐ ์ ์ธ์ ํด์ค๋ค.
@Id
๋ก ๊ธฐ๋ณธํค๋ฅผ ์ค์ ํ๋ค.
@Data
@NoArgsConstructor
@Table(name = "User_list")
@Entity
public class User {
@Id
private Integer id;
private String name;
private Date joinDate;
private String password;
private String ssn;
}
์ฌ์ ์์ ์์ ์ปจํธ๋กค๋ฌ์ User ์ํฐํฐ๋ฅผ ๋ง๋ค์์ผ๋ฏ๋ก ๋ ํ์งํ ๋ฆฌ๋ง ๋ง๋ค์ด์ฃผ๊ณ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ฝ์ด์ค๋ ๋ฉ์๋๋ฅผ ์ปจํธ๋กค๋ฌ์ ์ถ๊ฐํ์.
๋จผ์ UserRepository
์ด๋ค. JpaRepository
์ ๋ค์ด๊ฐ๋ณด๋ฉด ์ฌ์ฉํ ์ ์๋ ๋ฉ์๋๋ค์ด ๋์์๋ค. ์ฌ๊ธฐ ์๋ ๋ฉ์๋๋ฅผ ๊ฐ์ ธ๋ค๊ฐ ์ฌ์ฉํ ์๋ ์๊ณ , UserRepository
์์์ SQL๋ฌธ์ ์ฌ์ฉํ์ฌ ์ปค์คํ
๋ ๊ฐ๋ฅํ๋ค.
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
}
๋ชจ๋ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ฝ์ด์ค๊ธฐ ๋๋ฌธ์ retrieveAllUsers()
์์findAll()
๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ค.
public class UserJpaController {
...
@GetMapping("/users")
public List<User> retrieveAllUsers(){
return userRepository.findAll();
}
}
์คํํด๋ณด๋ฉด ๋ฐ์ดํฐ๋ฅผ ์ ์์ ์ผ๋ก ์ฝ์ด์จ๋ค.
UserJpaController
์ ํน์ ID๋ง ๊ฒ์ํ๋ ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ค. ์์ Optional์ ์ฌ์ฉํด์ผ ํ๋๋ฐ, ์์๋ ๋ฉ์๋๋ฅผ ํ๊ณ ์ฌ๋ผ๊ฐ์ findById()๋ฅผ ์ฐพ์๋ณด๋ฉด, ํ๋์ ID๋ฅผ ๊ฒ์ํ ๋ ๋ฐํ๊ฐ์ด Optional์ด๊ธฐ ๋๋ฌธ์ด๋ค.
@RestController
@RequestMapping("/jpa")
public class UserJpaController {
...
@GetMapping("/users/{id}")
public User retrieveUser(@PathVariable int id){
Optional<User> user = userRepository.findById(id);
return user.get();
}
}
์ด๋ ๊ฒ๋ง ํด๋ ๊ฒ์์ ์ ๋๋ค.
์ ์ฝ๋์๋ค๊ฐ ์ง๋๋ฒ์ ๊ตฌํํ hateoas์ id๊ฐ ์์ ๋ ๋ฐ์ํ ์๋ฌ๋ฉ์ธ์ง๋ฅผ ์ถ๊ฐํด์คฌ๋ค.
@RestController
@RequestMapping("/jpa")
public class UserJpaController {
...
@GetMapping("/users/{id}")
public EntityModel<User> retrieveUser(@PathVariable int id){
Optional<User> user = userRepository.findById(id);
if(!user.isPresent()){
throw new UserNotFoundException(String.format("User ID [%s} not found", id));
}
EntityModel<User> model = new EntityModel<>(user.get());
WebMvcLinkBuilder linkTo = linkTo(methodOn(this.getClass()).retrieveAllUsers());
model.add(linkTo.withRel("all-user"));
return model;
}
}
์ด์ ํ์ดํผ๋ฏธ๋์ด ์ฒ๋ฆฌ๋ ๊ฐ๋ฅํ๊ณ , ์๋ฌ์ฒ๋ฆฌ๋ ๊ฐ๋ฅํด์ก๋ค.
์ญ์ ๋ ์ ๋ง ๊ฐ๋จํ๋ค. ๊ฐ์ ๋ฐ๋ก ๋ฆฌํดํ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฌผ๋ก ์ญ์ ๊ฐ ๋์๋ค๋ ๋ฉ์ธ์ง๋ฅผ ๋ฆฌํดํ๋๋ก ๊ตฌํํด๋ ๋๋ค.
๋ค์๊ณผ ๊ฐ์ด UserJpaController
์ delete ๋ฉ์๋๋ฅผ ์ถ๊ฐํด์ค๋ค.
@RestController
@RequestMapping("/jpa")
public class UserJpaController {
...
@DeleteMapping("/users/{id}")
public void deleteUser(@PathVariable int id){
userRepository.deleteById(id);
}
}
์คํํด๋ณด์. ๋จผ์ ์ญ์ ํ๊ณ
์กฐํํด๋ณด๋ฉด id 1์ ์ญ์ ๋์ด์๋ค.
POST ๋ฉ์๋๋ ์ด์ง ๋ณต์กํ๋ค. ๋จผ์ ์ฝ๋๋ถํฐ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค. @valid
๋ ์ ํจ์ฑ ๊ฒ์ฌ๋๋ฌธ์ด์ง ์ฌ์ฉํ์ง ์์๋ ๋์๊ฐ๊ธดํ๋ค.
save()
๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ savedUser์ ๋ฐํ์ํค๊ณ ServletUriComponentsBuilder.fromCurrentRequest()
๋ฅผ ์ด์ฉํด์ ํ์ฌ ์์ฑ๋ id ๊ฐ์.path()
์ ๋ด๊ณ ์ด๋ฅผ ํค๋๊ฐ์ผ๋ก buildAndExpand()
์ ๋งคํํด์ ์ ๋ฌ์ํฌ ๊ฒ์ด๋ค. ์ด๋ฅผ URI ๋ฐ์ดํฐ ๊ฐ์ผ๋ก ๋ณํํ๋ค.
@RestController
@RequestMapping("/jpa")
public class UserJpaController {
...
@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody User user){
User savedUser = userRepository.save(user);
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(savedUser.getId())
.toUri();
return ResponseEntity.created(location).build();
}
}
๋ฐํ๊ฐ์ธ ResponseEntity
๋ฅผ ์กฐ๊ธ ๋ฏ์ด๋ณด๋ฉด, ํค๋์ ๋ฐ๋๋ก ์ด๋ฃจ์ด์ง ๊ฒ์ ๋ณผ ์ ์๋ค.
์ด๋ฅผ ์คํ์์ผ๋ณด์. ๋ฐ์ดํฐ์ ๋ํ POST์์ฒญ์ ๋ณด๋ด๊ณ ํ์ธํด๋ณด๋ฉด ์ถ๊ฐ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๊ฒ์ํ์ ๋ณด๋ฉด ํ๋์ ์ฌ์ฉ์๊ฐ ์ฌ๋ฌ ๊ฐ์ ๊ฒ์๋ฌผ์ ์์ ๊ถ์ ๊ฐ๋๋ค. ์ด๋ฅผ JPA๋ฐฉ์์ผ๋ก ํํํด๋ณด์.
๋จผ์ UserPost๋ผ๋ ์ํฐํฐ๋ฅผ ๋ง๋ค์ด์ฃผ์. ์ฌ๊ธฐ์ user ํ๋๋ฅผ ๋ณด๋ฉด ๋๊ฐ์ ์ ๋ํ ์ด์ ์ด ์ฌ์ฉ๋๋๋ฐ,
@ManyToOne
์ UserPost๋ฅผ ๋ค์, ๊ทธ๋ฆฌ๊ณ ๋ถ๋ชจ๋ก ์ฎ์ User ์ํฐํฐ๋ฅผ ํ๋๋ก ๋ณด๊ณ ๋งคํ์ํจ ๊ฒ์ด๋ค. ์ฆ User : UserPost = 1 : N ์ด ์ฑ๋ฆฝํ๋ค.
LAZY
๋ก ํญ์ UserPost์ user ํ๋๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ์ด ์๋๋ผ, ๋ถ๋ฌ์ฌ ๋๋ง ๊ฐ์ ธ์ค๋๋ก ์ ์ธํ๋ค.
@JsonIgnore
๋ฅผ ์ฌ์ฉํ์ฌ ๋
ธ์ถ๋์ง ์๊ฒ ๋ง๋ค์๋ค.
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserPost {
@Id
@GeneratedValue
private Integer id;
private String description;
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnore
private User user;
}
๊ทธ๋ฆฌ๊ณ ๊ธฐ์กด์ ์๋ User ํด๋์ค์ ์๋๋ฅผ ์ถ๊ฐํ๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก
@OneToMany
๋ก User ํด๋์ค๋ 1:N์์ 1์ ๋ช
์ํ ๊ฒ์ด๋ค. posts ํ๋์ ๋ค์๋ฅผ ์ ์ฅํ ์์ ์ด๋ List๋ก ์ ์ธํ๋ค.
public class User {
...
@OneToMany(mappedBy = "user")
private List<UserPost> posts;
}
๊ทธ๋ฆฌ๊ณ UserJpaController์ ์ ์ฒด ์ฌ์ฉ์์กฐํ ๋ฉ์๋์์ ์ด์ง๋ง ์์ ํ์ฌ ์กฐํ ๋ฉ์๋๋ฅผ ๋ง๋ค์ด์ค๋ค.
@RestController
@RequestMapping("/jpa")
public class UserJpaController {
...
@GetMapping("/users/{id}/posts")
public List<UserPost> retrieveAllPostsByUser(@PathVariable int id){
Optional<User> user = userRepository.findById(id);
if(!user.isPresent()){
throw new UserNotFoundException(String.format("User ID [%s} not found", id));
}
return user.get().getPosts();
}
}
์ด์ ํ ์คํธ๋ฅผ ์ํด ์คํํด๋ณด์. UserPost ์ํฐํฐ์ User id๊ฐ 1๋ฒ์ธ ์ฌ๋์ด ๊ฒ์๊ธ์ ์์ฑํ ๊ฒ์ฒ๋ผ ์์์ ๊ฐ์ ๋ฃ์๋ค.
insert into user_post values(1001, 'jeonghoon first post', 1);
insert into user_post values(1002, 'jeonghoon second post', 1);
ํฌ์คํธ๋งจ์ผ๋ก ์กฐํํด๋ณด๋ฉด ๊ธ์ด id์ ๋ง๊ฒ ์ข ์๋์ด ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค!
์ ์๋ํ๊ธด ํ๋๋ฐ ๋งค๋ฒ insert๋ก ๊ธ์ ์ธ ์ ์์ผ๋ ๊ธ ์์ฑํ๊ธฐ ์ํ POST ๋ฉ์๋๋ฅผ ๋ง์ง๋ง์ผ๋ก ๋ง๋ค์ด๋ณด์.
UserPost์ ๋ ํ์งํ ๋ฆฌ๊ฐ ์์ผ๋ POST๊ฐ ์ ๋ ๊ฒ์ด๋ค. ์ธํฐํ์ด์ค๋ก ๋ง๋ค์ด์ฃผ์. ๊ทธ๋ฆฌ๊ณ ์ปจํธ๋กค๋ฌ ์์
UserPostRepository
@Repository
public interface UserPostRepository extends JpaRepository<UserPost, Integer> {
}
์ปจํธ๋กค๋ฌ์์ ๋งค์ปค๋์ฆ์ ๋ค์๊ณผ ๊ฐ๋ค.
UserJpaController
@RestController
@RequestMapping("/jpa")
public class UserJpaController {
...
@Autowired
private UserPostRepository userPostRepository;
...
@PostMapping("/users/{id}/posts")
public ResponseEntity<UserPost> createUserPost(@PathVariable int id, @RequestBody UserPost userPost){
//์ฌ์ฉ์๋ฅผ ๋จผ์ ๊ฒ์ํจ. Get ๋ฉ์๋์์ ๊ธ์ด์๋ค.
Optional<User> user = userRepository.findById(id);
if(!user.isPresent()){
throw new UserNotFoundException(String.format("User ID [%s} not found", id));
}
userPost.setUser(user.get());
//๊ฒ์์ผ๋ก ์ฌ์ฉ์๋ฅผ ์ฐพ์ผ๋ฉด savedUserPost์ ๋๊ฒจ์ค๋ค. Post๋ฉ์๋์์ ๊ธ์ด์๋ค.
UserPost savedUserPost = userPostRepository.save(userPost);
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(savedUserPost.getId())
.toUri();
return ResponseEntity.created(location).build();
}
}
๋ ๊ฐ์ ๊ฒ์๋ฌผ์ ์์ฑํ๋ค.
์กฐํํด๋ณด๋ ์ ์์ ์ผ๋ก ์ถ๋ ฅ ๋์๋ค!