안녕하세요. 강사님이 해주신 강의를 듣고 있는 수강생입니다. 코드를 따라가면서 @ModelAttribute를 복습하면서 컨트롤러에있는 메소드들이 실행될때마다 @ModelAttribute가 붙은 메소드로 부터 반환된 모델들이 생성된다는 것은 이해했습니다. 그래서 items.html 에서 모든 아이템에 대해서 등록지역을 출력하고 싶어 코드를 다른 html에 있는 코드를 items.html에 아이템을 반복하면서 조회하는 부분에 넣어주면 되겠거니 했지만 제목에 기재한 오류가 발생했습니다. 검색을 통해 해결을 하려했지만 그렇지 못해서 질문에 올렸습니다. 아래에 코드를 첨부해드리오니 확인 부탁드립니다. !! 감사합니다!! 에러가 발생하는 지점은 <input type="checkbox" th:field="${item.regions}" th:value="${region.key}" class="form-check-input" disabled> 이부분입니다. <tr th :each ="item : ${items}" > <td><a href ="item.html" th :href ="@{/form/items/{itemId} (itemId=${item.id})}" th :text ="${item.id}" > 회원 id </a></td> <td><a href ="item.html" th :href ="@{|/form/items/${item.id}|}" th :text ="${item.itemName}" > 상품명 </a></td> <td th :text ="${item.price}" > 10000 </td> <td th :text ="${item.quantity}" > 10 </td> <td> <div th :each ="region : ${regions}" class ="form-check form-check-inline" > <input type ="checkbox" th :field ="${item.regions}" th :value ="${region.key}" class ="form-check-input" disabled > <label th :for ="${#ids.prev('regions')}" th :text ="${region.value}" class ="form-check-label" > 서울 </label> </div> </td> </tr>
목록페이지를 그냥 들어가면 # 이름 이렇게 잘 뜹니다. 하지만 회원등록을 하고 난 후 회원목록에 들어가면 Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Could not parse as expression: "${member.id" (template: "members/memberList" - line 19, col 15)] with root cau member.id 를 찾을수없다고 나옵니다 ㅠㅠ
검증 시 @InitBinder 를 사용해서 Validator 를 추가했을 때, 강의 예제와 같은 상황에선 문제가 없습니다. 하지만, 너무 햇갈리는 상황이 일어나서 질문드립니다. 컨트롤러의 매핑 메서드의 인자에 @Validated 애노테이션을 추가하지 않더라도 매핑 메서드에서 model.addAttribute(); 에 Item 이 아닌 객체를 넣을 시 다음과 같은 오류가 발생합니다.. java.lang.IllegalStateException: Invalid target for Validator ====== 추가. 우선 디버깅을 하다보니 @Validated 를 붙이지 않아도 무엇이든지 값을 매핑해야할 일이 있다면 @InitBinder 를 통해 등록한 Validator 의 support() 가 호출 된다는 것을 알 수 있었습니다. 근데, 이걸 보고나니 더욱 의문이 남는게 Validator의 support() 를 실행했을 때 false 가 나와서 해당 검증기를 지원하지 않는다고 하면 그냥 검증을 안하고 넘어가는게 아닌가봅니다..잘 이해가 가지 않습니다. 결국 Model 객체에다가 Item이 아닌 다른 객체를 넣을 때, 결과적으로 DataBinder.java 안의 assertValidators(Validator ... validators); 메서드에서 if (validator != null && (target != null && !validator.supports(target.getClass()))) { throw new IllegalStateException("Invalid target for Validator [" + validator + "]: " + target); } 조건이 참이되버려서 지원하지 않는다면 그냥 예외가 터져버리고 맙니다. 이런식으로 된다면 @InitBinder 로 검증기를 등록해서 사용하다간, 되려 예측하지 못한 검증찾기 실패 오류만 늘어나는것이 아닌지 생각됩니다... 한 컨트롤러내에서 Model 객체에 Item 객체 말고도 실제론 다양한 객체를 넣을텐데 이런 경우엔 @InitBinder 를 사용하지 않고 전부 수동으로 메서드에서 검증을 해야하는건가요? 해결 방법이 궁금합니다.. 마지막으로 해당 상황을 재현할 수 있는 샘플코드를 작성해보았습니다.. 뭔가 질문이 난잡한거 같아서 죄송합니다..ㅠ 항상 감사드립니다. MyController.java @Controller @RequiredArgsConstructor public class MyController { private final MyValidator myValidator ; @InitBinder public void init ( WebDataBinder webDataBinder ) { webDataBinder . addValidators ( myValidator ) ; } @GetMapping ( "/index/{text}" ) public String myView ( @PathVariable String text , Model model ) { SomeObject someObject = new SomeObject () ; someObject . setText ( text ) ; model . addAttribute ( "someObject" , someObject ) ; return "myView" ; } @GetMapping ( "/index" ) public String index ( @ModelAttribute TargetObject targetObject , Model model ) { model . addAttribute ( "targetObject" , targetObject ) ; return "myView" ; } } MyValidator.java @Component public class MyValidator implements Validator { @Override public boolean supports ( Class < ? > clazz ) { return clazz . isAssignableFrom ( TargetObject . class ) ; } @Override public void validate ( Object target , Errors errors ) { TargetObject myTarget = ( TargetObject ) target ; if ( myTarget . getText () . equals ( "error" )) { errors . reject ( "error" ) ; } } } SomeObject.java @Data public class SomeObject { private String text ; } TargetObject.java @Data public class TargetObject { private String text ; }
안녕하세요. 방학기간을 통해 스프링에 대해 공부하고 있는 대학생입니다. 다름이 아니라 스프링 핵심원리 강의에서 역할과 구현을 분리하라고 배웠습니다. 그래서 만약 '회원 저장소'를 만든다고 하면 pubic interface MemberRepository{ void save(Member member); Member findById(Long memberId); } 을 만들고 필요한 구현체를 따로 만들었습니다. 메모리를 이용한다면 public class MemoryMemberRepository implements MemberRepository { private static Map<Long, Member> store = new HashMap<>(); @Override public void save(Member member) { store.put(member.getId(), member); } @Override public Member findById(Long memberId) { return store.get(memberId); } } 이런 식으로 만들고, 만약 JPA를 이용한다면 public class MemberJpaRepository implements MemberRepository { @PersistenceContext private EntityManager em; public void save(Member member) { em.persist(member); } public Member findById(Long id) { Member member = em.find(Member.class, id); return member; } } 이런 식으로 만들어서 사용했습니다. 여기서 스프링데이터JPA를 사용하기 위해선 인터페이스에 JpaRepository를 상속받아야하는데 그러면 기존에 있던 MemberRepository에 상속받아서 사용하면 되나요? 그런데 MemberRepository에서 JpaRepository를 상속받게 되면 기존에 MemberRepository 구현체들이 JpaRepository까지 모두 구현해야하는 문제가 있고, MemberReposity에서 사용하는 메소드 이름과 JpaRepository에서 사용하는 메소드 이름이 같으면 MemberRepository를 주입받아 사용하는 다른 클래스에도 문제가 발생했습니다. 이래저래 글이 길었지만 그래서 어떻게 스프링데이터 JPA를 사용하면서 역할과 구현을 구분할 수 있을까요?
조인/ 단일테이블 / 구현클래스마다 테이블 이 세가지 전략에 대한 소스코드를 교재에서 확인할 수 있는데요 세 전략 모두 Item 클래스를 추상클래스로 선언했음에도 아래와 같은 차이를 보입니다. '조인' / '단일테이블' 의 경우에는 ITEM 테이블이 생성된 반면,[그림7.3, 그림7.4] '구현클래스마다 테이블'에서는 ITEM 테이블이 생성되지 않는 것으로 이해되고 있습니다.[그림 7.5] 왜 이런 차이를 발생시키는 것인지 궁금합니다. 별개로, 강의에서는 '조인'/'단일테이블' 설명하실 때 Item클래스를 추상클래스로 선언하지 않으셔서 이 부분도 혼동을 주고있습니다.
[템플릿 레이아웃1 강의에서의 질문] 안녕하세요. 김영한 강사님. 강의 정말 잘 듣고있고 있는데 궁금한 점이 생겨 여쭤봅니다. base.html 의 틀을 여러 곳에서 사용하고 싶을 때 강의에선 th:fragment="common_header(title, links)" 와 같이 공통을 제외하고 바뀌어야할 부분은 인자로 받아서 replace 하는데 사용하고 있습니다. 그런데, base.html를 사용하고 싶은 어떤 a.html이 있다고 가정할 때 a.html은 넘겨줄만한 추가 links나 title이 없는 경우 th:replace="template/layout/base :: common_header(~{::title})" 다음과 같이 사용할 수 있도록 선택적으로 인수를 받거나 주는 방법 은 없을까요? 레이아웃이 되는 html은 사용하고자하는 많은 html 이 있을 것이라고 생각합니다. 선택적으로 받을 수 없다면 항상 사용하고자 하는 html 쪽에서 추가할 것이 없고 레이아웃을 그대로 따르기만 하는 상황 에선, 쓸모없는 태그를 만들고 필요없는 인자를 항상 넘겨야하는지 의문이 생깁니다. 강의를 다듣고 강의에서 배운 내용들을 적극 활용해 혼자서 프로젝트를 해보는 중에 이런 문제에 부딛혔고 여차여차 어떻게든 해나가려다 보니 thymeleaf-layout-dialect 라는 것도 줏어듣게 되었는데, 이부분은 의존성 추가를 해서 해결하는 부분이라 순수하게 타임리프에서 제공하는 방법으론 해결할 수 없는지 궁금합니다. 감사합니다!
주문취소쪽 테스트하다가 궁금한점 있어 질문드립니다. 취소할 주문ID를 조회하고 Order order = orderRepository.findOne(orderId); order.cancel(); 로 주문취소하기 전에 orderItems에 값이 넣어져 있는지 모르겠습니다. Order와 OrderItem은 @OneToMany로 기본이 LAZY 로딩이라 orderItems을 직접 호출하기 전까지는 데이터를 조회하지 않는거로 알고 있는데 어떻게 orderItems에 값이 채워져서 취소가 되는지요?... for (OrderItem orderItem : orderItems ) { orderItem.cancel() ; } 저 for문 시점에 데이터를 조회하면 이해하겠는데 디버깅해보면 order를 조회할때 이미 값이 다 채워져 있습니다...
안녕하세요! 김영한님. 항상 좋은 강의 너무 감사합니다. 강사님 덕분에 웹에 대해서 많은걸 빠르고 정확하게 알 수 있었습니다. 질문 드리고 싶은게 있는데요! 강의를 보던 도중 HttpServletRequest -> @RequestBody 어노테이션을 사용하여 json 을 바로 HelloData 타입에 맵핑 시켜버리는 정말 간단하고 효율적인 방법이 있다 라는 걸 배웠을때. "이런 지식(@RequestBody에서 객체로 바로 맵핑이 가능하는 하다는 것)을 모르는 상태에서 코드를 해석하는건 거의 불가능이겠네..?" 라는 생각과 함께 "그럼 이런것들은 어디서 찾아봐야 하는거야??" 라는 궁금증으로 이어지게 되었습니다. 지금이야 강사님께서 스프링mvc를 매우 친절하게 거의 씹고 소화가 되도록 입에 넣어주시기 까지 해서 무리없이 배우고 있지만, 강사님 도움 없이 제가 혼자 공부를 해야할 때는 과연 어떻게 해야할지 잘 모르겠습니다! (막힐 때마다 동영상 강의를 틀 수 도 없는 노릇이구요 ㅜ) 혹시 이런 정보를 담고있는 레퍼런스가 있을까요? 없다면 어떻게 학습해야할지 궁금합니다. 그리고 강사님은 스프링부트 뿐만이 아니라 프레임워크를 새로 배우실 때에는 어떤 식으로 접근하시는지 약간의 노하우를 알려주시면 정말 감사할 것 같습니다!
강의에서 영한님께서는 커맨드와 쿼리를 구분하는 것을 선호하신다고 하셨습니다. 그래서 알아보니 이런걸 CQRS라고 하던데 회원 정보를 update시 update command 메소드 실행 후 보통같으면 update메소드 자체의 반환값으로 member객체나 member id를 받는데, 이것을 명령과 질의를 구분해 memberService.update() 후 memberService.findOne을 실행하면 결과적으로 쿼리문을 한번 더 실행을 하게 되잖아요? update 메소드 내에서도 findOne이라는 메소드를 호출하니깐요. 이렇게 명령과 질의를 분리하였지만 그 대가로 쿼리문을 한번 더 호출하게 된 셈인데 쿼리문을 한번 더 호출해서 명령과 질의를 구분하는 것이 많이 효율적인 패턴인가요?
ms.getMessage("hello", null, null)을 넣고 테스트를 돌렸을 때 아래와 같이 뜨면서 테스트가 실패합니다. Expecting: <"??"> to be equal to: <"안녕"> but was not. org.opentest4j.AssertionFailedError: Expecting: <"??"> to be equal to: <"안녕"> but was not. at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at hello.itemservice.message.MessageSourceTest.helloMessage(MessageSourceTest.java:19) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688) at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84) at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115) at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) at java.base/java.util.ArrayList.forEach(ArrayList.java:1541) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) at java.base/java.util.ArrayList.forEach(ArrayList.java:1541) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75) at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99) at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79) at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75) at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94) at com.sun.proxy.$Proxy2.stop(Unknown Source) at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:133) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164) at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56) at java.base/java.lang.Thread.run(Thread.java:834) 2021-08-07 10:51:06.397 INFO 12216 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor' MessageSourceTest > helloMessage() FAILED org.opentest4j.AssertionFailedError at MessageSourceTest.java:19 1 test completed, 1 failed > Task :test FAILED FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':test'. > There were failing tests. See the report at: file:///C:/Users/dpffp/Desktop/STUDY/message/build/reports/tests/test/index.html * Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights. * Get more help at https://help.gradle.org BUILD FAILED in 19s 4 actionable tasks: 1 executed, 3 up-to-date 오류 메세지를 읽어 봤는데 messages.properties 파일에 hello=안녕 이 hello=??으로 바뀌어서 그런 것 같았습니다. 위는 제 messages.properties 파일의 현재 상태입니다. 그래서 인코딩 문제인가보다 하고 인텔리제이 인코딩을 다시 해 주었습니다. 1. Help >> Edit Custom VM Options 클릭해서 파일에 -Dfile.encoding=UTF-8 추가 후 인텔리제이 껐다 켜기 2. Settings >> Editor >> File Encodings >> Global, Project Encoding, Properties Files 설정을 UTF-8로 변경 이후 인텔리제이 껐다 켜기 이 두 가지 방법을 해 보았는데도 여전히 messages.properties파일에 한글이 ?? 으로 깨집니다. 이걸 다시 제가 한글로 수정 후 저장을 하면 다시 ?? 으로 돌아와 버리네요. 어떻게 해결하면 좋을까요?
안녕하십니까? 강사님 수업을 듣는 도 중 똑같이 따라 했는데, Error가 발생해서 질문 드립니다. 먼저 SpringConfig.java 입니다. 위의 Error 내용은 필요 Typedms MemoryMemberRepository인데, 제공된 타입이 MemberRepository여서 Error가 나고 있습니다 MemberService.java 입니다. MemoryMemberRepository.java 입니다. 이렇게 수업대로 따라 했는데, SpringConfig에서 Repository부분에서 Error가 나는데, 왜 나는지가 궁금합니다!
http://localhost:8080/servlet/members/new-form 이 주소를 호출했다면 new MemberFormControllerV3()가 호출이 되는것까지 이해했습니다. (22분 26초) 그런데 그 전에 createParamMap을 가지고 HttpServlet request에 있는 파라미터를 다 뽑아서 paramMap을 만들어서 반환한다. 이 부분이 이해가 안됩니다 ㅠㅠ 실제 어떤 데이터가 들어가고 어떤 데이터가 반환되는지 실제값으로 설명해주실 수 있나요? ㅠㅠ request에는 servlet/members/new-form 이 주소가 들어가는건가요..? 파라미터를 뽑는다는게 정확히 어떤 의미인지 잘 모르겠습니다 ㅠㅠ 마지막으로, paramMap은 HttpServlet request, HttpServlet response를 대체한 것 맞죠..?
SpringConfig에서 문제가 있는데 이유가 뭔지 모르겠습니다! Could not autowire. There is more than one bean of 'MemberRepository' type.Beans:memoryMemberRepository (MemoryMemberRepository.java)springDataJpaMemberRepository (SpringDataJpaMemberRepository.java)
안녕하세요. 너무 좋은 강의 잘 듣고있습니다 !! :) 강의 마지막부분에서 가장 좋은 방법이라고 말씀해주신대로, Service 계층에 ItemUpdateDto 를 추가하고, 엔티티 클래스에 update() 함수도 만들어서 구현을 했습니다. 여기서 한 가지 궁금한점이 생겼는데요, - price >= 0 - stockQuantity >= 0 - name 은 빈 문자열이 아님(StringUtils.hasText == true) 등의 조건을 검사하여 exeception 을 날리거나, update 를 진행하고 싶을 때 조건검사를 어디서 하는 것이 가장 좋은지 고민이 됩니다. 제 생각에는 크게 세가지 방법이 있을 것 같은데요.. 1. Controller 에서 검사하여, 검증된 값만 DTO에 담아서 service 에 전달한다. 2. service 에서 엔티티의 update() 함수를 호출하기전에 검사한다. 3. 엔티티 클래스의 update() 함수 내부에서 검사한다. 세 가지 방법에대해 제가 고민해본 내용을 말씀드리면.. Book 클래스의 removeStock() 처럼 엔티티 내부에서 검사하고, NotEnoughStockException 같은 에러를 날리는 비지니스 로직을 넣어야할까요? (코드에 일관성이 있도록..) --> 3번 그런데, Controller 에서 미리 검사를 하면 굳이 service -> repository 를 타고 내려가서 select 쿼리를 날릴 필요가 없어지기 때문에 성능상 유리할 것 같다는 생각도 듭니다. --> 1번 두 군데에서 다 검사를 하는 것이 좋을까요? 실무에서는 보통 어떤 방법을 채택하는지 궁금합니다 .
안녕하세요 김영한 팀장님. 강의 너무 잘 듣고 있습니다. 앞 강의(Handler / Adapter)를 듣고 이번 강의를 듣다가 궁금한 점이 생겨서 문의드립니다. 앞 강의 첫 번째 예시에서 OlderController -> Controller 인터페이스를 구현하였고, SimpleControllerHandlerAdapter가 채택되어, 내부에서 OlderController가 오버라이딩한 메서드 'handleRequest'를 실행함 앞 강의 두 번째 예시에서 MyHttpRequestHandler -> HttpRequestHandler 인터페이스를 구현하였고, HttpRequestHandlerAdapter가 채택되어, 내부에서 MyHttpRequestHandler가 오버라이딩 한 메서드 'handleRequest'를 실행함 이번 강의의 @RequestMapping된 Controller들은 인터페이스를 구현하고 있지 않는데 어떻게 'RequestMappingHandlerAdapter' 라는 핸들러 어댑터에서 (입력되는 파라미터들도 각기 다른) process 메서드를 호출할 수 있는건지 궁금합니다. 이것도 @RequestMapping 애노테이션으로 인한 효과로 이해하면 될까요?
안녕하세요, JSP를 사용한 회원 관리 프로젝트를 진행하던 중 궁금한 것이 생겨 질문드립니다. JSP도 결국에는 프로젝트 실행시 Java 코드로 변환이 되는 것으로 알고 있는데요. 이전에 개인적으로 Eclipse IDE를 사용한 경우 .metadata라는 폴더가 존재했고, 그 안을 들여다 보면 JSP가 Java 코드로 변환된 파일이 존재했습니다. 예를 들어 "sum.jsp" 파일을 작성했다면 "sum_jsp.java" 파일이 존재한 것 처럼요. (이 .java 파일안에서 pageContext, session, application 객체를 사용할 수 있도록 선언되어 있었던 것도 기억이 나네요.) 어느덧 IntelliJ에 익숙해져서 이런 내용을 잊어버린체 코딩을 하는 것 같아 제가 작성한 JSP 파일에 대해 Java 코드로 변환된 파일을 찾아보고 싶은데, 어떤 경로를 통해 찾을 수 있을까요? 미리 답변 감사드립니다.
기존에는 테스트코드에 대한 중요성을 몰라서 그냥 따라 치기만 했었는데요 생각이 바뀌어서 강의를 들으면서 테스트 코드에 대한 것도 같이 배우면 좋겠다고 생각해서 테스트코드를 이해하고 공부하려고 하는데 혹시 김영한님이 테스트 코드 작성하실 때 쓰는 given/when/then의 정확한 의미가 어떻게 되나요 ?.. 소스를 봐도 딱 개념을 정립하기에 어려움을 겪어 질문하게 되었습니다 ㅠㅠ
※ 참고 : MySQL DB 를 사용하고 있습니다. 아래 사진처럼 SecureSetting, SessionTimeoutSetting 2개의 엔티티를 JOINED 전략을 이용해 상속관계 매핑을 해주었습니다. 그런데 3번째 사진처럼 테스트 코드를 작성하고 실행한 결과, ss_configuration 테이블에는 데이터가 잘 들어가는데 ss_session_timeout 테이블에는 데이터가 들어가지 않습니다. 쿼리로 로그 찍힌걸 봐도 insert 쿼리는 2번 나간것을 확인하였습니다. 혹시나 싶어서 SecureSetting 클래스의 @Id 전략을 AUTO 로 바꾸고 하면 잘 되었습니다. JOINED 전략에서는 Id 전략 중 IDENTITY 전략을 사용할 수 없나요?