묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
강의 별개의 질문이 있습니다.
안녕하세요. 스프링 입문 다 듣고 기본편을 듣고 있는 수강생입니다. 개인적으로 스프링부트로 프로젝트를 하는도중 mysql 관련해서 궁금한 점이 있어서 글을 남깁니다. 간단하게 말씀드리자면 웹에서 회원가입을 했을 경우 필수 입력사항이 아니면 db에 null 값으로 안들어가고 공백으로 들어가고 있습니다.. 아래 일반적인 테이블인데 공백으로 들어가는 부분이 생깁니다. create table test( num smallint auto_increment primary key, id varchar(200), pw varchar(200), gender varchar(10) ) 다만, 아래 코드처럼 웹사이트가 아닌 쿼리문으로 바로 실행하면 값을 입력하지 않는 컬럼은 null로 들어가고 있습니다. insert into test (id,pw) values ('test','1234'); 웹에서는 입력하지 않은 값이 null이 아닌 공백으로 들어가는지가 궁금합니다.ㅠㅠ
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
갑자기 중복_회원_예외가 Tests failed 떠서 질문드립니다.
안녕하세요 스프링 데이터 JPA를 수강하던 중에 @Test 중복_회원_예외 부분에서 Tests가 failed 되어 질문합니다. 분명 setName으로 설정해준 값도 같은데 말이죠.. 왜 failed가 됐고 성공하려면 어떻게 해야할까요? 다음은 에러 코드입니다. 2021-12-09 22:56:32.154 INFO 5676 --- [ main] o.s.t.c.transaction.TransactionContext : Began transaction (1) for test context [DefaultTestContext@37052337 testClass = MemberServiceIntegrationTest, testInstance = com.example.hellospring.service.MemberServiceIntegrationTest@4ba1f425, testMethod = 중복_회원_예외@MemberServiceIntegrationTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@2320fa6f testClass = MemberServiceIntegrationTest, locations = '{}', classes = '{class com.example.hellospring.HelloSpringApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@51891008, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@9816741, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@2f67a4d3, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@49b2a47d, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@1a5a4e19, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@5e955596], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true, 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@2b4954a4]; rollback [true] Hibernate: select member0_.id as id1_0_, member0_.name as name2_0_ from member member0_ where member0_.name=? Hibernate: insert into member (id, name) values (null, ?) Hibernate: select member0_.id as id1_0_, member0_.name as name2_0_ from member member0_ where member0_.name=? 2021-12-09 22:56:33.381 INFO 5676 --- [ main] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test: [DefaultTestContext@37052337 testClass = MemberServiceIntegrationTest, testInstance = com.example.hellospring.service.MemberServiceIntegrationTest@4ba1f425, testMethod = 중복_회원_예외@MemberServiceIntegrationTest, testException = org.opentest4j.AssertionFailedError: Expecting: <"~~~ 이미 존재하는 회원입니다. validateDuplicateMember"> to be equal to: <"이미 존재하는 회원입니다."> but was not., mergedContextConfiguration = [WebMergedContextConfiguration@2320fa6f testClass = MemberServiceIntegrationTest, locations = '{}', classes = '{class com.example.hellospring.HelloSpringApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@51891008, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@9816741, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@2f67a4d3, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@49b2a47d, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@1a5a4e19, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@5e955596], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true, 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]] org.opentest4j.AssertionFailedError: Expecting: <"~~~ 이미 존재하는 회원입니다. validateDuplicateMember"> to be equal to: <"이미 존재하는 회원입니다."> but was not. Expected :"이미 존재하는 회원입니다." Actual :"~~~ 이미 존재하는 회원입니다. validateDuplicateMember" <Click to see difference> 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 com.example.hellospring.service.MemberServiceIntegrationTest.중복_회원_예외(MemberServiceIntegrationTest.java:55) 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 com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54) 다음은 MemberServiceIntegrationTest의 중복_회원_예외 부분입니다. @Testpublic void 중복_회원_예외() throws Exception { //Given Member member1 = new Member(); member1.setName("spring"); Member member2 = new Member(); member2.setName("spring"); //When memberService.join(member1); IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));//예외가 발생해야 한다. assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");} 다음은 MemberService의 join부분입니다. @Transactionalpublic class MemberService { //private final MemberRepository memberRepository = new MemoryMemberRepository(); private final MemberRepository memberRepository; // 외부에서 memberRepository를 넣어준다. ★★(DI : Dependency Injection) @Autowired public MemberService(MemberRepository memberRepository){ this.memberRepository = memberRepository; } /** * 회원가입 */ public Long join(Member member){ validateDuplicateMember(member); // 중복회원 검증 //System.out.println("~~~ MemberService join save 직전"); memberRepository.save(member); //System.out.println("~~~ MemberService join save 직후"); return member.getId(); } private void validateDuplicateMember(Member member) { memberRepository.findByName(member.getName()) .ifPresent(m -> { throw new IllegalStateException("~~~ 이미 존재하는 회원입니다. validateDuplicateMember"); }); } /** * 전체 회원 조회 */ public List<Member> findMembers(){ return memberRepository.findAll(); } public Optional<Member> findOne(Long memberId){ return memberRepository.findById(memberId); }} 감사합니다 갑자기 잘 되던 부분이 안돼서 당황스럽네요..
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
스프링 데이터 jpa 강의에서 에러 질문이요
안녕하세요 스프링 데이터 jpa 부분을 수강하던중에 에러가 발생해서 질문합니다.. 구글링해봐도 해결책이 안나와서 질문합니다.. 기존 JPA 강의까지는 에러없이 잘 실행 되던 코드가 SpringDataJpaMemberRepository 인터페이스를 추가하고 SpringConfig를 추가했더니 에러가 발생하네요.. 우선 SpringConfig.java코드는 아래와 같습니다. package com.example.hellospring;import com.example.hellospring.repository.JdbcTemplateMemberRepository;import com.example.hellospring.repository.JpaMemberRepository;import com.example.hellospring.repository.MemberRepository;import com.example.hellospring.service.MemberService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import javax.persistence.EntityManager;import javax.persistence.PersistenceContext;import javax.sql.DataSource;@Configurationpublic class SpringConfig { // 스프링 데이터 jpa가 구현체를 만들어 놓은게 등록이됨 private final MemberRepository memberRepository; @Autowired // 생성자가 하나인경우는 생략해도됨, 그러나 명시하는게 좋을듯 public SpringConfig(MemberRepository memberRepository) { // 스프링 컨네이너에서 MemberRepository를 찾는다 근데 등록해 놓은게 ..SpringDataJpaMemberRepository this.memberRepository = memberRepository; } @Bean public MemberService memberService() { // memberService에다 의존관계 셋팅을 해줘야함 return new MemberService(memberRepository); }} 또한 SpringDataJpaMemberRepository 부분은 다음과 같습니다. package com.example.hellospring.repository;import com.example.hellospring.domain.Member;import org.springframework.data.jpa.repository.JpaRepository;import java.util.Optional;public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository { // 스프링 데이터 JPA가 JpaRepository 를 상속받고 있으면 // SpringDataJpaMemberRepository 를 스프링 빈으로 자동 등록해준다 (구현체로 만들어서 등록을 해준다.) // 이것을 SpringConfig에서 가져다 쓰면 된다. @Override Optional<Member> findByName(String name);} 기존 jpa강의 까지 회원가입과 중복_회원_예외 부분이 에러없이 성공적으로 실행 됐습니다. 그런데 아래와 같은 에러가 발생합니다. Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set 참고로 application.properties 부분과 build.gradle 부분은 직전강의까지 잘 실행되던 부분에서 수정한게 없습니다.. 혹시 몰라서 application.properties 부분과 build.gradle부분도 올리겠습니다. application.properties 부분입니다. spring.datasource.url=jdbc:h2:tcp://localhost/~/testspring.datasource.driver-class-name=org.h2.Driverspring.datasource.username=saspring.jpa.show-sql=truespring.jpa.hibernate.ddl-auto=none build.gradle 부분입니다. plugins { id 'org.springframework.boot' version '2.4.12' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java'}group = 'com.example'version = '0.0.1-SNAPSHOT'sourceCompatibility = '11'repositories { mavenCentral()}dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web'// implementation 'org.springframework.boot:spring-boot-starter-jdbc' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly 'com.h2database:h2'// testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' }}test { useJUnitPlatform()} 감사합니다.
-
미해결스프링 핵심 원리 - 고급편
안녕하세요! 질문이 있습니다.
안녕하세요! 영한님, 언제나 좋은 강의 감사드립니다. 해당 수업을 들으면서 궁금한 사항이 생겨 질문 드립니다. 제가 해당 수업을 듣기 이전에는 그냥 막연하게 스프링 AOP에서는 프록시 객체를 런타임 시점에 바이트 코드를 조작해서 만들어 준다라고 알고 있었는데요. 런타임 시점에 바이트코드를 조작한다는 말은 잘못된 표현이라고 생각할 수 있을까요?? 해당 수업을 듣고 나니, 바이트 코드 자체를 조작하는 위빙은 컴파일 타임 위빙이나 로드 타임 위빙에서 바이트 코드를 조작하는 것이지 런타임 시점에서는 바이트 코드를 조작하는 게 아니라는 생각이 들어서요.
-
미해결스프링 핵심 원리 - 기본편
[혹시]스프링 배치프로그램 강의 예정은 없는지요 ?
[혹시]스프링 배치프로그램 강의 예정은 없는지요 ?
-
미해결
스프링입문 강의 오류 질문
스프링 입문 강의 22강 JPA 연결후 회원 가입 TEST 과정에서 오류가 나는데 해결이 안되네요 ㅠ 1. config class 2. service 2. test class join 확인시 하이버네이트 db 연결 오류가 나요 application.properites
-
미해결스프링 핵심 원리 - 기본편
질문입니다.
1. InitializingBean와 DisposableBean "개발자가 코드를 고칠 수 없는 외부 라이브러리에는 적용할 수 없다."라고 설명하셨습니다. 외부 라이브러리의 코드를 제가 직접 고칠 수 없는 건 알겠는데, 그렇기 때문에 해당 메소드를 적용할 수 없는 이유를 좀 더 상세하게 알려주시면 감사하겠습니다. 2. initMethod와 destroyMethod "코드가 아니라 설정 정보를 사용하기 때문에 코드를 고칠 수 없는 외부 라이브러리에도 해당 메소드를 사용할 수 있다."라고 설명하셨습니다. 여기서 해당 기능이 설정 정보를 사용한다는 말의 뜻과 그렇기 때문에 외부 라이브러리에서 사용할 수 있는 이유를 좀 더 상세하게 알려주시면 감사하겠습니다.
-
미해결스프링 핵심 원리 - 기본편
질문입니다.
1. 생성자를 제외한 대부분의 빈은 "컨테이너 생성 -> 빈 객체 생성 -> 의존관계 주입 -> 초기화"의 라이프사이클을 가진다고 하셨습니다. 그러면 생성자 빈의 라이프 사이클은 어떻게 되나요? 강의 15분 48초에서 "생성자 주입 같은 경우에는 객체를 생성해야 되기 때문에 스프링 빈 생성 단계에서 어느정도 일어납니다. "라고 하셨는데, 좀 더 구체적으로 알고 싶습니다. 2. 초기화 콜백, 소멸 전 콜백에 관한 질문입니다. 초기화 콜백은 "의존관계 주입 완료 후 호출"이라고 하셨고, 소멸 전 콜백은 "빈이 소멸되기 직전에 호출"이라고 하셨는데, 여기에서 호출이라는 게 뭔가요? 무엇을 호출한다는 건지요?
-
미해결스프링 핵심 원리 - 기본편
질문입니다.
(관련 코드) static class DiscountService { private final Map<String, DiscountPolicy> policyMap; private final List<DiscountPolicy> policies; @Autowired public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) { this.policyMap = policyMap; this.policies = policies; System.out.println("policyMap = " + policyMap); System.out.println("policies = " + policies); } (강의에서 설명) DiscountService는 Map으로 모든 DiscountPolicy(부모 인터페이스)를 주입 받는다. 이때 fixDiscountPolicy(자식 클래스), rateDiscountPolicy(자식 클래스)가 주입된다. (질문) DiscountPolicy는 인터페이스고 이것을 상속 받는 객체가 rateDiscountPolicy랑 fixDiscountPolicy입니다. 위 설명 대로라면 부모를 주입 받았을 때 자식까지 다 주입 받는 건가요? 자식을 주입 받았을 때 부모까지 주입 받는 거 아니었나요? 제가 상속에 대해 잘못 알고 있었던 건가요?
-
미해결스프링 핵심 원리 - 기본편
빈 생명주기에서 @PostConstruct & @Component 애노테이션 같이 사용할때 질문입니다.
@ProConstruct , @PreDestroy 와 @Component 애노테이션을 함께 사용해보았는데 @ProConstruct 가 붙은 메서드는 의존관계가 주입이 다 끝난후 작동하므로 init 메서드안에 setUrl 메서드를 이용하여 url을 주입한후 @Component를 이용하여 빈으로 등록하였습니다. 결과는 이전에 강의에서 하셨던 코드와 동일하게 나왔습니다. 위와같은 방식으로 @PostConstruct와 @Component 애노테이션을 같이 써봤는데 , 저의 짐작으로 코드를 조작하고 실행해본거라 결과는 똑같이 나왔지만 혹시 이런식으로도 현업에서 개발을 하는건지 궁금해서 여쭤봅니다. 강의 너무 잘 듣고 있습니다. 항상 감사합니다.
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
핸들러 매핑의 방법에 대해 궁금한게 있습니다
강의를 듣다보니 RequestMapping 이 애너테이션 기반이라 편리해서(?) 실무에서 가장 많이 쓰신다고 하셨는데요. 스프링빈 이름도 어차피 애너테이션기반으로 @빈컴포넌트("이름") 으로 등록가능하면 스프링이 알아서 핸들러 매핑을 가져와서 찾을테니 RequestMapping과 큰 차이가 없는것 아닌가요? 뭔가 별다른 부가기능이있거나 특별히 우위를 갖는점이 있는건지 잘 모르겠습니다. 메소드단위로 매핑이 가능한점때문일까요?
-
미해결스프링 핵심 원리 - 기본편
안녕하세요! 강의를 보는 도중 문득 궁금한것이 생겨 질문드립니다!
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(http://bit.ly/3fX6ygx)을 먼저 확인해주세요. 3. 질문 잘하기 메뉴얼(http://bit.ly/2UfeqCG)을 먼저 읽어주세요. 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] 지금 빈조회까지 봤는데 실무에서 자연스럽게 스프링을 사용하고싶으면 빈 조회나 아니면 어노테이션컨피그컨텍스트같은것들의 사용방법들을 따로 모아서 봐야 하는지 아니면 강의를 계속 보다보면 자연스레 외워지는지 궁금합니다. 아니면 따로 추천해주실만한 공부법이 있을까요?
-
미해결스프링 핵심 원리 - 기본편
build.gradle 질문입니다.
hello 프로젝트 생성하고 build.gradle 파일에 dependencies에 exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' 이것이 추가되어 있지 않습니다. 강의하실때 보면 파일에 있는데 추가해줘야하는건가요?
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
강의 내용중 이미지 파일 출력 핸들러 메소드의 보안적 문제 언급에 대한 질문입니다.
안녕하세요. 이번 강의 내용에서 이미지 출력 처리에 있어서는 여러 방법 중 UrlResource를 사용하여 처리하는 과정을 볼 수 있었습니다. @ResponseBody@GetMapping("/images/{filename}")public Resource downloadImage(@PathVariable String filename) throws MalformedURLException { return new UrlResource("file:" + fileStore.getFullPath(filename));} 다만, 32:25 부분에서 "위 코드 만으로는 보안에 취약해 보일 수 있으니, 여러 체크 기능을 넣는 것이 좋다"라고 언급하신 부분에 대해 어떤 부분이 보안에 취약할까 생각하던 중 도무지 생각나질 않아서 좀 더 구체적인 내용을 얻어갈 수 있을까 해서 질문드립니다. 보안 이슈에 대한 설명만 해주셔도, 취약점 체크를 위한 코딩에 도움이 될 것 같습니다. 미리 답변 감사드립니다.
-
미해결스프링 핵심 원리 - 기본편
테스트에 대한 질문
안녕하세요 본 강의의 핵심 내용은 아니지만 테스트 관련해서 궁금한 점이 있어 여쭤봅니다. 1. 협업 현장에서 하나의 테스트 (@Test 1개) 에 대해서 다양한 데이터로 돌아가면서 테스트를 진행하나요? 2. 만약 그렇다면 하나의 테스트에 적용할 다수의 데이터에 대해서 디자인 패턴이 있을 것 같은데 어떤 방식으로 짜는지 궁금합니다. 2번에 대해서 구글링도 해보고 고민을 해봤는데 뭔가 정석? 이 아닌것 같아 질문 드립니다. 아래는 예제 코드입니다. // test 클래스 일부 @Test void join() { //given Member member = MemberTestUtil.getMemberSample("sample1"); //when, then 생략 } // MemberTestUtil 클래스 public class MemberTestUtil { public static Member getMemberSample(String descriptor) { Member member = new Member(); // Member는 @builder 포함 switch (descriptor) { case "sample1": member.builder().id(1L).name("memberA").grade(Grade.VIP); break; case "sample2": member.builder().id(2L).name("memberB").grade(Grade.VIP); break; // 생략 } return member; } }
-
미해결스프링 핵심 원리 - 기본편
Springboot를 사용할땐 AutoAppConfig , AppConfig가 없어도 되는건가요?
@SpringBootApplication 에 @ComponentScan이 존재하니 CoreApplication을 최상단에 두고 하면 정상적으로 돌아간다고 이해해도 되는걸까요? @SpringBootApplication에 존재하는 @ComponentScan에는 필터가 존재한다고 했는데 , 이 필터에 해당되는 클래스만 수동으로 빈으로 등록하고 싶을때 AutoAppConfig를 쓰면 될까요?
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
스프링 웹 프로젝트에서 서블릿 필터, 인터셉터, AOP가 선언된 경우 AOP가 동작하는 시점에 대한 질문입니다.
안녕하세요. 스프링 MVC Part.2 강좌에서 필터와 인터셉터를 배우고나서, 서블릿 필터, 스프링 인터셉터, AOP가 모두 선언이 되어 있는 경우 AOP가 동작하는 시점에 대해 질문을 드리고자 글을 남깁니다. [강의 자료에서 가져온 필터, 인터셉터의 동작 과정] HTTP 요청 -> WAS -> 필터 -> 서블릿(디스패처 서블릿) -> 스프링 인터셉터 -> 컨트롤러 동작 과정을 보다가 문득 든 생각입니다. '그럼 AOP는 어느 구간에서 요청을 캐치해서 동작하는거지?' 예를 들어, 공통 관심 사항(메소드 실행시간 체크)을 처리하는 AOP를 @Around(핵심 기능 실행 전/후 동작)로 선언했다면 AOP가 동작하는 과정은 아래 과정이 맞을까요? HTTP 요청 -> WAS -> 필터 -> 서블릿(디스패처 서블릿) -> 스프링 인터셉터 -> AOP -> 컨트롤러 무조건 위 과정이 맞는지 아니면 공통 관심 사항을 적용하는 방법(메소드 실행 전, 후, 전+후)에 따라 바뀌는지 궁금합니다.
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
HomeConroller의 핸들러 메소드에서 로그인 정보를 담는 member 객체에 대한 질문입니다.
안녕하세요, 로그인 처리2 - 필터, 인터셉터 파트의 'ArgumentResolver' 활용편에서 궁금한 사항이 있어 질문 글을 작성해 봅니다. HomeController에서 '/' URL에 대한 핸들러 메소드 선언시 'member' 파라미터에 대해서는 @Login 어노테이션을 선언하여 직접 구현한 LoginMemberArgumentResolver를 통해 세션에 담긴 로그인 객체를 바인딩(?) 시켜주는 과정을 확인할 수 있었습니다. 만약, HomeController에서 '/' URL 요청 매핑 외 다른 URL 요청 매핑을 처리할 수 있는 여러 핸들러 메소드가 선언되고, 기획자 또는 클라이언트의 요구사항에 따라 HomeController에서 처리되는 모든 핸들러 메소드에 대해서는 로그인 객체를 이용하여 무언가 분기 처리를 해야하는 로직이 포함되어 있어야 한다면(분기 처리는 각기 다른 로직을 포함하고 있습니다.) HomeController에 존재하는 모든 핸들러 메소드의 파라미터로 '@Login Member member'가 선언이 되어야 할 것 같다라는 생각이 들었습니다. 이 또한 반복적인 코드가 아닐까 싶은데요. HomeController에서 '전역적'으로 로그인 정보를 포함하고 있는 객체를 선언하고, 이를 핸들러 파라미터로 굳이 선언하지 않아도, 각 핸들러 메소드에서 사용할 수 있는 방법이 있을까요? P.S HTTP 요청 -> WAS -> 필터 -> 서블릿(디스패처 서블릿) -> 스프링 인터셉터 -> 컨트롤러 흐름을 생각해 보면... 서블릿 필터 또는 인터셉터를 통해 매 요청에 세션에 담긴 로그인 정보를 핸들러 메소드에 각각 다시 주입(?) 시켜줘야 할 것 같은데 실무에서 보통 이렇게 처리하는지 아니면 다른 방법이 있는지 궁금합니다. 미리 답변 감사드립니다.
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
AOP와 서블릿 필터/스프링 인터셉터의 사용 시점에 대한 질문입니다.
안녕하세요. 서블릿 필터 - 소개 강의 내용 4:45 부분에서 '웹과 관련된 공통 관심사는 AOP보다 서블릿 필터 또는 스프링 인터셉터를 이용하는 것이 좋다.' 라는 말씀을 언급해 주셨는데요. 스프링 입문 강의 파트에서 AOP에 대해서 맛보기로 다룰 때 예제 코드에서는 특정 메소드의 실행 시간을 출력해 보는 용도로써 AOP 기술을 사용해 본 적이 있습니다. 여기서 궁금한 것은 실무에서. 물론 규모에 따라 다르겠지만, 보편적으로 웹과 관련된 공통 관심사를 서블릿 필터와 스프링 인터셉터로 구현했다면 AOP를 사용하여 구현할 공통 관심사항에는 메소드 실행시간 외 어떤 것들이 있는지 궁금합니다. 미리 답변 감사드립니다.
-
해결됨
스프링으로 쇼핑몰을 만들고 싶어요.
안녕하세요. 입문 비전공자입니다. 단순히 목표가 스프링 프레임워크로 쇼핑몰을 만들어보자 입니다. 목표 설정 이유는, 한국에서 자주 쓰이는 프레임워크가 스프링으로 알고있고, 쇼핑몰을 만들게되면 어느정도 웹사이트에 대해서 알 수 있지 않을까 싶어서입니다. 목표는 바꾸지 않을 예정이고, 처음부터 백지상태로 공부할 생각입니다. (간단한 교양프로그래밍만 해본 정도입니다.) 혹시 참고할만한 로드맵이나 강의가 있을까요? 감사합니다. p.s 프레임워크는 바뀌어도 괜찮습니다. 죽는 한이 있더라도 실제 결제가능한 쇼핑몰을 어떻게든 만들고 싶습니다.