묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
select 쿼리없이 dto 만들지 않은 이유
강의에서는 아래와 같이 select 쿼리를 이용해 업데이트 된 회원을 조회후 response로 전달해 주었는데 @PutMapping("/api/v2/members/{id}") public UpdateMemberResponse updateMemberV2(@PathVariable("id") Long id, @RequestBody @Valid UpdateMemberRequest request) { memberService.update(id,request.getName()); Member findMember = memberService.findOne(id); return new UpdateMemberResponse(findMember.getId(), findMember.getName()); }아래와 같이 하지 않은 이유가 있을까요??@PutMapping("/api/v2/members/{id}") public UpdateMemberResponse updateMemberV2(@PathVariable("id") Long id, @RequestBody @Valid UpdateMemberRequest request) { memberService.update(id, request.getName()); return new UpdateMemberResponse(id, request.getName()); }
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
오류 코드 Validation과 메세지 처리 과정
@PostMapping("/add") public String addItemV4(@ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) { //검증 로직 if(!StringUtils.hasText(item.getItemName())) { bindingResult.rejectValue("itemName","required"); } if(item.getPrice() == null || item.getPrice() < 1000 || item.getPrice() > 1000000) { bindingResult.rejectValue("price", "range", new Object[]{1000,1000000}, null); } if(item.getQuantity() == null || item.getQuantity() > 9999) { bindingResult.rejectValue("quantity", "max", new Object[]{9999}, null); } //특정 필드가 아닌 복합 룰 검증 if(item.getPrice() != null && item.getQuantity() != null ) { int resultPrice = item.getPrice() * item.getQuantity(); if(resultPrice < 10000){ bindingResult.reject("totalPriceMin", new Object[]{10000, resultPrice}, null); } } if (bindingResult.hasErrors()) { log.info("errors={}", bindingResult); return "validation/v2/addForm"; } ... }제가 생각하는 error 메세지 출력 과정(검증과정)이 맞는 것인지 확인부탁드립니다..!! (addItemV4 기준) 스프링 부트가 errors 메시지 파일을 인식…HTML 폼에서 넘어온 데이터가 검증로직에 걸리면 rejectValue를 통해 bindingResult에 에러 내용을 담는데 MessageCodesResolver을 통해 다음과 같은 오류 코드도 자동으로 생성한다. 예) required.item.itemName, required.itemName, required.java.lang.String, required 또한 사용자 입력 값을 저장해준다.bindingResult에 에러사항이 있으면 bindingResult의 에러 내용이 자동으로 model에 포함되고 다시 validation/v2/addForm으로 돌아간다.타임리프 화면을 렌더링 할 때 th:errors가 실행되면서 오류가 있다면 위에서 생성된 오류 메시지 코드를 순서대로 돌아가면서 메세지 파일과 만족하는 값을 찾아 나타내고(세부적인 것이 더 우선) 없으면 디폴트 메시지를 출력한다. 그리고 th:field는 정상 상황에서는 모델객체의 값을 보여주지만 에러가 있다면 FieldError에서 보관한 값을 꺼내어 나타낸다.추가적으로 만약 타입 오류와 같은 바인딩 오류라면 스프링은 FieldError 를 생성하면서 사용자가 입력한 값을 넣어둔다. 그리고 해당 오류를 BindingResult에 담아서 컨트롤러를 호출한다. 감사합니다!
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
스프링mcv2 - 로그인처리2 - 스프링 인터셉터 요청 로그
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]스프링mvc2 강의에서 로그인처리2 - 스프링 인터셉터 요청 로그 강의에서 LogInterceptor 가 싱글톤처럼 사용된다고 했는데 왜 그런건가요??빈으로 등록이 안됐는데 어떻게 싱글톤으로 관리되는건가요??
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
순수 자바 테스트
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 안녕하세요. 강의 내에서 스프링 없이 테스트 코드를 짜는 것이 좋다고 하신 것을 보고 실제로 테스트 코드는 스프링을 의존하지 않고 짜는 것이 무엇인지 궁금해졌습니다.실제로 강의에서 작성하는 내용 중에, 어느 부분이 스프링에 의존해서 테스트를 한 것인지, 또한 그러한 스프링 의존 테스트를 순수 자바 기반의 테스트로 바꾸며 어떤 식으로 나오게 될지 궁금합니다. 감사합니다.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
model.addAttribute 오류
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. model.addAttribute 하고 안에 값 넣었는데 이게 안먹네요 어떻게해야 해결할 수 있을까요?import 구문 따로 넣는게 있나요?
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
generated 폴더와 Q class import에 관한...
[질문 내용]여기에 질문 내용을 남겨주세요.1. Tasks - other에 compileQuerydsl이 없어서 compileJava를 눌러서 했는데 괜찮은지 ??2.강사님과 다르게 build /generated 이렇게 생성되어도 문제가 없는지?저런식으로 Q파일들이 생성되었는데 import가 안되고 사용이 안되는 이유 알려주시면 감사하겠습니다.
-
미해결Practical Testing: 실용적인 테스트 가이드
OrderResponse에 List<ProductResponse> 를 추가하는게 적절한가 에 대해 의문이 듭니다
안녕하세요 강사님! 질문 드리기에 앞서 항상 좋은 강의 감사드립니다!제가 강의를 수강하면서 의아한 부분이 있었는데요,바로 OrderResponse에 List<ProductResponse> 를 추가하신 부분 입니다.이에 따라 OrderResponse의 of() 메소드 안에서 order.getOrderProducts() 를 호출할 수 밖에 없게 되었는데요,이때 페치조인을 하지 않는 이상 쿼리가 나가게 될 것 같습니다 (지연로딩)저는 바로 이 측면이 개인적으로 잘못되었다고 생각하는데요,JPA는 어떤 쿼리가 어느 타이밍에 나가는지를 파악하기 어려워서, 최대한 이 측면을 명확하게 해주는게 필요하다고 생각합니다.그래서 저의 경우는 서비스 로직에서 사용되는 repository 메소드 들에서만 쿼리가 나가는 경우로 명확하게 제한을 해주는 편 인데요,이런식으로 서비스 로직이 아닌(정확히는 그 안에서 사용되는 repository메소드) 다른 곳에서 지연로딩으로 인해 쿼리가 나간다면 - 어느타이밍에 어떤 쿼리가 나가는지를 코드만 보고 명확하게 파악할 수 없게 된다고 생각합니다.그래서 결론적으로 저는 OrderResponse 안에서 order.getProducts()를 호출하여 List<ProductResponse>를 만드는게 적절하지 않다고 생각하는데요, 이부분에 대해 강사님의 생각을 말씀해주시면 감사하겠습니다! 감사합니다.
-
미해결Practical Testing: 실용적인 테스트 가이드
테스트를 위하여 , OrderService의 createOrder의 파라미터로 registerDateTime을 추가한 측면
안녕하세요! 먼저 항상 좋은 강의 감사드립니다!\다름이 아니라,저는 제목대로 , 테스트를 위해서 OrderSerivce의 createOrder의 파라미터로 registerDateTime을 파라미터로 받게 추가한 측면이 개인적으로 적절하지 않다고 생각하여 질문글을 작성하였습니다. 파라미터를 사용하는 이유는 결국 외부로 부터 값을 받는다는 전제가 깔려있다고 생각하고, 이런 측면에서 보았을 때 요청값으로 시간 값을 받는다고 생각할 수 있습니다.그렇게 생각을 했을때 개인적으로 2가지 정도의 의아한 점이 발생한다고 생각합니다.클라이언트로 부터 넘겨받는 시간이 과연 등록 시간이라고 할 수 있는가? (network delay가 있을것 이기 때문)그렇다고 Controller에서 now() 를 호출한 시간이라는 일종의 고정값을 받을거면 - 파라미터를 선언하는 의미가 있는가? 결론적으로 저는 createOrder의 파라미터로 registerDateTime을 선언하는것이 적합하지 않다고 생각합니다.하지만 우리의 경우는 tdd로써 테스트를 위해 외부로 값을 추출하였는데 - 이러한 문제가 발생하였으므로, tdd 개발론이 과연 적절한 production code를 만드는게 기여하는가? 라는 측면에서 의문이 듭니다.나아가 당연히 저의 미숙한 탓 이겠지만, 강의를 진행해주신 방식대로 온전한 비즈니스 로직을 작성하지 않고 , 테스트 - 개발 - 테스트 - 개발... 이런 플로우로 개발을 하는것이 과연 도움이 되는가? 도 조금 의아한 것 같습니다.어쨌든 여기까지는 저의 순수한 개인적 생각인데요, 이런 부분에 대해서 강사님 께서는 어떻게 생각하시는지 말씀해주시면 정말 감사하겠습니다!
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
TypeNotPresentException
1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예MemberServiceIntegrationTest 에서 회원가입을 run하는 과정중에, 처음에는 NullPointerException 이 뜨다가, 코드수정만 했는데 이제는 아얘 실행조차 안되고 다음과 같이 오류가 뜹니다 __________________위의 오류를 해결하려고 아래와 같이 src/java/main을 소스루트로 지정했습니다 캐쉬삭제도 해보고 이것저것 해봤는데 실행조차 안됩니다 어떻게 고쳐야하나요 ... ㅠㅠ 도와주세요 ..
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
AOP가 적용되지않습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]"package hello.hellospring.aop;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.springframework.stereotype.Component;@Component@Aspect public class TimeTraceAop { @Around("execution(* hello.helloSpring..*(..))") public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {long start = System.currentTimeMillis(); System.out.println("START : " + joinPoint.toString()); try { return joinPoint.proceed(); } finally {long finish = System.currentTimeMillis(); long timeMs = finish - start; System.out.println("END : " + joinPoint.toString()+ " " + timeMs + "ms"); }}}" TimeTraceAop 클래스를 작성한 이후에 실행을 시켜보아도 수업처럼 START END 부분이실행되지 않습니다. 단순 스프링 실행화면만 보이는데 어디가 문제일까요?
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
Validator 분리 2 - 4:25를 듣던 중 궁금한 점이 생겼습니다!
@InitBinder 에 여러 개의 검증이 등록되고 @Validated에 의해 실행될 때 각 검증을 구분하는 것이 Validator의 supports라고 설명하셨는데그래서 임의로 UserValidator를 추가하고 실행해본 결과 IllegalStateException이 발생하는 것을 확인했습니다. 유사한 질문으로 https://www.inflearn.com/questions/811214/initbinder-%EC%A7%88%EB%AC%B8%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4또한 확인했습니다. @InitBinder에 모델명을 등록하는 방식, 한 컨트롤러에서 하나의 모델 객체만 사용하는 방식 등 을 사용하게 된다면 결국 Validator의 supports는 다른 타입을 받게되는 경우가 없는 것 같은데 어떤 경우에 사용되는 것 일까요?
-
미해결Practical Testing: 실용적인 테스트 가이드
Persistence Layer 테스트 (1) 질문
안녕하세요, 좋은 강의 잘 듣고 있습니다.강의 14분쯤에 forDisplay() 메서드를 ProductSellingType Enum 파일에서 생성을 하셨는데요.ProductService 클래스가 아닌 ProductSellingType Enum에서 생성한 이유가 있을까요?어떠한 기준으로 생성을 하셨는지 궁금합니다.추가적으로 이런 부분에 있어 특정 기준을 세우는 관련 글?을 읽고 싶은데 키워드 같은게 있을까요?
-
미해결스프링 핵심 원리 - 기본편
AutoAppConfig 클래스의 역할은 무엇인가요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.강의에서 @Component 에노테이션이 붙은 클래스들을 찾아 빈(bean)으로 등록을 한다고 말씀하셨습니다.이때, 각각의 클래스들이 빈(bean, 자바 개념으로는 객체)로 등록이 되어 관리가 된다는 것까지는 이해가 됐습니다.근데 AutoAppConfig 클래스는 무엇인가요?? 이 클래스는 다른 클래스들을 관리하는 빈으로 생각하면 되는건가요?? 설명 부탁드립니다.더위 조심하세요
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
Cannot snapshot 오류가 뜹니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 코드를 모두 정상적으로 작성하였는데Cannot snapshot C:\Users\이름\OneDrive\바탕 화면\App\Programming\study\inflearn\Spring\forBeginner\hello-spring\build\test-results\test\binary\output.bin: not a regular file이런 오류가 뜹니다.
-
미해결스프링 핵심 원리 - 기본편
소멸 메서드의 호출 시점
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]SingletonBean.init singletonBean1 = hello.core.scope.PrototypeTest$SingletonBean@54504ecd singletonBean2 = hello.core.scope.PrototypeTest$SingletonBean@54504ecd org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing SingletonBean.destroysingletonBeanFind()의 실행 결과입니다.결과를 보면 ac.close() 로 인해 스프링 컨테이너가 종료된 뒤(네 번째 라인), 싱글톤 빈의 종료 메서드가 호출됩니다. 제가 이해한 바로는 싱글톤 빈의 소멸 메서드는 스프링 컨테이너가 종료되기 전에 호출된다고 알고 있습니다. 그런데 출력 순서를 보면 반대로 되어있어서 왜 그런건지 모르겠습니다
-
미해결
스프링 인터셉터가 동작하지 않아 질문드립니다.
안녕하세요, 스프링 MVC 강의를 완강이후 프로젝트를 수행중인 학부생입니다.로그인 기능 구현과 관련하여 강의 예제 코드를 참고하며 구현하던 중이해할 수 없는 현상이 발생하여 질문 드립니다. 코드LoginInterceptor.javapackage Alchole_free.Cockpybara.interceptor; import Alchole_free.Cockpybara.constant.SessionLoginConst; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @Slf4j //@Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); log.info("session = {}", session); if(session==null || session.getAttribute(SessionLoginConst.LOGIN_MEMBER)==null){ log.info("로그인되지 않은 사용자"); response.sendRedirect("/login"); return false; } log.info("정상 요청"); return true; } } WebConfig.javapackage Alchole_free.Cockpybara.config; import Alchole_free.Cockpybara.interceptor.LoginInterceptor; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; //@Slf4j @Configuration //@RequiredArgsConstructor public class WebConfig implements WebMvcConfigurer { // private final LoginInterceptor loginInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .order(1) .addPathPatterns("/**") .excludePathPatterns("/", "/join", "/login", "/css/**", "/*.ico", "/error"); } } 문제위와 같이 코드를 구성하고 애플리케이션을 동작시켰는데, 인터셉터가 아예 로그에 남지않는(생성되지 않는 것으로 보이는) 현상이 발생하였습니다. 관련하여 구글링을 하다보니인터셉터 클래스를 빈으로 등록해주는 형태가 아니면 동작하지 않을 수 있다고 하여,빈으로 등록하고 WebConfig 클래스에서 생성자를 통해 주입받는 형태로 구현도 해보았는데여전히 같은 문제가 발생하더군요. 도대체 어느 부분에서 문제가 발생하는 것인지파악하기가 힘들어 고민끝에 질문드립니다. 혹시 몰라 아래 빌드, 설정 파일도 첨부합니다. 문제 실행 화면/hello 로 Controller @GetMapping 메서드를 구현해놓고 요청을 보냈으나 인터셉터 관련 로그가기록되지 않는 모습입니다.build.gradleplugins { id 'java' id 'org.springframework.boot' version '2.7.13' id 'io.spring.dependency-management' version '1.0.15.RELEASE' } group = 'Alchole_free' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '11' } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' compileOnly 'org.projectlombok:lombok' runtimeOnly 'org.mariadb.jdbc:mariadb-java-client' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' //swagger 설정 implementation group:'io.springfox', name:'springfox-swagger2', version:'2.8.0' implementation group:'io.springfox', name:'springfox-swagger-ui', version:'2.8.0' } tasks.named('test') { useJUnitPlatform() } application.properties# ?????? ?? ?? spring.datasource.url=jdbc:mariadb://localhost:3306/cockpybara spring.datasource.username=root spring.datasource.password=cockpybara spring.datasource.driver-class-name=org.mariadb.jdbc.Driver # JPA ?? spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=create spring.jpa.properties.hibernate.format_sql=true //JPA ???? Hibernate? ????? ???? SQL? formating?? ?? spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect #show parameter binding logging.level.org.hibernate.type.descriptor.sql=DEBUG logging.level.org.hibernate.SQL=DEBUG
-
미해결Practical Testing: 실용적인 테스트 가이드
테스트 동시성 관련 질문드립니다
안녕하세요 강의 다 듣고 기능 추가해 가며 공부를 하고 있습니다. 그러다 막히는 부분이 있어 질문드리는데 강의 내용을 조금 벗어 나는거 같아 질문을 드려도 될지 모르겠는데 괜찮으시다면 답변 주시면 감사하겠습니다. @Transactional public OrderResponse createOrder(OrderCreateServiceRequest request, LocalDateTime registeredDateTime) { List<String> productCodes = request.getProductCodes(); List<Product> products = findProductsBy(productCodes); Member member = memberRepository.findByPhoneNumber(request.getPhoneNumber()).get(); deductStockQuantities(products); Order order = Order.create(products, member, registeredDateTime); return OrderResponse.of(orderRepository.save(order)); }order를 생성하는 부분에서 재고 감소 되는 부분을 동시성 처리를 해보려 하는데 테스트 코드에선 deductStockQuantities로 넘어가서 findAllByProductCodeIn 만 한번 돌고 롤백이 되더라구요. @Test public void create_order_with_concurrent_5_request() throws InterruptedException { //given createProducts(); OrderCreateServiceRequest request1 = OrderCreateServiceRequest.builder() .productCodes(List.of("A002","A003")) .phoneNumber("010-1111-2222") .build(); OrderCreateServiceRequest request2 = OrderCreateServiceRequest.builder() .productCodes(List.of("A002","A003")) .phoneNumber("010-1111-2222") .build(); OrderCreateServiceRequest request3 = OrderCreateServiceRequest.builder() .productCodes(List.of("A002","A003")) .phoneNumber("010-1111-2222") .build(); int numberOfThreads = 3; ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads); CountDownLatch latch = new CountDownLatch(numberOfThreads); //when executorService.submit(() -> { try { orderService.createOrder(request1, LocalDateTime.now()); }finally { latch.countDown(); } }); executorService.submit(() -> { try { orderService.createOrder(request2, LocalDateTime.now()); }finally { latch.countDown(); } }); executorService.submit(() -> { try { orderService.createOrder(request3, LocalDateTime.now()); }finally { latch.countDown(); } }); latch.await(); //then List<Stock> stocks = stockRepository.findAllByProductCodeIn(List.of("A002","A003")); assertThat(stocks).hasSize(2) .extracting("productCode", "quantity") .containsExactlyInAnyOrder( tuple("A002", 7), tuple("A003", 7) ); } @Lock(LockModeType.PESSIMISTIC_WRITE) List<Stock> findAllByProductCodeIn(List<String> productCodes);테스트 코드는 구글링해서 넣어보았는데 이런 부분 관련해서 따로 배운게 없어 잘 안되더라구요. 락도 걸어보고 했는데 어디서 안되는지 잘 모르겠어서 질문드립니다.
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
지금까지 정리한 부분이 맞는지 궁금합니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]제가 지금까지 정리한 부분인데 맞는 이야기인지 확인 및 피드백 부탁 드려도 될까요? 1. 서블릿 컨테이너에 의해 요청된 값이 담긴 Request 객체와 Response 객체가 생성됨. 생성된 Request 객체와 Response 객체는 Dispatcher Servlet의 service() 함수를 호출하면서 전달됨.2. Dispatcher Servlet가 HttpServlet의 service() 함수를 실행함으로써 Dispatcher Servlet의 핵심 로직인 doDispatch()가 호출됨.3. 구현된 HandlerMapping에서 요청 URL에 매핑된 핸들러(컨트롤러)를 찾기 시작함. 만약 핸들러에 @Controller가 적용되어 있고, 요청 URL과 매핑된 @RequestMapping 메소드가 있다면 RequestMappingHandlerMapping는 해당 핸들러를 Dispatcher Servlet에 반환됨.4. HandlerMapping은 전달받은 핸들러를 처리할 수 있는 HandlerAdapter를 조회함. 예를 들어, @RequestMapping 기반의 핸들러를 처리할 수 있는 RequestMappingHandlerAdapter를 찾음.5. HandlerAdapter는 실제 핸들러(컨트롤러)를 호출하기 전에 필요한 매개변수 정보(@RequestParam인지, @ModelAttribute인지, @RequestBody인지, HttpEntity인지)를 ArgumentResolver에 제공함.6. 핸들러 어댑터는 ArgumentResolver의 supportsParameter()를 호출하여 컨트롤러의 매개변수를 처리할 수 있는 ArgumentResolver를 찾음.7. 해당 ArgumentResolver의 resolveArgument()를 호출하여 필요한 데이터를 생성하고, 이를 HandlerAdapter에 반환함.7-1. 만약 핸들러(컨트롤러)가 메서드 레벨에서 @RequestBody, HttpEntity(RequestEntity)를 사용한다면 ArgumentResolver는 HTTP 메시지 컨버터의 canRead() 메소드를 호출하여 매개변수 타입과 미디어 타입(Content-Type)을 처리할 수 있는 HTTP 메시지 컨버터를 찾음.8. canRead() 조건을 만족하면 ArgumentResolver는 해당 HTTP 메시지 컨버터의 read()를 호출하여 필요한 데이터를 생성하고, 이를 HandlerAdapter에 반환함.9. HandlerAdapter는 생성된 파라미터의 값이 모두 준비되면 핸들러(컨트롤러)를 호출하면서 값을 넘겨주고 핸들러(컨트롤러)의 로직을 수행함.10-1. 메시지 바디에 직접 응답하지 않는 경우예를 들면 핸들러(컨트롤러)가 String 타입으로 뷰 이름을 반환하는 경우, HandlerAdapter는 ReturnValueHandler의 supportsReturnType()을 호출하여 지원하는 리턴 타입인지 확인함.지원한다면 HandlerAdapter는 해당 ReturnValueHandler의 handleReturnValue()를 호출하고 Model과 뷰 이름을 가지고 ModelView를 생성함. 그리고 이를 HandlerAdapter, Dispatcher Servlet 순으로 반환함.Dispatcher Servlet은 ModelView를 ViewResolver에 전달함.ViewResolver가 동작하고 뷰를 반환함. 그리고 Dispatcher Servlet가 Model에 담겨져 있는 뷰의 render()를 호출하면 HTML이 생성되고 이를 클라이언트에게 응답함.10-2. 메시지 바디에 직접 응답하는 경우@ResponseBody를 사용하면 뷰 템플릿 대신 HTTP 메시지에 직접 응답 데이터를 출력함.ArgumentResolver는 HTTP 메시지 컨버터의 canWrite() 메소드를 호출하여 리턴 타입과 미디어 타입(Accept-Type)을 처리할 수 있는 HTTP 메시지 컨버터를 찾음.canWrite() 조건을 만족하면 ArgumentResolver는 해당 HTTP 메시지 컨버터의 write()를 호출하여 필요한 데이터를 HTTP 응답 Body 부분에 기록함.흐름이 다시 Dispatcher Servlet으로 돌아가고, ViewResolver를 거치지 않고 바로 클라이언트에게 응답함. 감사합니다.
-
미해결스프링 핵심 원리 - 기본편
CoreApplication 실행이 안돼요....!
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 안녕하세요! 선생님따라서 인텔리제이에 core파일 open해서 CoreApplication실행하려고 하는데 run 버튼도 꺼져있고 실행이 안되는데 어떻게 해결해야할까요....??
-
미해결Practical Testing: 실용적인 테스트 가이드
이 경우, @BeforeEach에 fixture를 구성해도 될까요?
지금 OrderServiceTest 클래스의 createOrder(), createOrderWithStock(), ... 메서드들은 주문을 생성하기 위해서 given절에서 모두 동일하게 product1, 2, 3을 먼저 생성해주는 fixture가 있습니다. @Test void createOrder() { // given LocalDateTime registeredDateTime = LocalDateTime.now(); Product product1 = createProduct(HANDMADE, "001", 1000); Product product2 = createProduct(HANDMADE, "002", 3000); Product product3 = createProduct(HANDMADE, "003", 5000); productRepository.saveAll(List.of(product1, product2, product3)); OrderCreateServiceRequest request = OrderCreateServiceRequest.builder() .productNumbers(List.of("001", "002")) .build(); // when OrderResponse orderResponse = orderService.createOrder(request, registeredDateTime); // then assertThat(orderResponse.getId()).isNotNull(); assertThat(orderResponse) .extracting("registeredDateTime", "totalPrice") .contains(registeredDateTime, 4000); assertThat(orderResponse.getProducts()).hasSize(2) .extracting("productNumber", "price") .containsExactlyInAnyOrder( tuple("001", 1000), tuple("002", 3000) ); }product를 생성해주는 부분을 @BeforeEach로 빼내려고 하는데, 적절하다고 판단되시는지 궁금합니다. OrderServiceTest의 모든 메서드가 동일한 product를 생성하고는 있지만,각 테스트 메서드에서 "001"이라는 상품이 있는지는 @BeforeEach 메서드까지 스크롤을 왔다갔다하면서 확인해야될거라 생각합니다.(만약 없는 상품을 주문한다면 given절에서 예외가 발생하는 것이기 때문에, 이 부분은 당연히 있는 상품을 주문한다는 것을 보장하고 테스트 코드를 작성해야 할까요?) order에 관한 테스트이기 때문에, product에 대한 부분은 분리해도 될거라 생각하지만, 우빈님의 말씀대로 스크롤을 왔다갔다하면서 @BeforeEach의 메서드를 수시로 보는 것은 안좋다고 느껴져서.. product 생성에 대한 fixture를 분리괜찮다고 생각하시나요?