이야기를 나눠요
130만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
오타입니다.
3. 메시지, 국제화.pdf 파일 8쪽 상단> "ms.getMessage("hello", null, Locale.KOREA) : locale 정보가 있지만, message_ko 가 없으므로 messages 를 사용"부분에서 "message_ko" 에 s 가 누락된 듯 합니다. messages_ko 아닌지요.
-
스프링 핵심 원리 - 기본편
findAllBean과 findApplicationBean의 test를 다르게 적용했는데도 불구하고 값이 계속 같게 나옵니다. 애플리케이션 빈만 출력되야 하는데 전체가 출력되고 있는데 해결방안은 따로 없을까요?
김영한님 강의대로 라이브 코딩했는데 런 했을 시 findAllBean이랑 findApplicationBean의 값이 동일하게 나와서 당황스럽네요... "C:\Program Files\Java\jdk-11.0.14\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2022.3.2\lib\idea_rt.jar=61288:C:\Program Files\JetBrains\IntelliJ IDEA 2022.3.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Users\samsung\.m2\repository\org\junit\platform\junit-platform-launcher\1.8.2\junit-platform-launcher-1.8.2.jar;C:\Users\samsung\.m2\repository\org\junit\platform\junit-platform-engine\1.8.2\junit-platform-engine-1.8.2.jar;C:\Users\samsung\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;C:\Users\samsung\.m2\repository\org\junit\platform\junit-platform-commons\1.8.2\junit-platform-commons-1.8.2.jar;C:\Users\samsung\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2022.3.2\lib\idea_rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2022.3.2\plugins\junit\lib\junit5-rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2022.3.2\plugins\junit\lib\junit-rt.jar;C:\hello\core\out\test\classes;C:\hello\core\out\production\classes;C:\hello\core\out\production\resources;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-test\2.7.7\204419b38438a398fe43bed95fb835d4ddeb2d2e\spring-boot-starter-test-2.7.7.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter\2.7.7\dd06582c2b6b911bdf1be4f3a40e7b63a5ae75d7\spring-boot-starter-2.7.7.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-test-autoconfigure\2.7.7\ae1417f8f60f4ca378568d965e69a7f043e65397\spring-boot-test-autoconfigure-2.7.7.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-test\2.7.7\aff19a025de03eaa2f465dd5c9bc5fe128da69c9\spring-boot-test-2.7.7.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework\spring-test\5.3.24\dcad3d7fa11fe832005667ab074a54a9546a59ac\spring-test-5.3.24.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework\spring-core\5.3.24\d095c329f30baf2b6d44eccbd2352d7a2f840c72\spring-core-5.3.24.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\com.jayway.jsonpath\json-path\2.7.0\f9d7d9659f2694e61142046ff8a216c047f263e8\json-path-2.7.0.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\jakarta.xml.bind\jakarta.xml.bind-api\2.3.3\48e3b9cfc10752fba3521d6511f4165bea951801\jakarta.xml.bind-api-2.3.3.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.assertj\assertj-core\3.22.0\c300c0c6a24559f35fa0bd3a5472dc1edcd0111e\assertj-core-3.22.0.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.hamcrest\hamcrest\2.2\1820c0968dba3a11a1b30669bb1f01978a91dedc\hamcrest-2.2.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.junit.jupiter\junit-jupiter\5.8.2\5a817b1e63f1217e5c586090c45e681281f097ad\junit-jupiter-5.8.2.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.mockito\mockito-junit-jupiter\4.5.1\f81fb60bd69b3a6e5537ae23b883326f01632a61\mockito-junit-jupiter-4.5.1.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.mockito\mockito-core\4.5.1\ed456e623e5afc6f4cee3ae58144e5c45f3b3bf\mockito-core-4.5.1.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.skyscreamer\jsonassert\1.5.1\6d842d0faf4cf6725c509a5e5347d319ee0431c3\jsonassert-1.5.1.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.xmlunit\xmlunit-core\2.9.0\8959725d90eecfee28acd7110e2bb8460285d876\xmlunit-core-2.9.0.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-autoconfigure\2.7.7\8da88afca89ce4b1ab5762e6ca35e1bad196ad47\spring-boot-autoconfigure-2.7.7.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot\2.7.7\1fa59eb2fce0363bdf152d7660b784257bfac99b\spring-boot-2.7.7.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-starter-logging\2.7.7\c71bdb4e93d75b535fef277606868d1d6934c35\spring-boot-starter-logging-2.7.7.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\jakarta.annotation\jakarta.annotation-api\1.3.5\59eb84ee0d616332ff44aba065f3888cf002cd2d\jakarta.annotation-api-1.3.5.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.yaml\snakeyaml\1.30\8fde7fe2586328ac3c68db92045e1c8759125000\snakeyaml-1.30.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework\spring-jcl\5.3.24\2b30878663ceed2af07238dc54e92e5bf001438d\spring-jcl-5.3.24.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\net.minidev\json-smart\2.4.8\7c62f5f72ab05eb54d40e2abf0360a2fe9ea477f\json-smart-2.4.8.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.slf4j\slf4j-api\1.7.36\6c62681a2f655b49963a5983b8b0950a6120ae14\slf4j-api-1.7.36.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\jakarta.activation\jakarta.activation-api\1.2.2\99f53adba383cb1bf7c3862844488574b559621f\jakarta.activation-api-1.2.2.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.junit.jupiter\junit-jupiter-params\5.8.2\ddeafe92fc263f895bfb73ffeca7fd56e23c2cce\junit-jupiter-params-5.8.2.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.junit.jupiter\junit-jupiter-api\5.8.2\4c21029217adf07e4c0d0c5e192b6bf610c94bdc\junit-jupiter-api-5.8.2.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\net.bytebuddy\byte-buddy\1.12.20\6ec3b8bccc4c988790d8cde5baad3b95609ef136\byte-buddy-1.12.20.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\net.bytebuddy\byte-buddy-agent\1.12.20\c37341e04a529c7263ff3093ecdceaa4ab39b489\byte-buddy-agent-1.12.20.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\com.vaadin.external.google\android-json\0.0.20131108.vaadin1\fa26d351fe62a6a17f5cda1287c1c6110dec413f\android-json-0.0.20131108.vaadin1.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework\spring-context\5.3.24\e48634d7b8f40d4d0fe978830be0247bfc2ff2cd\spring-context-5.3.24.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-classic\1.2.11\4741689214e9d1e8408b206506cbe76d1c6a7d60\logback-classic-1.2.11.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-to-slf4j\2.17.2\17dd0fae2747d9a28c67bc9534108823d2376b46\log4j-to-slf4j-2.17.2.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.slf4j\jul-to-slf4j\1.7.36\ed46d81cef9c412a88caef405b58f93a678ff2ca\jul-to-slf4j-1.7.36.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\net.minidev\accessors-smart\2.4.8\6e1bee5a530caba91893604d6ab41d0edcecca9a\accessors-smart-2.4.8.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.apiguardian\apiguardian-api\1.1.2\a231e0d844d2721b0fa1b238006d15c6ded6842a\apiguardian-api-1.1.2.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.junit.platform\junit-platform-commons\1.8.2\32c8b8617c1342376fd5af2053da6410d8866861\junit-platform-commons-1.8.2.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.opentest4j\opentest4j\1.2.0\28c11eb91f9b6d8e200631d46e20a7f407f2a046\opentest4j-1.2.0.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework\spring-aop\5.3.24\efd01bc1048a2e1b6a7442fbd78170bc02c342b7\spring-aop-5.3.24.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework\spring-beans\5.3.24\e487ea6de09b9a7c36548028feeafa511a593532\spring-beans-5.3.24.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.springframework\spring-expression\5.3.24\ae7410418e7b4bd27a01e3fb1c2fed35b2bc1e84\spring-expression-5.3.24.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\ch.qos.logback\logback-core\1.2.11\a01230df5ca5c34540cdaa3ad5efb012f1f1f792\logback-core-1.2.11.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-api\2.17.2\f42d6afa111b4dec5d2aea0fe2197240749a4ea6\log4j-api-2.17.2.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm\9.1\a99500cf6eea30535eeac6be73899d048f8d12a8\asm-9.1.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.junit.jupiter\junit-jupiter-engine\5.8.2\c598b4328d2f397194d11df3b1648d68d7d990e3\junit-jupiter-engine-5.8.2.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.objenesis\objenesis\3.2\7fadf57620c8b8abdf7519533e5527367cb51f09\objenesis-3.2.jar;C:\Users\samsung\.gradle\caches\modules-2\files-2.1\org.junit.platform\junit-platform-engine\1.8.2\b737de09f19864bd136805c84df7999a142fec29\junit-platform-engine-1.8.2.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit5 hello.core.beanfind.ApplicataionContextInfoTest10:18:45.983 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@32ee6fee10:18:46.013 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'10:18:46.237 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'10:18:46.241 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'10:18:46.243 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'10:18:46.246 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'10:18:46.263 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'appConfig'10:18:46.274 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'memberService'10:18:46.295 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'memberRepository'10:18:46.298 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderService'10:18:46.301 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'discountPolicy'name = appConfig object = hello.core.order.AppConfig$$EnhancerBySpringCGLIB$$b9000c86@7966baa7name = memberService object = hello.core.member.MemberServiceImpl@60975100name = memberRepository object = hello.core.member.MemoryMemberRepository@1253e7cbname = orderService object = hello.core.order.OrderServiceImpl@2d36e77ename = discountPolicy object = hello.core.discount.RateDiscountPolicy@61c9c3fd10:18:46.385 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@655ef32210:18:46.386 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'10:18:46.390 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'10:18:46.390 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'10:18:46.391 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'10:18:46.392 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'10:18:46.393 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'appConfig'10:18:46.394 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'memberService'10:18:46.394 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'memberRepository'10:18:46.395 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderService'10:18:46.395 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'discountPolicy'name = org.springframework.context.annotation.internalConfigurationAnnotationProcessor object = org.springframework.context.annotation.ConfigurationClassPostProcessor@58ffcbd7name = org.springframework.context.annotation.internalAutowiredAnnotationProcessor object = org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@555cf22name = org.springframework.context.annotation.internalCommonAnnotationProcessor object = org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@6bb2d00bname = org.springframework.context.event.internalEventListenerProcessor object = org.springframework.context.event.EventListenerMethodProcessor@3c9bfddcname = org.springframework.context.event.internalEventListenerFactory object = org.springframework.context.event.DefaultEventListenerFactory@1a9c38ebname = appConfig object = hello.core.order.AppConfig$$EnhancerBySpringCGLIB$$b9000c86@319bc845name = memberService object = hello.core.member.MemberServiceImpl@4c5474f5name = memberRepository object = hello.core.member.MemoryMemberRepository@2f4205bename = orderService object = hello.core.order.OrderServiceImpl@54e22bddname = discountPolicy object = hello.core.discount.RateDiscountPolicy@3bd418e4종료 코드 0(으)로 완료된 프로세스
-
자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
왜 강의가 벌써 끝나있죠..??
살면서 이렇게 즐겁게 강의 들어본 적이 없는 것 같네요...들으면서 남겼던 질문 3개도 너무 감동적으로 답변해주시고,,62 강의 12시간 1분 동안의 시간동안 태현님과 진행한 공부가 정말 행복했습니다이렇게나 훌륭한 강의 만들어주셔서 감사드리고 항상 행복만 가득하시길 바라겠습니다.공부하는 개발자 최태현님감사합니다!
-
스프링 DB 2편 - 데이터 접근 활용 기술
@Transactional 적용 범위 관련 말씀드립니다!
삭제된 글입니다
-
스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
강의 동영상 앞으로가기
동영상 10 초 앞으로 가기 나 뒤로 가기 안되나요? 강의 중간에 놓치면 처음부터 다시 듣고 있어서요
-
스프링 DB 2편 - 데이터 접근 활용 기술
스프링 부트 3.0 기준 Hibernate 6 Logging 설정입니다.
logging.level.org.hibernate.SQL = debug logging.level.org.hibernate.orm.jdbc.bind = trace찾아보니까 Hibernate 6 부터org.hibernate.type.descriptor.sql -> org.hibernate.orm.jdbc.bind 으로 변경되었다고 하네요 ~모두들 화이팅! ^^7참고: https://thorben-janssen.com/hibernate-logging-guide/#Logback_via_Slf4j_configuration_for_Hibernate_4_5_and_6
-
스프링 DB 2편 - 데이터 접근 활용 기술
혹시나 저처럼 스프링 부트 3.0으로 따라오고 계신 분들을 위해...
https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/저처럼 스프링 부트 3.0을 사용하고 계신다면, build.gradle에 추가해줄때 3.0.1 버전으로 추가하셔야 합니다. 그 외의 버전은 위 사이트를 참고해주세요.아래의 코드를 복사하시면 됩니다. ^^7 다들 화이팅!implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.1'
-
실전! 스프링 데이터 JPA
맥북 사양
곧 맥북 구매 예정인데 영한님께서 사용하시는 사양이 궁금합니다. (특히 ram)혹시 알 수 있을까요?
-
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
주석 부분이지만 누락 된 거 말씀 드려 봅니다.
PDF 문서 6번 11 페이지 마지막 부분 예제 소스의 주석@PathVariable("userId") String userId -> @PathVariable userId부분에서 "String" 타입명시가 빠졌습니다.
-
스프링부트 개념정리(이론)
강의 감사합니다 쏙쏙 들어오는 느낌
2탄도 있을까요?
-
스프링 프레임워크는 내 손에 [스프2탄]
다음강의 문의 드려요~~
선생님 덕분에 좋은 회사에 취업해서 업무를 배우고있습니다~회사 입사 이후에도 퇴근 후 선생님의 좋은 강의를 계속 듣고 싶어서 문의드려요.수강평에 3월쯤 오픈 예정이라고 답글 달려있는걸 보았는데 3월달에 다음강좌 오픈 확정인가요?제가 선생님의 수업을 모두 들었지만 본의 아니게 Frontend로 가게되어 다음강의에 있는 React 부분이 너무 궁금해서 문의 남깁니다~~항상 감사합니다!
-
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
안녕하세요 해당 강의를 보고 토이프로젝트를 진행하다 궁금한 점이 생겨 질문드립니다.
안녕하세요 항상 강의 잘 보고 있습니다.다름이 아니라 영한님의 jpa강의를 토대로 제가 하는 토이프로젝트에 적용하는 과정에서 궁금한 점 몇가지가 생겨서 질문드립니다.application.yaml파일에서 ddl-auto: create-drop으로 했을때 콘솔창에서는 해당 테이블이 없다면서 자꾸 오류가 났었습니다(콘솔에서는 오류가 나오나 DB상으로는 적절하게 테이블이 생성되었음). 그러나 먼저 ddl-auto: create로 해당 테이블들은 생성해놓고 그 다음 update를 하니 오류없이 동작했습니다. 강의를 들을때는 그러지 않았던것 같았는데 원래 이런건가요? 영한님께서 강의 도중 다대다 관계는 1대다, 다대1 관계로 풀어서 진행하라고 하셨던 기억이 납니다. 그렇게 하는 이유에 대해서는 이해를 하였습니다. 저는 기존의 관계형 데이터 베이스에서는 기존의 다대다 관계를 이루고 있던 테이블들의 pk를 가져와서 새로운 테이블에 FK로 넣었고 이러한 두개의 FK를 묶어서 하나의 PK로 만들었습니다. 그러나 강의에서는 기존의 테이블들을 이어주는 테이블에 FK로 넣어주기는 하였으나 아예 새로운 PK를 만들어서 강의를 진행하시던 기억이 납니다. 여기서 제가 궁금한 점은 기존에 제가 했던 방식대로 하려면 @Embedable으로 복합키를 만들어서 진행을 해야할까요? 아니면 기존 하던 방식 말고 새로운 PK를 만들어서 진행하는 방식이 훨씬 깔끔할까요? 제가 진행하는 토이프로젝트의 환경은 aws ec2를 사용하고 있으면 DB는 mariadb를 사용하고 있습니다. 자바 버전은 17입니다.
-
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
junit5에서는 @Test 에노테이션에서 expected를 지원하지 않는 것 같습니다.
Assertions.assertThrows(IllegalStateException.class, () -> { memberService.join(m2); // Exception 터져야 돼. }); 혹시 junit5 쓰시는 분들은 위와 같이 수정하여서 돌려도 괜찮은 것 같습니다.
-
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
Spring Boot 3.0.2를 사용 중이신 분들이 설정하면 좋은 것
application.properties에 다음 설정을 추가해주세요.logging.level.org.springframework.core.LocalVariableTableParameterNameDiscoverer = error이 것은 Controller가 처음 실행될 때 나오는 로그인,WARN 10382 --- [nio-8080-exec-1] ocalVariableTableParameterNameDiscoverer : Using deprecated '-debug' fallback for parameter name resolution. Compile the affected code with '-parameters' instead or avoid its introspection: hello.springcoremvc211.controller.SpringUploadController를 없애줍니다.이것의 대한 자세한 내용은 https://github.com/spring-projects/spring-framework/issues/29612 에 있으며, Spring 6.0.3에서 고쳐지는 내용입니다.
-
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
안녕하세요 김영한 강사님 봐주실수있을까요 절실해요ㅠ
삭제된 글입니다
-
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
Filter를 등록하는 4가지 방법
안녕하세요. 정리 강의를 들으면서 Filter를 스프링 빈으로 등록하는 방법을 따라하다 버전 차이인지, 스프링 부트의 설정 차이인지, 에러가 발생하더군요.The bean 'logFilter', defined in class path resource [hello/springcoremvc26/config/FilterConfig.class], could not be registered. A bean with that name has already been defined in file [/project/java/spring/spring-core-mvc2-6/out/production/classes/hello/springcoremvc26/web/filter/LogFilter.class] and overriding is disabled.이유를 읽어보니, logFilter가 이미 빈으로 등록되어서 중복 등록이 안된다고 써져있었습니다.그래서 이에 대해 찾아본 결과를 공유하고자 글을 작성합니다. 아래 글은 제 블로그에도 정리되어 있습니다. (홍보...ㅎㅎ..)@ConfigurationLogFilter - 로그 필터@Slf4j public class LogFilter implements Filter { @Override public void init( FilterConfig filterConfig ) throws ServletException { log.info("LogFilter init()"); } @Override public void destroy() { log.info("LogFilter destroy()"); } @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String requestURI = req.getRequestURI(); log.info("[{}] LogFilter doFilter Start", requestURI); try { chain.doFilter(request, response); } finally { log.info("[{}] LogFilter doFilter End", requestURI); } } }LoginCheckFilter - 로그인 필터@Slf4j public class LoginCheckFilter implements Filter { @Override public void init( FilterConfig filterConfig ) throws ServletException { log.info("LoginCheckFilter init()"); } @Override public void destroy() { log.info("LoginCheckFilter destroy()"); } @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String requestURI = req.getRequestURI(); log.info("[{}] LoginFilter doFilter Start", requestURI); try { chain.doFilter(request, response); } finally { log.info("[{}] LoginFilter doFilter End", requestURI); } } }FilterConfig - Filter 등록@Configuration public class FilterConfig { @Bean public FilterRegistrationBean<Filter> logFilter() { FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>(); bean.setFilter(new LogFilter()); bean.setOrder(1); bean.addUrlPatterns("/*"); return bean; } @Bean public FilterRegistrationBean<Filter> loginCheckFilter() { FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>(); bean.setFilter(new LoginCheckFilter()); bean.setOrder(2); bean.addUrlPatterns("/*"); return bean; } }실행 결과[/] LogFilter doFilter Start [/] LoginFilter doFilter Start [/] LoginFilter doFilter End [/] LogFilter doFilter End특징강의에서 나온 방법입니다.설정을 위한 별개의 파일(@Configuration 이 붙은 객체)이 필요합니다.setOrder() 를 통해 순서를 정할 수 있습니다.addUrlPatterns() 을 통해 베이스 URL 및 Whitelist를 설정할 수 있습니다.@ComponentLogFilter@Slf4j @Component @Order(1) public class LogFilter implements Filter { @Override public void init( FilterConfig filterConfig ) throws ServletException { log.info("LogFilter init()"); } @Override public void destroy() { log.info("LogFilter destroy()"); } @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String requestURI = req.getRequestURI(); log.info("[{}] LogFilter doFilter Start", requestURI); try { chain.doFilter(request, response); } finally { log.info("[{}] LogFilter doFilter End", requestURI); } } }LoginCheckFilter@Slf4j @Component @Order(2) public class LoginCheckFilter implements Filter { @Override public void init( FilterConfig filterConfig ) throws ServletException { log.info("LoginCheckFilter init()"); } @Override public void destroy() { log.info("LoginCheckFilter destroy()"); } @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String requestURI = req.getRequestURI(); log.info("[{}] LoginFilter doFilter Start", requestURI); try { chain.doFilter(request, response); } finally { log.info("[{}] LoginFilter doFilter End", requestURI); } } }실행 결과[/] LogFilter doFilter Start [/] LoginFilter doFilter Start [/] LoginFilter doFilter End [/] LogFilter doFilter End특징컴포넌트 스캔을 이용하기 때문에 설정을 위한 별개의 파일이 필요하지 않습니다.@Order 애노테이션을 이용해 순서를 설정할 수 있습니다.기본 URL Pattern이 /* 이며 설정할 수 없습니다.@WebFilter + @ServletComponentScanLogFilter@Slf4j @WebFilter public class LogFilter implements Filter { @Override public void init( FilterConfig filterConfig ) throws ServletException { log.info("LogFilter init()"); } @Override public void destroy() { log.info("LogFilter destroy()"); } @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String requestURI = req.getRequestURI(); log.info("[{}] LogFilter doFilter Start", requestURI); try { chain.doFilter(request, response); } finally { log.info("[{}] LogFilter doFilter End", requestURI); } } } LoginCheckFilter@Slf4j @WebFilter public class LoginCheckFilter implements Filter { @Override public void init( FilterConfig filterConfig ) throws ServletException { log.info("LoginCheckFilter init()"); } @Override public void destroy() { log.info("LoginCheckFilter destroy()"); } @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String requestURI = req.getRequestURI(); log.info("[{}] LoginFilter doFilter Start", requestURI); try { chain.doFilter(request, response); } finally { log.info("[{}] LoginFilter doFilter End", requestURI); } } } MainApplication@ServletComponentScan @SpringBootApplication public class MainApplication { public static void main(String[] args) { SpringApplication.run(SpringCoreMvc26Application.class, args); } } 실행 결과[/] LogFilter doFilter Start [/] LoginFilter doFilter Start [/] LoginFilter doFilter End [/] LogFilter doFilter End 특징설정을 위한 별개의 파일이 필요하지 않습니다.대신, 애플리케이션 실행되는 메인 객체위에 @ServletComponentScan 을 사용해야 합니다.@Order를 이용한 순서 등록을 사용할 수 없습니다.각 필터에 대한 순서를 보장할 수 없습니다.@WebFilter 의 value 나 urlPatterns 파라미터를 이용해 whitelist 방식으로 베이스 URL을 설정할 수 있습니다.@WebFilter("/filter/*")@WebFilter({"/login", "/items"})@WebFilter(urlPatterns = "/filter/*")@WebFilter(urlPatterns = {"/login", "/items"})@WebFilter + @ComponentLogFilter@Slf4j @WebFilter @Component @Order(1) public class LogFilter implements Filter { @Override public void init( FilterConfig filterConfig ) throws ServletException { log.info("LogFilter init()"); } @Override public void destroy() { log.info("LogFilter destroy()"); } @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String requestURI = req.getRequestURI(); log.info("[{}] LogFilter doFilter Start", requestURI); try { chain.doFilter(request, response); } finally { log.info("[{}] LogFilter doFilter End", requestURI); } } } LoginCheckFilter@Slf4j @WebFilter @Component @Order(1) public class LoginCheckFilter implements Filter { @Override public void init( FilterConfig filterConfig ) throws ServletException { log.info("LoginCheckFilter init()"); } @Override public void destroy() { log.info("LoginCheckFilter destroy()"); } @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String requestURI = req.getRequestURI(); log.info("[{}] LoginFilter doFilter Start", requestURI); try { chain.doFilter(request, response); } finally { log.info("[{}] LoginFilter doFilter End", requestURI); } } } 실행 결과[/] LogFilter doFilter Start [/] LoginFilter doFilter Start [/] LoginFilter doFilter End [/] LogFilter doFilter End 특징두 번째 방법과 세 번째 방법을 모두 사용하는 방법입니다.설정을 위한 별개의 파일이 필요하지 않습니다.컴포넌트 스캔 방식을 사용하기 때문에 @ServletComponentScan 도 필요없습니다.@Order 애노테이션을 이용해 순서를 설정할 수 있습니다.@WebFilter 의 value 나 urlPatterns 파라미터를 이용해 베이스 URL이나 Whitelist 방식으로 설정할 수 있습니다.@WebFilter("/filter/*")@WebFilter({"/login", "/items"})@WebFilter(urlPatterns = "/filter/*")@WebFilter(urlPatterns = {"/login", "/items"})애노테이션이 기본으로 3개가 필요합니다.정리결론필터를 사용하기 위한 4가지 방식을 알아보았습니다.첫 번째 방법(@Configuration + FilterRegistrationBean)과 두 번째, 세 번째 방법을 합친 네 번째 방법(@WebFilter + @Component) 중에서 고려하면됩니다.저의 경우에는 @Configuration + FilterRegistrationBean을 더 맘에 드는데, 이유는 Filter Class 위에 애노테이션을 여러개 붙이는 것 보다, 별도의 생성 파일을 하나 만들어서 관리하는게 더 편할 것 같아서였습니다.하지만, @WebFilter + @Component은 스프링 빈으로 등록하는 방법이기에, 다른 스프링 빈을 의존성 주입 받을 수 있습니다. 그런 경우에는 첫 번째 방법으론 할 수 없으니, 네 번째 방법을 사용하면 될 것 같습니다.
-
스프링 DB 2편 - 데이터 접근 활용 기술
내부 트랜잭션이 여러 개 있을 때 롤백 실험
내부 트랜잭션이 여러 개 있을 때 앞쪽 내부 트랜잭션이 롤백될 경우 이후의 내부 트랜잭션은 로직을 수행하는지, 아니면 이후 로직은 수행되지 않고 바로 물리 트랜잭션을 롤백시키는지 의문이 들어 확인해보았습니다. 구조외부 트랜잭션내부 트랜잭션 1내부 트랜잭션 2 코드: 내부 트랜잭션1 - 롤백, 내부 트랜잭션2 -커밋결과결과를 확인해보면 내부 트랜잭션1을 롤백하는 코드가 실행될 때 물리 트랜잭션을 rollback-only로 마킹하고 해당 내부 트랜잭션이 실패합니다. -> 트랜잭션 동기화 매니저에 마킹을 합니다.(이후 강의 내용)하지만 이후 로직을 수행하러 갑니다.수행하러 가서 내부 트랜잭션2 커밋 호출문을 만나면 글로벌(물리) 트랜잭션이 rollback-only로 마킹되어있기 때문에 커밋할 수 없다고 합니다. 계속 가서 마지막에 외부 트랜잭션 커밋이 호출되면 UnexpectedRollbackException 예외가 발생하면서 "rollback-only로 마킹되어있기 때문에 해당 트랜잭션은 롤백되었다"는 로그가 뜹니다. 해당 예외의 조상에는 발생시 트랜잭션이 롤백되는 RuntimeException 예외가 있었습니다. 결론내부 트랜잭션 수행 중 롤백 발생시에 바로 물리 트랜잭션이 롤백되는게 아니다.물리 트랜잭션 -> 트랜잭션 동기화 매니저가 rollback-only의 체크 유무로 롤백 여부를 판단하고, 예상치 못한 상황(rollback-only 마킹돼 있는데 물리 트랜잭션을 커밋하려고 할 때)에서 UnexpectedRollbackException을 발생시켜 롤백을 수행한다. 아직 모르는게 많아서 결론이 맞지 않을 수도 있습니다! 이후 강의를 수강하면서 부족한 점을 채우러 가겠습니다~!
-
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
PathPattern에 대한 몇가지 예시입니다.
설명PathPattern 공식 문서?: 한 문자 일치/pages/t?st.htmlYES: /pages/test.html, /pages/tXst.htmlNO : /pages/toast.html*: 경로(/) 안의 모든 문자 일치/resources/*.pngYES: /resources/photo.pngNO : /resources/favority.ico**: 하위 경로 모든 문자 일치/resources/**/resources/image.png, /resources/css/spring.css{spring}: spring 이라는 변수로 캡처/resources/{path}/resources/robot.txt -> path변수에 "robot.txt" 할당@PathVariable("path")로 접근 가능{*spring}: 하위 경로 끝까지 spring변수에 캡쳐/items/{*path}/items/1/add -> path변수에 "/1/add" 할당{spring:[a-z]+}: 정규식 이용/items/{path:[a-z]+}YES: /items/robotsNO : /items/123 예제 1 - {*spring}@GetMapping("/hello/{*name}") @ResponseBody public String handleTest( @PathVariable String name ) { log.info("name = {}", name); return name; }GET http://localhost:8080/hello/path-test -> name = /path-test === GET http://localhost:8080/hello/path-test/other -> name = /path-test/other 예제 2 - 정규식@GetMapping("/static/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}") @ResponseBody public String handle( @PathVariable String name, @PathVariable String version, @PathVariable String ext ) { log.info("name = {}", name); log.info("version = {}", version); log.info("ext = {}", ext); return "/" + name + "/" + version + "/" + ext; }GET http://localhost:8080/pathtest-1.0.0.jar -> name = pathtest version = 1.0.0 ext = .jar 잘못된 사용@GetMapping("/static/{*fullpath}{name}") @ResponseBody public String runtimeError( @PathVariable String fullpath, @PathVariable String name ) { log.info("fullpath = {}", fullpath); log.info("name = {}", name); return name; } Description: Invalid mapping pattern detected: /static/{*fullpath}{name} ^ No more pattern data allowed after {*...} or ** pattern element{*...} 또는 ** 패턴 요소 다음에는 다른 패턴 데이터를 사용할 수 없습니다.
-
스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
[오타 발견] RedirectAttribute를 설명해주실때, pathVarible 이라 적혀있습니다.
pathVarible -> pathVariablea가 빠진 것을 발견했습니다.
-
자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
강사님 따로 멘토링은 안하시는지요?
인프런에도 멘토링 서비스가 있는데, 멘토링은 따로 안하시나요?