월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
@Component를 InitDb에서 전역으로 해준 것 아닌가요?
@Component를 InitDb에서 전역으로 해준 것 아닌가요?다시 InitService에서 다시 @component를 해주는 이유가뭔지 궁금합니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
V2에서 별도의 DTO를 사용하는 이유가 궁금합니다.
안녕하세요 강사님!Entity를 바로사용 하지 않는 이유는보안에 취약여러 곳에서 사용하기 때문에 entity가 바뀌면 곤란함이 두가지 때문이라고 이해했는데.V2의 경우에는 별도의 DTO를 구성해서 이를 해결한다고 말씀을 해주셨습니다. 하지만 사용 쓰임새가 다 다르면 별도의 DTO를 계속해서 고쳐줘야 하는건 V1과 마찬가지 아닌가요? 보안 문제만 해결할 수 있는 것처럼 보이는데 원리를 이해하지 못하겠습니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
Spring 3.xx버전 querydsl gradle 설정 관련 질문
QueryDSL 소개 강의 영상에서 gradle 설정하는 부분을 3이상버전 관련해서 올려주신 자료를 보면서 따라했는데 build-clean을 하고 해봐도 tasks-others밑에 compileQuerydsl파일이 생성되 지않아서 comlile.java 를 눌렀더니 generated에 파일들은 잘 생성됐습니다. plugins { id 'java' id 'org.springframework.boot' version '3.1.5' id 'io.spring.dependency-management' version '1.1.3' } group = 'jpabook' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '17' } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-devtools' implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0' //Hibernate5JakartaModule 등록 (하이버네이트 모듈) implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5-jakarta' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' //QueryDsl 관련 추가 implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" annotationProcessor "jakarta.annotation:jakarta.annotation-api" annotationProcessor "jakarta.persistence:jakarta.persistence-api" } tasks.named('test') { useJUnitPlatform() } def querydslSrcDir = 'src/main/generated' clean { delete file(querydslSrcDir) } tasks.withType(JavaCompile) { options.generatedSourceOutputDirectory = file(querydslSrcDir) } 이렇게 작성했는데 혹시 틀린 부분이 있을까요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
샘플 데이터 입력시 OrderItem, Delivery를 persist()하지 않는 이유
확인 차원에서 질문드립니다. 샘플 데이터를 넣는 코드에서 member, book, order은 em.persist()를 통해 영속성 컨텍스트에 등록합니다.반면에 orderItem과 delivery는 따로 persist()를 하지 않습니다. 그 이유가 Order 엔티티 연관 관계에서 Cascasde 옵션을 했기 때문에, order 객체를 영속성 컨텍스트에 올려 놓는 순간, orderItem과 delivery 객체도 함께 등록되기 때문이라고 이해했습니다.제가 잘 이해했는지 궁금합니다.package jpabook.jpashop.domain; @Entity @Table(name = "orders") @Getter @Setter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Order { .... @OneToMany(mappedBy = "order", cascade = CascadeType.ALL) private List<OrderItem> orderItems = new ArrayList<>(); @OneToOne(fetch = LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "delivery_id") private Delivery delivery; .... } public void dbInit1() { Member member = createMember("userA", "서울", "1", "1111"); em.persist(member); Book book1 = createBook("JPA1 BOOK", 10000, 100); em.persist(book1); Book book2 = createBook("JPA2 BOOK", 20000, 100); em.persist(book2); OrderItem orderItem1 = OrderItem.createOrderItem(book1, 10000, 1); OrderItem orderItem2 = OrderItem.createOrderItem(book2, 20000, 2); Delivery delivery = createDelivery(member); Order order = Order.createOrder(member, delivery, orderItem1, orderItem2); em.persist(order); }
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
Response DTO VS HTTP Response
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하세요. 강의 잘 듣고 있습니다.강의 도중 궁금한 점이 생겨 질문드립니다. 강의에서는 POST나 PUT요청에서도 Response DTO 객체를 생성해서 전달하셨는데, 실제 실무에서도 이렇게 하는지 궁금합니다. 질문드린 이유는 HTTP Response code상 201이나 204 등의 응답코드가 있는 것으로 알고있는데, Response를 매번 생성하는게 실질적으로 좋은 설계이기 때문인지, 아니면 변경이 완료된 것을 실제로 조회하면서 이해를 돕기 위함인지 궁금했습니다. 감사합니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
v5의 쿼리 횟수에 대 질문이 있습니다.
public List<OrderQueryDto> findAllByDto_optimization() { List<OrderQueryDto> result = findOrders(); List<Long> orderIds = result.stream() .map(o -> o.getOrderId()) .collect(Collectors.toList()); List<OrderItemQueryDto> orderItems = em.createQuery( "select new jpabook.jpashop.repository.order.query.OrderItemQueryDto(oi.order.id, i.name, oi.orderPrice, oi.count)" + " from OrderItem oi" + " join oi.item i" + " where oi.order.id in :orderIds", OrderItemQueryDto.class) .setParameter("orderIds", orderIds) .getResultList(); //최적화(Lambda사용) Map<Long, List<OrderItemQueryDto>> orderItemMap = orderItems.stream() .collect(Collectors.groupingBy(orderItemQueryDto -> orderItemQueryDto.getOrderId())); result.forEach(o -> o.setOrderItems(orderItemMap.get(o.getOrderId()))); return result; } 여기서 map을 사용하는 코드가 있는 경우에는 쿼리를 한 번 날리고 map으로 가져와서 값을 세팅하기 때문에 쿼리가 총 2번 나가는 거고 그 부분이 없으면 어떤 방식으로 쿼리가 나가는 건가요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
트랜잭션의 시작을 모르겠습니다
강의를 듣다보니 Api를 사용하기 위해 만든 Controller에서는 @Transactional 어노테이션이 포함된 Service를 아예 사용 안해서 트랜잭션의 시작을 어디로 봐야 될지 모르겠어서요1.@Transactional 어노테이션을 달고있는 메서드의 시작이 트랜잭션의 시작이고,또한 em를 통해서 createQuery나 persist를 하는 것은 em코드가 포함된 메서드가 트랜잭션의 시작인건가요?2.그리고 컨트롤러는 컨트롤러에 남겨두고 내부 로직이 있으면 빼내서 클래스로 만들어서 @Transactional(readOnly = true)로 설정해서 컨트롤러에서 쓰면컨트롤러는 그대로 있고, 내부의 로직을 트랜잭션 어노테이션으로 묶는건가요? 3.2번이 맞게 이해한거면 ApiController에 있는 컨트롤러에 바로 @Transactional을 붙이면 OSIV를 꺼도 작동되는데이렇게 컨트롤러에 바로 붙이면 OSIV를 킨거와 같은 경우가 되는거 아닌가요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
static not allowed here에러
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 등록 API를 할 때까지는 static에 에러가 없었는데수정 API를 할 때에 static 부분 4군데에 다 해당 에러가 뜹니다.static이 있는 상태로는 해당 에러로 작동하지 않고static을 지우고 작동을 시키면 작동을 하고 포스트맨에서 수정도 가능합니다.여기서 궁금한 점은1. 왜 이런 상황이 발생하는 지2. static을 지우고 그냥 진행을 시켜도 문제가 없는지에 대해서 알고 싶습니다.
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
부분 업데이트시 PATCH vs POST
회원 수정 API 관련해서 강의 자료 오류 정정부분에 PUT은 전체 업데이트 시 사용하는 것이고, 부분 업데이트 할 때는 PATCH나 POST를 사용하는 것이 맞다고 나와있는데 실무에서는 PATCH나 POST중에 어떤 것을 더 많이 사용하나요? 개인 프로젝트시에 참고하고 싶어 질문드립니다!
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
@OneToMany 를 쓰는 이유??
생각해보니 양방향 연관관계를 써야 하는 근본적인 이유가 무엇이었나요? 예를 들면 member 와 team 이 다대일 이라면 ,team 에 @OneToMany 가 있을 텐데지금까지 강의에서 보았을떄는 그냥 주 Entity에서 @OneToMany 써서 연관관계 편의 메서드 만들어서 데이터 넣는 느낌? 이 다인 것같은데 근본적인 이유가 뭘까요. 이전 JPA 강의에서는 @OneToMany를 쓸때는 조회하는 것만 사용하라고 했었던 기억이 나는데 강의에서는 @OneToMany를 사용해서 조회해서 APi로 반환한다거나 그런 내용이 없었던 걸로 기억해요 . . .
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
Spring Boot 2.7.17 Java 11 버전 빌드 성공 한 build.gradle
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)아니오2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)예[질문 내용]빌드하다 머리털 빠질뻔해서 공유합니다plugins { id 'java' id 'org.springframework.boot' version '2.7.17' id 'io.spring.dependency-management' version '1.0.15.RELEASE'}group = 'jpabook'version = '0.0.1-SNAPSHOT'java { sourceCompatibility = '11'}ext["hibernate.version"] = "5.6.5.Final"configurations { compileOnly { extendsFrom annotationProcessor}}repositories { mavenCentral()}dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-devtools' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6' implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate5', version: '2.16.0' //Querydsl 추가 implementation 'com.querydsl:querydsl-jpa' annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa" annotationProcessor "jakarta.annotation:jakarta.annotation-api" annotationProcessor "jakarta.persistence:jakarta.persistence-api" compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok'}tasks.named('test') { useJUnitPlatform()}//Querydsl 추가, 자동 생성된 Q클래스 gradle clean으로 제거clean { delete file('src/main/generated')}
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
내부클래스 접근지정자
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]DTO 클래스를 내부클래스로 만들었는데, 접근지정자를 public으로 지정해주지 않으면 Class 'CreateMemberResponse' is exposed outside its defined visibility scopeClass 'CreateMemberRequest' is exposed outside its defined visibility scope 이런식으로 경고가 발생합니다.강의에서는 public으로 지정하지 않아도 경고창이 뜨지 않았는데 왜그런걸까요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
@JsonIgnore
@JsonIgnore의 위치는 양방향 연관관계 중 아무곳이나 적어줘도 되는 건가요??
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
JPA 순환참조 질문 드립니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. EventGroupInformation.java@NotFound(action = NotFoundAction.IGNORE)@JsonBackReference@ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)@JoinColumn(name="CATEGORY_ID", insertable = false, updatable = false)private CategoryInformation categoryInformation;@BatchSize(size = 1000)@JsonManagedReference@OneToMany(mappedBy = "eventGroupInformation", cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)@Where(clause = "DBSTS = 'O' AND FEED_DISPLAY_YN = 'Y' AND START_DATE <= SYSDATE AND END_DATE >= SYSDATE ")@Column(insertable = false, updatable = false)private List<EventInformation> eventInformations; CategoryInformation.java@BatchSize(size = 1000)@JsonManagedReference@OneToMany(mappedBy = "categoryInformation", fetch = FetchType.LAZY)@Where(clause = "DBSTS = 'O' AND START_DATE <= SYSDATE AND END_DATE >= SYSDATE ")@Column(insertable = false, updatable = false)//@Access(value = AccessType.PROPERTY)public List<EventGroupInformation> eventGroupInformations; 여러개의 oneToMany가 걸려 있는 entitiy들을 강의 V5예제를 참고하여 개선중에 있습니다.CategoryInformation(Order)ㄴ EventGroupInformation(OrderItem)ㄴ EventInformation(Item)이런 식에 구조인데요, 각각 oneToMany 입니다. EventGroupInformation과 EventInformation을 fetchJoin을 통해 쿼리를@Query(value = "SELECT distinct eg FROM EventGroupInformation eg " +"LEFT JOIN FETCH eg.eventInformations e " +"WHERE eg.dbsts = :dbsts " +"AND eg.categoryId IN :categoryIds" ) 호출하면 해당 fetchjoin 쿼리 하나만 나갈꺼라고 생각을했는데,갑자기 상위 entity인 CategoryInformation 테이블에 category_id(PK)로 category_id 개수만큼의N+1 이슈가 발생 하였습니다. JsonBackReference, JsonManagedReference 해당 옵션을 주면 역참조가 안되어야 하는게 맞지 않나요?? 추가로 ManyToOne 쪽에 @JsonIgnore 도 추가 해보았으나 마찬가지입니다 ㅠ제가 놓치고 있는게 있을까요? 김영한 선생님 강의 에서는OrderItem-Item 관계에서 IN쿼리를 호출했을때 IN절에 포함되는 orderId기준의 상위 엔티티인 Order 테이블에 역으로 쿼리가 나가는건 못봤는데 말이죠..(물론, 양방향 관계를 끊고 단방향 설정시 N+1 쿼리는 나가지 않습니다.)
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
메모리에 올린다에서 메모리가 영속성 컨텍스트 인가요?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예[질문 내용]메모리에 올린다는 내용이 등장하는데, getter로 조회해서 영속성 컨텍스트에 올려놓는 다는 뜻인가요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
1:N 계층구조 테이블들 간에 Fetch 조인 사용 질문 드립니다.
안녕하세요. 열심히 강의를 듣고 있는 수강생입니다!궁금한게 있습니다.현재 실무에서 사용하고 있는 구조를 좀더 개선시키고 싶어서 열심히 노력중인데요.현재 상황을 말씀 드리겠습니다.A, B, C, D 테이블이 있습니다.각 entitiy 클래스 별로 OneToMany로 A-B, B-C, C-D 이런식으로 Relation이 걸려 있습니다.현재 기준으로는 각 OneToMany 별로 BatchSize=1000 & FetchType=Eager로 적용이 되어있는데요.이렇다 보니, A 테이블 조회시 조회된 ID 기준으로 하위 테이블들에 대해서 IN쿼리가 몇개씩 불려지게 됩니다. 그래서 Fetch 조인을 통해서 한번에 가져오는 방식으로 바꿔보려고 개선을 하려고 했는데요.예를 들면select a.* from A aleft fetch join a.B bleft fetch join b.C cleft fecth join c.D d이런식으로 하려고했더니 컴파일 단계에서 MultipleBagFetchException이 발생 하였습니다.그래서 찾아보니 fecth 조인 사용할 경우에는 oneToMany로 걸리는 대상이 2개 이상이면위와같은 Exception을 떨군다고 하더라구요..(카티션 곱 이슈로 인한 하이버네이트에서 사전에 미리 막는..) 그래서 결국에는 A-B까지만 Fetch로 빼고 나머지 B-C, C-D는 기존 그대로 Eager 전략으로기존과 동일하게 조회되도록 조금이나마 개선은 했는데요..B-C, C-D를 lazy로 바꾸니 N+1이 발생했구요.. N+1해소 하는 방법으로 Fecth조인을 쓰자니위와같은 Exception이 발생을 하구요..어떻게 하면 좋을까요.. 도와주세요!
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
[질문X] orderV6 for문으로 발라내기
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]복붙 하려다 못참아서 그만.. ㅎㅎ @GetMapping("/api/v6/orders") public List<OrderQueryDto> ordersV6(){ List<OrderFlatDto> orderFlats = orderQueryRepository.findAllByDto_flat(); Map<Long, List<OrderItemQueryDto>> orderItemMap = new HashMap<>(); Map<Long, OrderQueryDto> orderMap = new HashMap<>(); orderFlats.forEach(orderFlat -> { Long orderId = orderFlat.getOrderId(); if(orderMap.get(orderId) == null){ orderMap.put(orderId,new OrderQueryDto(orderId, orderFlat.getName(), orderFlat.getOrderDate(), orderFlat.getOrderStatus(), orderFlat.getAddress())); } if(orderItemMap.get(orderId) == null){ orderItemMap.put(orderId,new ArrayList<OrderItemQueryDto>()); } orderItemMap.get(orderId).add(new OrderItemQueryDto(orderId, orderFlat.getItemName(), orderFlat.getOrderPrice(), orderFlat.getCount())); }); orderItemMap.forEach((orderId, orderItem)->{ orderMap.get(orderId).setOrderItems(orderItem); }); return new ArrayList<OrderQueryDto>(orderMap.values()); }stream 저처럼 잘 모르시는 분들은 이게 더 와 닿으실 거임.. 아 보람차다 ㅎㅎㅎ
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
batch는 정확히 등록된 엔티티를 조회해 올때만 작동되는 건가요?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]from 해서 엔티티에서 가져오는 거니 Dto로 가져와도 왠지 먹힐 줄 알았는데 아니었네요..정확히 fetch 등이나 엔티티 자체를 가져올 때만 되는 거 맞나요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
CRUD에 따른 ResponseDto를 보내는 유형 및 ResponseDto 구성 방식에 대한 질문
안녕하십니까 영한님.영한님 덕분에 JAVA Spring 기반 백엔드 개발의시작을 할 수 있었고,이제는 5개월 차 스타트업 백엔드 개발자로써 커리어를 시작하게 되었습니다. 현업에 와서는 오히려 취준생 때 보다 더 많은 고민을 하게 되느데요, 질문 1. 그중 최근에 CRUD의 각 상황별 API 응답을 어떻게 보내는게 적절할지, 질문 2. 그리고 ResponseDto를 어떻게 구성하는것이 적절할지에 대한 고민을 팀장님과 함께 하고있어서, 영한님의 생각을 여쭙고자 질문글을 올리게 되었습니다.답변 해주시면 정말 감사할 거 같습니다! Q1. 생성, 조회 , 수정, 삭제 API의 응답을 각각 어떻게 보내시는지 여쭤보고 싶습니다. 가장 먼저 조회의 경우는 말 그대로 path의 Entity 및 관련된 Entity 정보를 조합하여 응답 DTO로 변환하여 보내고 있습니다. 그런데 나머지 Write Operation에 대한 응답을 어디까지 보내야 하냐가 이슈 입니다.예를들면 엔티티의 생성의 경우 엔티티의 응답 DTO를 보내면 - 프론트에서 별도의 조회 API 호출 없이 바로 프론트가 화면에 뿌려줄 수 있으니깐 저는 생성의 경우에도 조회와 마찬가지로 Entity의 정보를 조합하여 응답 DTO로 변환하여 보내고 있었습니다. 그런데 이러한 부분이 Command Query Sperate 원칙에 어긋나는것 같아, 영한님께서는 혹시 생성한 Entity의 Key만 보내시는지, 아니면 Entity의 정보를 DTO로 변환하여 보내시는지 궁금합니다. 만약 Entity의 Id만 보내신다면 이후에 별도로 조회API를 호출해야 하고 그 또한 비용일텐데 이러한 부분은 어떻게 하시는지 여쭤보고 싶습니다. 이제 수정 API인데요,제가 다룬 비즈니스 로직의 경우 수정 비즈니스 로직이 다양하고 , 각 비즈니스 로직의 경우 다뤄지는 Entity의 종류가 다른 경우였습니다. (중심 Entity는 동일하지만, 연관된 Entity를 누구까지 건드리냐의 차이) 그래서 하나의 통일된 응답으로 보내기 모호한 점이 첫 번째 이유이고,애초에 수정 후에 프론트 화면에서 그 엔티티의 정보를 보여줄 필요가 없어서 라는 두번째 이유에 의해서 에초에 엔티티의 Id값도 보내지 않고 있었는데요,이 수정 API의 응답을 영한님은 어떻게 진행하지는지 그 이유가 궁금합니다. 마지막으로 삭제의 경우는 정말, 프론트에게 보낼 응답이 없어도 되는 경우 라고 생각했는데요,팀장님의 의견은 만약에 나중에 삭제한 Entity를 복구하는 요구사항이 추가되는것을 고려하여Id 정도는 넘기자는 의견을 내어주셨습니다.마찬가지로 삭제의 경우도 어떤식으로 수행하시는지 그 이유가 궁금합니다. Q3. 마지막으로 Entity의 ResponseDto의 필드를 어떤식으로 구성하시는지 궁금합니다 예를들면 저의 경우는 API는 프론트와 서버 간의 스펙이라고 생각하고, Entity의 단건조회의 경우는 단건 조회용 ResponseDto를, 전체조회의 경우는 전체 조회용 SummaryResponseDto를 별도로 만들어서 사용하고 있었습니다. 저희 팀장님 께서는 프론트쪽도 일을 해오시다가 , 백엔드쪽 분야로 전향하신 케이스 인데요,그렇다 보니 어떻게 해야 프론트의 생산성이 올라가는지를 고려하시는 분이셨고,팀장님의 생각은 서버에서 넘겨주는 응답에 일관성이 있어야 그 응답을 사용하는 프론트 측도 학습이 되고 놓치는 부분 없이 생산성이 올라간다는 의견이셨습니다. 그래서 Entity별로 당장 사용하지 않더라도 가능한 모든 필드를 담은 ResponseDto를 하나만 만들고,해당 ResponseEntity의 조합으로 각 API별 응답 Dto를 만들어서 사용하면 ,프론트 측 에서는 일관성 있는 응답값을 사용할 수 있다는 의견이셨습니다.물론 이 방법이 네트워크 패킷의 양을 쓸데없이 증가시킨다는 것을 알고 계시면서도,생산성에 큰 영향을 미치는 부분이라고 생각하셨습니다. 예를들어 다음과 같이 각 Entity의 응답 Dto의 조합별로 API의 ResponseDto를 만들 수 있습니다.ResponseDto{ UserDto{id : 1,name : “aaa”… // User엔티티의 거의 모든 필드} ItemDto{ id : 2,name : “bbb”,… // Item엔티티의 거의 모든 필드}} 저는 이러한 부분에 대해 생각해 본 적이 없이,그냥 제가 “해당 API를 호출하는 화면에서 필요한 정보들만을 담아 (혹은 여러 화면에서 쓰인다면 여러개를 고려) ResponseDto를 각각 만들어서” 넘겼는데요 영한님께서는 이러한 ResponseDto를 구성하는 부분에 있어서상황별로 필드를 재구성 하여 ResponseDto를 정의하여 사용하시는 편 인지 (SummaryResponseDto 등의 별도 Dto에 사용될 Entity의 필드들을 풀어서 정의하시는지)아니면 생산성을 고려하여 각 Entity별 Dto를 만들고, 이들을 조합하여 ReponseDto를 정의하시는 편 이신지 ,혹은 다른 규칙이 있으신지 궁금합니다. 물론 그렇다고 , 팀장님의 의견에서 전체조회시 사용하는 DTO와 단건조회시 사용하는 DTO가 동일하더라도,전체조회 후 단건조회를 할때 단건조회 API를 호출하지 말고 기존 Front가 가지고 있는 값을 쓰지는 말자는 의견 이십니다 (단건조회API는 별도로 호출해야 한다)그저 핵심은 프론트가 다루는 ResponseDto의 일관성을 위해서 입니다 (결론은 생산성을 위해) 긴글 읽어주셔서 감사합니다.항상 건강하셨으면 좋겠고,다음 강의들도 손꼽아 기다리고 있습니다!
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
현업에서 제네릭 쓰나요?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]가끔 오류날 때 recompile 해보곤 하는데..G:\spring\spring-data-project\jpashop\src\main\java\jpabook\jpashop\api\MemberApiController.java:uses unchecked or unsafe operations.Recompile with -Xlint:unchecked for details. 이게 뭔가하고 찾아보니, @Data @AllArgsConstructor static class Result<T>{ private int count; private T data; }여기 이 부분이..물론 파란색이라 에러같은 느낌은 아니고, 그냥 안내 정도로 보이긴 하는데,https://bgpark.tistory.com/33 근데 제가 언뜻 왠만하면 제네릭 쓰지 말라고 들었던거 같긴 한데 기억이.. 잘못들었는지 왜곡되었는지..옛날 라이브러리들은 제네릭으로 구현된게 많아서 그냥 그거 쓰고 제네릭으로 따로 구현하지 말랬던거 같은데.. 제가 잘못 기억하고 있는 거겠죠?