๐ฅ๏ธ ๋ฐฑ์๋/SpringBoot
[API] API ๊ณ ๊ธ ์ค๊ณ - ์ง์ฐ ๋ก๋ฉ๊ณผ ์กฐํ ์ฑ๋ฅ ์ต์ ํ
OR15A
2023. 11. 28. 10:47
โ ์ํฐํฐ ์ง์ ๋ ธ์ถ
@GetMapping("/api/v1/orders")
public List<Order> ordersV1() {
List<Order> all = orderRepository.findAll();
for (Order order : all) {
order.getMember().getName(); //Lazy ๊ฐ์ ์ด๊ธฐํ
order.getDelivery().getAddress(); //Lazy ๊ฐ์ ์ด๊ธฐํ
List<OrderItem> orderItems = order.getOrderItems();
orderItems.stream().forEach(o -> o.getItem().getName()); //Lazy ๊ฐ์ ์ด๊ธฐํ
}
return all;
}
- order member ์ order address ๋ ์ง์ฐ ๋ก๋ฉ์ด๋ค. ๋ฐ๋ผ์ ์ค์ ์ํฐํฐ ๋์ ์ ํ๋ก์ ์กด์ฌ
- jackson ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ด ํ๋ก์ ๊ฐ์ฒด๋ฅผ json์ผ๋ก ์ด๋ป๊ฒ ์์ฑํด์ผ ํ๋์ง ๋ชจ๋ฆ ์์ธ ๋ฐ์
- [ํด๊ฒฐ๋ฐฉ์]
- Hibernate5Module ๋ชจ๋(์คํ๋ง ๋น) ๋ฑ๋ก, LAZY=null ์ฒ๋ฆฌ
- ์๋ฐฉํฅ ๊ด๊ณ ๋ฌธ์ ๋ฐ์ -> @JsonIgnore๋ก ํด๊ฒฐ
[ํ์ด๋ฒ๋ค์ดํธ ๋ชจ๋ ๋ฑ๋ก]
์คํ๋ง ๋ถํธ ๋ฒ์ ์ ๋ฐ๋ผ์ ๋ชจ๋ ๋ฑ๋ก ๋ฐฉ๋ฒ์ด ๋ค๋ฅด๋ค.
์คํ๋ง ๋ถํธ 3.0 ๋ถํฐ๋ javax -> jakarta ๋ก ๋ณ๊ฒฝ ๋์ด์ ์ง์ ๋ชจ๋๋ ๋ค๋ฅธ ๋ชจ๋์ ๋ฑ๋กํด์ผ ํ๋ค.
์คํ๋ง ๋ถํธ 3.0 ๋ฏธ๋ง: Hibernate5Module ๋ฑ๋ก build.gradle ์ ๋ค์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ์
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5' JpashopApplication ์ ๋ค์ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ ...(๋๋ณด๊ธฐ) P.15
โ ์ํฐํฐ๋ฅผ ์กฐํํด์ DTO๋ก ๋ณํ(fetch join ์ฌ์ฉX)
@GetMapping("/api/v2/orders")
public List<OrderDto> ordersV2() {
List<Order> orders = orderRepository.findAll();
List<OrderDto> result = orders.stream()
.map(o -> new OrderDto(o))
.collect(toList());
return result;
}
-
- ์ํฐํฐ๋ฅผ DTO๋ก ๋ณํํ๋ ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ์ด๋ค.
- ์ฟผ๋ฆฌ๊ฐ ์ด 1 + N + N๋ฒ ์คํ๋๋ค. (v1๊ณผ ์ฟผ๋ฆฌ์ ๊ฒฐ๊ณผ๋ ๊ฐ๋ค.)
- order ์กฐํ 1๋ฒ(order ์กฐํ ๊ฒฐ๊ณผ ์๊ฐ N์ด ๋๋ค.)
- order -> member ์ง์ฐ ๋ก๋ฉ ์กฐํ N ๋ฒ
- order -> delivery ์ง์ฐ ๋ก๋ฉ ์กฐํ N ๋ฒ
- ์) order์ ๊ฒฐ๊ณผ๊ฐ 4๊ฐ๋ฉด ์ต์
์ ๊ฒฝ์ฐ 1 + 4 + 4๋ฒ ์คํ๋๋ค.(์ต์
์ ๊ฒฝ์ฐ)
- ์ง์ฐ๋ก๋ฉ์ ์์์ฑ ์ปจํ ์คํธ์์ ์กฐํํ๋ฏ๋ก, ์ด๋ฏธ ์กฐํ๋ ๊ฒฝ์ฐ ์ฟผ๋ฆฌ๋ฅผ ์๋ตํ๋ค.
//OrderSimpleApiController - ์ถ๊ฐ
@Data
static class SimpleOrderDto {
private Long orderId;
private String name;
private LocalDateTime orderDate; //์ฃผ๋ฌธ์๊ฐ
private OrderStatus orderStatus;
private Address address;
/* public SimpleOrderDto(Order order) {
orderId = order.getId();
name = order.getMember().getName();
orderDate = order.getOrderDate();
orderStatus = order.getStatus();
address = order.getDelivery().getAddress();
}*/
public SimpleOrderDto(Long orderId, String name, LocalDateTime orderDate,
OrderStatus orderStatus, Address address) {
this.orderId = orderId;
this.name = name;
this.orderDate = orderDate;
this.orderStatus = orderStatus;
this.address = address;
}
}
โ ์ํฐํฐ๋ฅผ ์กฐํํด์ DTO๋ก ๋ณํ(fetch join ์ฌ์ฉO)
@GetMapping("/api/v3/orders")
public List<OrderDto> ordersV3() {
List<Order> orders = orderRepository.findAllWithItem();
List<OrderDto> result = orders.stream()
.map(o -> new OrderDto(o))
.collect(toList());
return result;
}
- ์ํฐํฐ๋ฅผ ํ์น ์กฐ์ธ(fetch join)์ ์ฌ์ฉํด์ ์ฟผ๋ฆฌ 1๋ฒ์ ์กฐํ
- ํ์น ์กฐ์ธ์ผ๋ก order -> member , order -> delivery ๋ ์ด๋ฏธ ์กฐํ ๋ ์ํ ์ด๋ฏ๋ก ์ง์ฐ๋ก๋ฉX
- ์ค๋ฌด์์ ๋ฌด์กฐ๊ฑด fetch์กฐ์ธ ์ฌ์ฉํ๊ธฐ
- ์ฌ๋ฌ ํ ์ด๋ธ์ ์ฐ๊ฒฐํ ๊ธด ๋ก์ฐ๋ฅผ ์ฐพ๊ฒ๋๋๋ฐ JPA๊ฐ ์ ์ ํ ์๋ผ์ค(๋ค์ ๋จ๊ณ์์ ์ด๋ถ๋ถ ์ต์ ํ)
//OrderRepository - ์ถ๊ฐ ์ฝ๋
public List<Order> findAllWithMemberDelivery() {
return em.createQuery(
"select o from Order o" +
" join fetch o.member m" +
" join fetch o.delivery d", Order.class)
.getResultList();
}
โ JPA์์ DTO๋ก ๋ฐ๋ก ์กฐํ
@GetMapping("/api/v4/orders")
public List<OrderQueryDto> ordersV4() {
return orderQueryRepository.findOrderQueryDtos();
}
- ์ํ๋ ๊ฒ๋ง selectํด์ด
- ์ผ๋ฐ์ ์ธ SQL์ ์ฌ์ฉํ ๋ ์ฒ๋ผ ์ํ๋ ๊ฐ์ ์ ํํด์ ์กฐํ
- new ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํด์ JPQL์ ๊ฒฐ๊ณผ๋ฅผ DTO๋ก ์ฆ์ ๋ณํ
- SELECT ์ ์์ ์ํ๋ ๋ฐ์ดํฐ๋ฅผ ์ง์ ์ ํํ๋ฏ๋ก DB ์ ํ๋ฆฌ์ผ์ด์
๋คํธ์ ์ฉ๋ ์ต์ ํ(์๊ฐ๋ณด๋ค ๋ฏธ
๋น) - ๋ฆฌํฌ์งํ ๋ฆฌ ์ฌ์ฌ์ฉ์ฑ ๋จ์ด์ง, API ์คํ์ ๋ง์ถ ์ฝ๋๊ฐ ๋ฆฌํฌ์งํ ๋ฆฌ์ ๋ค์ด๊ฐ๋ ๋จ์
//OrderSimpleQueryRepository ์กฐํ ์ ์ฉ ๋ฆฌํฌ์งํ ๋ฆฌ
@Repository
@RequiredArgsConstructor
public class OrderSimpleQueryRepository {
private final EntityManager em;
public List<OrderSimpleQueryDto> findOrderDtos() {
return em.createQuery(
"select new
jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto(o.id, m.name,
o.orderDate, o.status, d.address)" +
" from Order o" +
" join o.member m" +
" join o.delivery d", OrderSimpleQueryDto.class)
.getResultList();
}
}
V3์ V4๋ ์ฐ์๋ฅผ ๊ฐ๋ฆด ์ ์์.
V4๊ฐ ๊ฐ๊ฒฐํ๊ฒ ๊ฐ์ ธ์ค์ง๋ง ์ฌ์ฌ์ฉ์ฑ์ด ๋จ์ด์ง
V3๋ ์ํฐํฐ๋ฅผ ์กฐํํ๊ธฐ ๋๋ฌธ์ ๋น์ฆ๋์ค ๋ก์ง์ ์จ์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ๊ฐ๋ฅV4๋ DTO์กฐํ์ด๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ ๋ณ๊ฒฝํ ์ ์์(์ํฐํฐ ์๋๋ฏ๋ก)
์ํฐํฐ๋ฅผ DTO๋ก ๋ณํํ๊ฑฐ๋, DTO๋ก ๋ฐ๋ก ์กฐํํ๋ ๋๊ฐ์ง ๋ฐฉ๋ฒ์ ๊ฐ๊ฐ ์ฅ๋จ์ ์ด ์๋ค. ๋์ค ์ํฉ์ ๋ฐ๋ผ ์ ๋ ๋์ ๋ฐฉ๋ฒ์ ์ ํํ๋ฉด ๋๋ค. ์ํฐํฐ๋ก ์กฐํํ๋ฉด ๋ฆฌํฌ์งํ ๋ฆฌ ์ฌ์ฌ์ฉ์ฑ๋ ์ข๊ณ , ๊ฐ๋ฐ๋ ๋จ์ํด์ง๋ค. ๋ฐ๋ผ ์ ๊ถ์ฅํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ๋ค
์ฟผ๋ฆฌ ๋ฐฉ์ ์ ํ ๊ถ์ฅ ์์
1. ์ฐ์ ์ํฐํฐ๋ฅผ DTO๋ก ๋ณํํ๋ ๋ฐฉ๋ฒ์ ์ ํํ๋ค.
2. ํ์ํ๋ฉด ํ์น ์กฐ์ธ์ผ๋ก ์ฑ๋ฅ์ ์ต์ ํ ํ๋ค. ๋๋ถ๋ถ์ ์ฑ๋ฅ ์ด์๊ฐ ํด๊ฒฐ๋๋ค.
3. ๊ทธ๋๋ ์๋๋ฉด DTO๋ก ์ง์ ์กฐํํ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ค.
4. ์ตํ์ ๋ฐฉ๋ฒ์ JPA๊ฐ ์ ๊ณตํ๋ ๋ค์ดํฐ๋ธ SQL์ด๋ ์คํ๋ง JDBC Template์ ์ฌ์ฉํด์ SQL์ ์ง์ ์ฌ ์ฉํ๋ค.