[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 강의 회원테스트 기술 부분을 학습하고있는데 테스트케이스 오류가 났습니다 어떻게 해결해야할지 몰라 질문글을 적었습니다 아래는 테스트 코드입니다 import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*; class MemberServiceTest { MemberRepository memberRepository = new MemoryMemberRepository(); MemberService memberService = new MemberService(); //테스트는 과감하게 한글로 작성 가능 //테스트할땐 given,when,then 틀 사용 @Test void 회원가입() { //given Member member = new Member(); member.setName("hello"); //when Long saveId = memberService.join(member); //then Member findMember = memberService.findOne(saveId).get(); org.assertj.core.api.Assertions.assertThat(member.getName()).isEqualTo(findMember.getName()); } @Test void findMembers() { } @Test void findOne() { } } 그리고 MemberService코드입니다 package hello.hello_spring.service; import hello.hello_spring.domain.Member; import hello.hello_spring.repository.MemberRepository; import hello.hello_spring.repository.MemoryMemberRepository; import java.util.List; import java.util.Optional; public class MemberService { private final MemberRepository memberRepository = new MemoryMemberRepository(); /*회원가입*/ public Long join(Member member){ validateDuplicateMember(member); //중복회원검증 memberRepository.save(member); return member.getId(); } private void validateDuplicateMember(Member member){ memberRepository.findByName(member.getName()) .ifPresent(m -> { throw new IllegalArgumentException("이미 존재하는 회원입니다"); }); } /*전체회원 조회*/ public List<Member> findMembers() { return memberRepository.findAll(); } public Optional<Member> findOne(Long memberId){ return memberRepository.findById(memberId); } } 아래는 오류 메시지 입니다 java.lang.NullPointerException: Cannot invoke "java.util.Optional.ifPresent(java.util.function.Consumer)" because the return value of "hello.hello_spring.repository.MemberRepository.findByName(String)" is null at hello.hello_spring.service.MemberService.validateDuplicateMember(MemberService.java:22) at hello.hello_spring.service.MemberService.join(MemberService.java:15) at hello.hello_spring.service.MemberServiceTest.회원가입(MemberServiceTest.java:24) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) Process finished with exit code -1 어떻게 해결하면 좋을까요?
@Entity @Getter @Setter @DiscriminatorColumn(name = "dtype") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) public abstract class Item { @Id @Column(name = "item_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private int price; private int stockQuantity; @ManyToMany(mappedBy = "items") private List<Category> categories = new ArrayList<>(); //== 비즈니스 로직 ==// public void addStock(int quantity) { this.stockQuantity += quantity; } public void removeStock(int quantity) { int restStock = this.stockQuantity - quantity; if (restStock < 0) { throw new NotEnoughStockException("need more stock"); } this.stockQuantity = restStock; } } @Entity @Getter @Setter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class OrderItem { @Id @Column(name = "order_item_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "order_id") private Order order; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "team_id") private Item item; private int orderPrice; private int count; //==생성 메서드==// public static OrderItem createOrderItem(Item item, int orderPrice, int count) { OrderItem orderItem = new OrderItem(); orderItem.setItem(item); orderItem.setOrderPrice(orderPrice); orderItem.setCount(count); item.removeStock(count); return orderItem; } //==비즈니스 로직==// /* * 재고 수량을 복구한다. * */ public void cancel() { getItem().addStock(count); } //==조회 로직==// public int getTotalPrice() { return getOrderPrice() * getCount(); } } @Entity @Getter @Setter @Table(name = "orders") @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Order { @Id @Column(name = "order_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") private Member member; @OneToMany(mappedBy = "order", cascade = CascadeType.ALL) private List<OrderItem> orderItems = new ArrayList<>(); @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "delivery_id") private Delivery delivery; private LocalDateTime orderDate; @Enumerated(EnumType.STRING) private OrderStatus status; //== 연관관계 메서드 ==// public void addMember(Member member) { this.member = member; member.getOrders().add(this); } public void addOrderItem(OrderItem orderItem) { orderItems.add(orderItem); orderItem.setOrder(this); } public void addDelivery(Delivery delivery) { this.delivery = delivery; delivery.setOrder(this); } // 생성하는 지점을 변경해야 되면 아래 생성 메서드만 바꾸면 된다. 이게 중요한 포인트다 이것저것 찾아다닐 필요없고 //== 생성 메서드==// public static Order createOrder(Member member, Delivery delivery, OrderItem... orderItems) { Order order = new Order(); order.setMember(member); order.setDelivery(delivery); for (OrderItem orderItem : orderItems) { order.addOrderItem(orderItem); } order.setStatus(OrderStatus.ORDER); order.setOrderDate(LocalDateTime.now()); return order; } //==비즈니스 로직==// /* * 주문 취소 * */ public void cancel() { if (delivery.getStatus() == DeliveryStatus.COMP) { throw new IllegalStateException("이미 배송 완료된 상품은 취소가 불가능합니다."); } this.setStatus(OrderStatus.CANCEL); for (OrderItem orderItem : orderItems) { orderItem.cancel(); } } //==조회 로직==// /* * 전체 주문 가격 조회 * */ public int getTotalPrice() { int totalPrice = 0; for (OrderItem orderItem : orderItems) { totalPrice += orderItem.getTotalPrice(); } return totalPrice; } } @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class OrderService { private final OrderRepository orderRepository; private final MemberRepository memberRepository; private final ItemRepository itemRepository; // 주문 @Transactional public Long order(Long memberId, Long itemId, int count) { // 엔티티 조회 Member member = memberRepository.findOne(memberId); Item item = itemRepository.findOne(itemId); // 배송정보 생성 Delivery delivery = new Delivery(); delivery.setAddress(member.getAddress()); // 주문상품 생성 OrderItem orderItem = OrderItem.createOrderItem(item, item.getPrice(), count); // 주문 생성 Order order = Order.createOrder(member, delivery, orderItem); // 주문 저장 orderRepository.save(order); return order.getId(); } // 취소 @Transactional public void cancelOrder(Long orderId) { Order order = orderRepository.findOne(orderId); order.cancel(); } // 검색 // public List<Order> findOrders() { // return orderRepository.f // } } OrderService에서 cancelOrder()을 할 경우 @Transactional에 의해 자동으로 트랜잭션을 시작하고 커밋을 보내고 커밋을 보낼때 플러시가 발생하고 더티체킹이 발생해 직업 update를 안해도 알아서 update 쿼리가 날라가는 부분에 대해서는 이해를 했습니다. 궁금한 부분은 현재 Order order = orderRepository.findOne(orderId); 를 통해 order 엔티티만 조회 했으니 영속성 컨텍스트에는 order 엔티티만 존재하므로 Item 엔티티는 영속성 컨텍스트에 없는데 어떻게 더티체킹에 들어갈까가 저의 의문입니다. 이 부분에 대해서 아래와 같이 생각해봤는데 맞게 생각한건지 궁금합니다. 잘못된 부분에 대해서 알려주시면 감사하겠습니다. order.cancel();의 cancel() 메서드를 보면 orderItem.cancel(); 부분이 존재한다. orderItem.cancel() 의 cancel() 메서드를 보면 getItem().addStock(count); 부분이 존재한다. 여기서 getItem()을 사용해서 (현재 Order와 OrderItem은 지연로딩 관계) 실제 orderItem 값을 사용하므로 DB에서 orderItem 엔티티를 조회해서 영속성 컨텍스트에 저장한다. 다시 orderItem.cancel() 의 cancel() 메서드에서 addStock(count) 메서드를 들어가 보면 Item의 addStock() 메서드로 이동한다. 여기서 this.stockQuantity += quantity; 를 통해 Item의 실제 값을 사용하므로 Item 엔티티도 DB에서 조회해서 영속성 컨텍스트에 저장한다. 결과적으로 OrderService의 cancelOrder() 메서드에서 order.cancel();가 호출되면 Item과 OrderItem 엔티티도 영속성 컨텍스트에 저장되서 더티체킹 범위에 들어가게 된다.
빌더 패턴을 사용하여 객체를 생성하는 방법과 정적 팩토리 메서드를 사용하여 객체를 생성하는 방법을 각각 언제 사용하면 좋을지 궁금합니다. 구글링해서 찾아보니 빌더 패턴은 파라미터가 많을때 사용하고 정적 팩토리 메서드는 파라미터가 적을때 사용한다고 하는데 파라미터가 많고 적음의 기준도 잘 모르겠고 명확하게 언제 사용하면 좋을지에 대한 글을 찾지 못해 질문글을 작성합니다.
import { useEffect } from "react"; declare const window: typeof globalThis & { kakao: any; }; export default function KakaoMapPage(): JSX.Element { useEffect(() => { const container = document.getElementById("map"); const options = { center: new window.kakao.maps.LatLng(33.450701, 126.570667), level: 3, }; const map = new window.kakao.maps.Map(container, options); console.log(map); }, []); return ( <> <script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=키" ></script> <div id="map" style={{ width: 500, height: 400 }}></div> </> ); } Error: Hydration failed because the initial UI does not match what was rendered on the server. Warning: Expected server HTML to contain a matching <div> in <div>. See more info here: https://nextjs.org/docs/messages/react-hydration-error 카카오 맵 하는데 오류 왜 뜨는건가요??
안녕하세요 토비님 변하지 않는 코드 분리 commit 에서 WebApiExRateProvider가 private "static" 인 이유가 있나요? 강의에서는 extract method 단축키로 만드셨는데 왜 intellij가 static을 붙이는것을 추천해줬는지 도 좀 궁금합니다...
========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] 강의 내용에서 hashCode 결과로 음수 값이 나올 수 있으므로 절대값으로 변환하는 과정을 가졌는데요, 자바에서는 왜 음수 값이 나올 수 있게 해놓은 건가요? 인덱스로 사용하는 용도 외에 다른 용도가 있나요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 자바 버전 17이상을 사용하는데 빌드가 안됩니다.
안녕하세요 영한님! 다중서버로 이루어진 분산환경에서 분산락이 주로 사용되는데 이는 전체 또는 여러 서버에서 동기화가 필요한 데이터여서 그런것이죠? 현재 학습내용인 자바에서 제공하는 락 (서버별로 락을 갖는 방식은) 분산환경에는 적합하지 않고, 서버별로 락을 걸어도 커버 되는 자원에 한정되게 사용되는걸로 이해한게 맞을까요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 안녕하세요. car 클래스 engine클래스르 리팩토링 후에 car에 engine을 넣는것을 보았습니다. 그리고 그것을 좀 살펴 보던 중에, engine 안에 있는 start() 메서드를 private로 바꿔 보면 어떨까 라는 생각을 하게 되었고, 구동 결과가 이렇게 되었습니다. stop()이라는 메서드를 추가하고 여기 메서드에 private로 바꾸고 start()는 그대로 public임 영한님은 Enige이라는 클래스만 private로 바꾸고 나머지 메서드는 public로 놔두었는데, 메서드도 private로 바꾸는게 낳을까요? 아니면 그냥 그대로 놔두는것이 좋을까요? 답변 부탁드립니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 안녕하세요. 궁금증이 생겨서 질문을 남깁니다. 섹션7 - 정적 중첩클래스의 활용 - 8분때 중첩클래스의 접근 에서, 흔하지는 않지만 안쪽에 있는 클래스가 외부에서 사용되는 경우가 있다고 말씀하셨습니다. 그래서 어떨때 안쪽 클래스가 외부에서 사용될까?라는 궁금증이 생겼습니다. 일단 두가지를 생각해 보았는데, 헌혈을 할때(피를 다른사람에게 줄대) 차에서 기름을 뺄때(차에 있는 기름을 기름통에 담음) 이 두가지 경우가 있기는 한데 코딩이랑은 좀 상관이 없는것 같아서 어떻게 쓸까? 라는 감이 안 잡히네요. 어느 때에 사용하는지 알켜 주실 수 있으신가요? 답변 부탁 드립니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. child 객체가 parent만 연관관계를 가지면 사용가능 하지만, 다른 엔티티와도 연관관계를 가지면 영속성 전이를 사용하지 못한다고 설명하셨습니다. 위 ERD는 제가 지금 프로젝트를 하고 있는 예시인데요 동아리마다 게시판이 존재하고, 회원은 여러 동아리에 참여할 수 있습니다. 그래서 각 동아리마다 직위가 다르기 때문에 테이블을 따로 빼서 관리를 해주고 있는데요. 그럼 혹시 요 상황에서, 사용자가 가입을 했을 때 가입 테이블에도 자동으로 데이터를 저장하고 싶은데, 동아리 테이블과 연관관계를 가지고 있으므로 영속성 전이를 사용하지 못하는 것일까요? 만약 안된다면, 어떤 방식으로 가입 테이블에 자동으로 추가를 해야할지 조언을 해주실 수 있을까요 ㅠ
포트폴리오 과제중 BoardDetail 작성글 페이지에서 패치보드가 안불러와져서 계속 코드 고쳐보다가 결국 강사님이 올려주시는 포트폴리오리뷰 파일 불러와서 코드보고 똑같이 따라쳐도 제 파일에서만 패치보드가 안불러와져서 오류가 계속나네요.. 혹시 좀 봐주실수 있을까요?(_app.js에서 아폴로 주소 확인도 했습니다) 아래는 패치보드 로드 실패로 나오는 창입니다
자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
jar명령어까지 하여 스프링부트를 실행해주었는데 다음과 같은 오류가 뜨고 웹에서도 서버 내부 오류라고 뜹니다. 무엇이 잘못된건지 모르겠네요. https://www.inflearn.com/community/questions/1199055/45%EA%B0%95-dev-%EC%97%B0%EA%B2%B0-%EC%97%90%EB%9F%AC 이거 참고해도 이해가 안가요
이 부분 진행할 때 "default alias를 쓸 거냐? No" 라고 말씀해 주셨는데 반대로 말씀해 주신 거 같아요! default alias를 쓴다는 선택이니까요. default import alias 대신 custmize으로 쓰겠냐는 질문에 No라고 선택한 걸로 보입니다!