728x90
반응형
Java Persistence API의 개요
ORM(Object Relational Mapping)
- 객체를 관계형 데이터베이스에 있는 데이터와 자동으로 맵핑(연결)해주는 작업
- SQL 문장 자동으로 생성
- 객체 사용 ~> 데이터베이스의 데이터 다룰 수 있게 해주는 메커니즘
JPA(Java Persistence API)
- 자바 ORM 기술에 대한 API 표준 명세
- 자바 어플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스(규칙, 약속)
- EntityManager ~> CRUD 처리
Hibernate
- JPA의 구현체, 인터페이스를 직접 구현한 라이브러리
- 생산성, 유지보수, 비종속성
Spring Data JPA
- Spring Module
- JPA를 추상화한 Repository 인터페이스 제공
=> JDBC -> Hibernate -> JPA -> Spring Data JPA
JPA 사용을 위한 Dependency 추가와 Entity 설정
// pom.xml
// 이미 기존에 추가해둠
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
// application.yml
spring:
message:
basename: messages
datasource:
url: jdbc:h2:mem:testdb
username: sa
jpa:
hibernate:
ddl-auto: create-drop
show-sql: true
defer-datasource-initialization: true // hibernate 초기화 먼저
h2:
console:
enabled: true
settings:
web-allow-others: true
*spring security 잠시 주석 처리 => 인증 처리 계속해줘야 하기 때문
http://localhost:8088/h2-console 접속 -> Test Connection
Table Structure
create table user {
id integer not null,
join_date timestamp,
name varchar(255),
password varchar(255),
ssn varchar(20),
primary key(id)
}
-> 프로젝트 생성 시 DB 자동 생성
// User.java
@Data
@NoArgsConstructor // 추가, 디폴트 생성자
@AllArgsConstructor
@JsonIgnoreProperties(value = {"password", "ssn"})
@Schema(description = "사용자 상세 정보를 위한 도메인 객체")
@Entity // 추가
@Table(name = "users")
public class User {
@Schema(title = "사용자 ID", description = "사용자 ID는 자동 생성됩니다.")
@Id // 추가
@GeneratedValue // 추가
private Integer id;
생성된 것 확인
Spring Data JPA를 이용한 초기 데이터 생성
// resources -> data.sql
insert into users(id, join_date, name, password, ssn) values (90001, now(), 'User1', 'test111', '701010-1111111');
insert into users(id, join_date, name, password, ssn) values (90002, now(), 'User2', 'test222', '810283-1111111');
insert into users(id, join_date, name, password, ssn) values (90003, now(), 'User3', 'test333', '190293-1111111');
* spring security 문제
: /h2-console url 무인증 추가
// config -> SecurityConfig.java
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return ((web) -> web.ignoring().requestMatchers(new AntPathRequestMatcher("/h2-console/**")));
}
JPA Service 구현을 위한 Controller, Repository 생성
// repository -> UserRepository(interface)
package com.example.myrestfulservice.repository;
import com.example.myrestfulservice.bean.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
}
// controller -> UserJpaController
package com.example.myrestfulservice.controller;
import com.example.myrestfulservice.bean.User;
import com.example.myrestfulservice.repository.UserRepository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/jpa")
public class UserJpaController {
private UserRepository userRepository;
// 생성자 주입
public UserJpaController(UserRepository userRepository) {
this.userRepository = userRepository;
}
// /jpa/users
@GetMapping("/users")
public List<User> retrieveAllUsers() {
return userRepository.findAll();
}
}
JPA를 이용한 개별 사용자 상세 조회 - HTTP Get method
// UserController
// /jpa/users/{id}
@GetMapping("/users/{id}")
public ResponseEntity retrieveUser(@PathVariable int id) {
Optional<User> user = userRepository.findById(id);
if (!user.isPresent()) {
throw new UserNotFoundException("id-" + id);
}
EntityModel entityModel = EntityModel.of(user.get());
WebMvcLinkBuilder linTo = linkTo(methodOn(this.getClass()).retrieveAllUsers());
entityModel.add(linTo.withRel("all-users"));
return ResponseEntity.ok(entityModel);
}
JPA를 이용한 사용자 추가와 삭제 - HTTP POST/DELETE method
사용자 삭제
@DeleteMapping("/users/{id}")
public void deleteUser(@PathVariable int id) {
userRepository.deleteById(id);
}
// SecurityConfig.java
@Bean
protected SecurityFilterChain filterChain(HttpSecurity http,
HandlerMappingIntrospector introspector) throws Exception {
// csrf; cross-site request fogery
http.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
사용자 추가
// /jpa/users
@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
User savedUser = userRepository.save(user);
// CREATED
// /users/4
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(savedUser.getId())
.toUri();
return ResponseEntity.created(location).build();
}
게시물 관리를 위한 Post Entity 추가와 초기 데이터 생성
User : Posts -> 1 : N
// Post.java
package com.example.myrestfulservice.bean;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String description;
// 지연 로딩: post가 로딩되는 필요한 시점에 그때 그때 가져옴
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnore
private User user;
}
// User.java
@OneToMany(mappedBy = "user")
private List<Post> posts;
public User(Integer id, String name, Date joinDate, String password, String ssn) {
this.id = id;
this.name = name;
this.joinDate = joinDate;
this.password = password;
this.ssn = ssn;
}
// data.sql
insert into post(description, user_id) values ('My first post', 90001);
insert into post(description, user_id) values ('My second post', 90001);
게시물 조회를 위한 Post Entity와 User Entity와의 관계 설정
@GetMapping("/users/{id}/posts")
public List<Post> retrieveAllPostsByUser(@PathVariable int id) {
Optional<User> user = userRepository.findById(id);
if (!user.isPresent()) {
throw new UserNotFoundException("id-" + id);
}
return user.get().getPosts();
}
JPA를 이용한 새 게시물 추가 - HTTP POST Method
// PostRepository
package com.example.myrestfulservice.repository;
import com.example.myrestfulservice.bean.Post;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface PostRepository extends JpaRepository<Post, Integer> {
}
private PostRepository postRepository;
// 생성자 주입
public UserJpaController(UserRepository userRepository, PostRepository postRepository) {
this.userRepository = userRepository;
this.postRepository = postRepository;
}
@PostMapping("/users/{id}/posts")
public ResponseEntity<Post> createPost(@PathVariable int id, @RequestBody Post post) {
Optional<User> userOptional = userRepository.findById(id);
if (!userOptional.isPresent()) {
throw new UserNotFoundException("id-" + id);
}
User user = userOptional.get();
post.setUser(user);
postRepository.save(post);
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(post.getId())
.toUri();
return ResponseEntity.created(location).build();
}
728x90
반응형
'Spring | SpringBoot' 카테고리의 다른 글
스프링부트 개념정리(이론) (0) | 2024.04.29 |
---|---|
[Spring Boot 3.x 를 이용한 RESTful Web Services 개발] 섹션 6. RESTful API 설계 가이드 (0) | 2024.04.29 |
[Spring Boot 3.x 를 이용한 RESTful Web Services 개발] 섹션 4. Spring Boot API 사용 (0) | 2024.04.29 |
[Spring Boot 3.x 를 이용한 RESTful Web Services 개발] 섹션 3. RESTful Service 기능 확장 (0) | 2024.04.29 |
[Spring Boot 3.x 를 이용한 RESTful Web Services 개발] 섹션 2. User Service API 구현 (0) | 2024.04.29 |