묻고 답해요
169만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 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를 분리괜찮다고 생각하시나요?
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
jpa의 더티체킹 사용에 대해서
해당 강의에서 도메인 모델과 영속성 객체를 구분하는 리팩토링을 진행하셨는데요.리팩토링 이후 영속성 컨텍스트를 통한 더티체킹을 활용하지 않고, 대신 save 메서드를 매번 호출해 주시는 방법으로 변경하셨더라구요.도메인 모델과 영속성 객체의 의존성을 제거하기 위해서 더티체킹 기능도 사용하지 않는건가요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
isEqualTo를 isSameAs로 바꿔야하는것이 아닌가요??
@RunWith(SpringRunner.class) @SpringBootTest public class MemberRepositoryTest { @Autowired MemberRepository memberRepository; @Test @Transactional @Rollback(false) public void testMember() throws Exception { //given Member member = new Member(); member.setUsername("memberA"); //when Long saveId = memberRepository.save(member); Member findMember = memberRepository.find(saveId); //then assertThat(findMember.getId()).isEqualTo(member.getId()); assertThat(findMember.getUsername()).isEqualTo(member.getUsername()); assertThat(member).isEqualTo(findMember); System.out.println("findMember == member: " + (findMember == member)); } }위 코드에서 디비에 넣은 멤버와 찾은 멤버가 같은지를 비교를 isEqualTo를 사용을 하셨는데 이것은 제가 알기론 value부분만 같다면 true라는것으로 알고 있습니다. 같은 영속성 컨텍스트 안에서의 객체가 같은지 확인하려면 isSameAs가 맞지 않은지 의문이 생겼습니다!
-
해결됨JPA & Spring Data JPA 기초
도메인과 JPA 엔티티
도메인과 JPA 엔티티를 구분하려고 코드를 작성해봤습니다.@Repository@RequiredArgsConstructorpublic class OrderRepositoryImpl implements OrderRepository {private final OrderJpaRepository orderJpaRepository;@Override public void save(final OrderJpaEntity entity) {orderJpaRepository.save(entity);}@Overridepublic Optional<OrderJpaEntity> findById(final long orderId) {return orderJpaRepository.findById(orderId)}}이러한 방식으로 JpaRepository를 주입받고 OrderRepository를 구현하는 방식입니다.public interface OrderRepository {void save(final OrderJpaEntity entity);Optional<OrderJpaEntity> findById(final long orderId);} 그런데 이때 변경감지를 사용하려면 Order가 아닌 OrderJpaEntity를 반환해야하는데 이렇게 하면 결국 Repository에도 JPA 엔티티에 의존하기 때문에 분리를 잘 하지 못했다는 생각이 듭니다..혹시 도메인과 JPA 엔티티를 분리한다면 어떠한 방식으로 하시나요?
-
해결됨Java/Spring 주니어 개발자를 위한 오답노트
DB 엔티티와 도메인 분리
어디까지 추상화 해야 하는가? 강의에서 2분 17초에toDomain()으로 바꿔서 반환을 했는데이렇게하면 JPA 엔티티가 아니라서 변경감지를 사용하지 못하는거 아닌가요? 이러한 방식으로 작성한다면 업데이트가 필요할 때는 어떤식으로 처리하나요?
-
미해결Practical Testing: 실용적인 테스트 가이드
controller, service용 dto를 분리시키는 것에 대한 질문
항상 잘 듣고 있습니다. 감사합니다. controller layer와 service layer의 dto를 서로 분리시켜서 service layer가 상위 레이어를 모르도록 한다는 것은 이해가 되었습니다.질문 드리겠습니다! dto를 분리할 때, 중복된 코드가 복잡성을 증가시킬 수도 있고 운영 시, 두 dto 간의 변환 과정의 비용이 어느 정도 성능에 영향을 미칠 수 있다고도 생각합니다.2개로 분리하는 방법은 일반적인 설계 패턴은 아니라고 생각되는데, 혹시 현업에서도 자주 사용하는 방식이신지가 궁금합니다. service에서 생성된 response 데이터에 대해서도 controller만의 response dto를 따로 생성할 필요가 있는지 궁금합니다. 클라이언트로 내려주는 응답 객체로 controller 클래스에서 ResponseEntity는 사용하지 않으시는지,주로 현업에서도 강의에서처럼 응답 객체(ApiReponse)를 커스텀해서 내려주는 방식을 선호하시는지 궁금합니다.
-
미해결더 자바, 코드를 조작하는 다양한 방법
gradle 사용하시는 분 도움
일단 새로운 프로젝트 만들고 premain 추가해주는 것 까진 강의를 그대로 따라하시면 됩니다. manifest plugin 부터 조금 차이가 있어서 거기부터 설명하면, build gradle 에 다음과 같이 추가한다.tasks.named('jar') { manifest { attributes( 'Implementation-Title': project.name, 'Implementation-Version': project.version, 'Premain-Class' : "com.java.magicianAgent.MagicianAgent", 'Can-Redefine-Classes' : true, 'Can-Retransform-Classes' : true) } }터미널에서 다음 명령어를 통해 build 한다./gradlew clean buildbuild.libs file 안에 있는 jar file 을 확인한다. (옵션)강의에서와 마찬가지로 zip file 로 변경하면 확인가능합니다. 저같은 경우 SNAPSHOT.jar 과 SNAPSHOT-plain.jar 이렇게 2개가 생겼는데 SNAPSHOT.jar 은 제가 spring boot 로 실행서 그런지 관련 설정들이 보이고 SNAPSHOT-plain.jar 이 맞는거 같더라구요. jar file 의 절대 경로를 복사해 VM option 에 추가한다. 여기서부터는 다시 강의와 같습니다. VM option 이 안보이시면 오른쪽에 Modify options 클릭하면 add vm options 라고 보이실 겁니다. 이상한거나 궁금한거 있으시면 말씀해주세요. gradle 을 쓰시는 모든 분들도 마술을 성공시킵시다 하하
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
세션은 요청 당 하나만 만들어지는건가요?
SessionManager에서 직접 개발한 세션은 createSession() 메서드로 여러 개의 세션을 만들어서 sessionStore에 저장할 수 있는 것으로 보이는데요 HttpSession을 이용하기 위해 HttpServletRequest의 getSession() 메서드 호출 시 기존 세션이 있다면 생성하지 않고 기존 세션을 가져오는 것으로 이해했습니다.그러면 2개 이상의 세션을 생성할 수 없고 요청 당 하나의 세션만 만들수 있는 건가요?? 질문 하나 더 드리자면 HttpServletRequest의 getSession() 호출 시 세션 ID는 자동으로 생성되고, 세션 Name과 Value는 setAttribute로 설정해야 하는 것이 맞나요? 그렇다면 세션과 세션 ID는 1개만 생성되지만 세션 Name과 Value를 여러 개 설정하는 것이 맞는 것인지요?? 머리 속이 복잡해서 질문드립니다. 읽어주셔서 감사합니다.
-
미해결Practical Testing: 실용적인 테스트 가이드
추상클래스 IntegrationTestSupport을 통한 테스트수행 비용단축에 관한 질문
안녕하세요 강의 테스트 수행도 비용이다. 환경 통합하기 를 듣다가 궁금한 점이 생겨 질문드립니다.강의에서는 추상클래스 IntegrationTestSupport에 어노테이션 @SpringBootTest을 달아서 통합테스트가 필요한 테스트클래스가 상속하여 스프링컨테이너가 반복 실행되는걸 단축하는게 인상깊었는데요.원리가 궁금한 점이 있어 질문드립니다.어떤 원리로 마치 스프링컨테이너가 전파되듯이 상속받은 클래스로 설정한 컨테이너가 작동하는걸까요? 그리고 어떻게 상속받은 클래스가 또 실행될 줄 알고 그 환경(컨테이너)가 어느시점까지 종료되지 않고 지속되고 있는건지 궁금합니다
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
API인터셉터 경로
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]만약에 API로 개발할경우 인터셉터 경로는 어떻게 설정해야하죠?ex 유저API@RestController("api/user")@postmapping유저등록api @Deletemapping유저 삭제 api 이때만 인터셉터 실행 이렇게 있으면 .addPathPatterns("/**")할시 둘다 등록이 되기 때문에 @Deletemapping 이때만 등록하고 싶은데 방법이 있나요? 유저등록일때만@postmapping("/join")으로 설정해야 하나요?