묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
@Transacional의 범위에 대해서 궁금한 점이 하나 있습니다!
안녕하세요 강사님. 항상 훌륭한 강의 감사드립니다. 스프링 MVC 1, 2편에서 사용했던 프로젝트에 JPA를 적용시키는 도중 궁금한점이 하나 생겨서 질문드립니다. TestInitData 클래스에 @PostConstruct로 데이터베이스에 초기 데이터들을 넣어두려고 합니다. package com.myservice.web.test;import com.myservice.domain.item.Item;import com.myservice.domain.item.ItemRepository;import com.myservice.domain.member.Grade;import com.myservice.domain.member.Member;import com.myservice.domain.member.MemberRepository;import com.myservice.domain.member.MemberService;import lombok.RequiredArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;import org.springframework.transaction.annotation.Transactional;import javax.annotation.PostConstruct;@Slf4j@Component@RequiredArgsConstructor@Transactionalpublic class TestDataInit { private final ItemRepository itemRepository; private final MemberService memberService; private final MemberRepository memberRepository; /** * 테스트용 데이터 추가 */ @PostConstruct public void init() { itemRepository.save(new Item("itemA", 10000, 10)); itemRepository.save(new Item("itemB", 20000, 20)); itemRepository.save(new Item("itemC", 15000, 15)); Member member1 = new Member(); member1.setLoginId("manager"); member1.setPassword("manager"); member1.setUsername("최한슬"); member1.setGrade(Grade.MANAGER); Member member2 = new Member(); member2.setLoginId("user"); member2.setPassword("user"); member2.setUsername("USER"); //바로 memberRepository.save로 접근하면 현재 스레드에서 사용할 수 있는 EntityManager가 없다고 오류 발생 memberRepository.save(member1); memberRepository.save(member2); //memberService.save -> memberRepository.save로 접근하면 정상적으로 작동 memberService.save(member1); memberService.save(member2); }} 또한, memberRepository와 memberService는 다음과 같습니다. [memberRepository] package com.myservice.domain.member;import org.springframework.stereotype.Repository;import java.util.List;import java.util.Optional;@Repositorypublic interface MemberRepository { Long save(Member member); Optional<Member> findById(Long id); Optional<Member> findByLoginId(String loginId); List<Member> findAll();} package com.myservice.domain.member;import lombok.RequiredArgsConstructor;import org.springframework.context.annotation.Primary;import org.springframework.stereotype.Repository;import javax.persistence.EntityManager;import java.util.List;import java.util.Optional;@Repository@RequiredArgsConstructor@Primarypublic class JpaMemberRepository implements MemberRepository { private final EntityManager em; @Override public Long save(Member member) { em.persist(member); return member.getId(); } @Override public Optional<Member> findById(Long id) { Member member = em.find(Member.class, id); return Optional.ofNullable(member); } @Override public Optional<Member> findByLoginId(String loginId) { Member member = em.createQuery("select m from Member m where m.loginId = :loginId", Member.class) .setParameter("loginId", loginId) .getResultStream() .findAny() .orElse(null); return Optional.ofNullable(member); } @Override public List<Member> findAll() { return em.createQuery("select m from Member m", Member.class) .getResultList(); }} [memberService] package com.myservice.domain.member;import lombok.RequiredArgsConstructor;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;@Service@Transactional@RequiredArgsConstructorpublic class MemberService { private final MemberRepository memberRepository; public void save(Member member) { memberRepository.save(member); }} 현재 MemberService에는 @Transactional이 걸려있고, memberRepository에는 @Transactional 걸려있지 않습니다. 궁금한점은 TestDataInit 클래스의 init() 메서드에서 바로 memberRepository로 접근하게되면 사용할 수 있는 EntityManager가 없다고 나오며, memberService->memberRepository로 접근하게 되면 정상적으로 처리되는 것을 확인하였습니다. 두 방식 모두 결국 memberRepository를 통해 save를 수행하게 되는데 바로 memberRepository의 접근은 오류가 발생하고 memberService를 통한 접근은 정상적으로 처리되는 이유를 모르겠습니다.
-
해결됨스프링 핵심 원리 - 기본편
@ComponentScan 사용 시 @Configuration에 대하여
안녕하세요 영한님 전 강의에서는 @Configuration이 있는 AppConfig클래스에서 CGLIB를 통해 AppConfig를 상속받은 AppConfig@CGLIB 클래스를 빈으로 등록한다고 하셨는데요, 이때는 AppConfig@CGLIB 클래스가 빈으로 등록되었기 때문에 빈 설정 파일에 등록된 모든 메서드가 CGLIB 기능을 거쳐서 빈 등록이 되었다고 생각했었습니다. 그런데 이번 강의와 같이 @Configuration과 컴포넌트 스캔을 통해서 빈 등록을 한다면 빈 등록이 되어있는 모든 객체가 CGLIB 기능을 거쳐서 빈 등록이 되는건지 여쭈어보고 싶습니다!
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
addInterceptors() 는 어떻게 인터셉터를 등록하는건가요?
김영한 강사님 항상 좋은 강의해주셔서 감사합니다! 인터셉터는 정확히 어떻게 등록되는 건가요? 설정파일에 WebMvcConfigurer을 구현해주고 addInterceptors() 메서드를 오버라이딩 해주기만 하면 알아서 인터셉터가 등록되는 건가요???... 인터셉터가 어떤 식으로 등록이 되는지 궁금합니다ㅠㅠ
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
@ResponseBody vs ResponseEntity
1. @ResponseBody와 ResponseEntity의 기능적인 부분이 동일한 것으로 알고 있는데 ResponseEntity를 사용하면 HTTP header를 좀 더 편리하게 변경할 수 있다고 이해하면 될까요? 2.어떤 상황에 어떤 것을 사용하는지 예시를 들어주실수 있나요? - 제가 생각한 예시는, HTTP 상태코드를 변경하지 않아도 되는상황에 API통신을 할 때 @ResponseBody를 사용하고 HTTP 상태 코드도 변경해야할 때는 ResponseEntity를 사용하는 것이라고 생각했습니다. (물론 @ResponseBody도 파라미터로 Response객체를 받아 헤더의 상태코드를 변경할 수 있지만 ResponseEntity는 추가 파라미터 없이 가능하니까 좀 더 유연하다?는 개념으로 이해했습니다.)
-
미해결스프링 핵심 원리 - 기본편
nullPointException 에러
map 객체에 static을 안붙이면 nullpoint 예외가 나오는데 static을 붙이지 않으면 메모리를 공유하지 않기 때문인가요??
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
label 위치 질문입니다.
안녕하세요! 이 코드에서 라벨의 위치만 바꿔서 이렇게하면 제 예상으론 label이 위로가서 원래 ㅁ 판매오픈 , ㅁ 서울 ( ㅁ은 체크박스 입니다) 이렇게 나오는게 판매오픈 ㅁ, 서울 ㅁ 이렇게 나온다고 예상했는데 판매오픈같은 경우에는 옮겨도 오류는 안나지만 그대로 ㅁ판매오픈 이런식으로 나오고 서울 부산 제주 밑에 코드의 경우에는 아예 오류가 나버리던데 왜그런건가요,..?
-
미해결스프링 핵심 원리 - 기본편
SingletonWithPrototype에서 Provider 대신 프록시 사용
이전 강의에 싱클톤 빈(ClientBean)안에 PrototypeBean이 있는 예제에서 프로바이더 대신 프록시로 해봤는데, 프로토타입빈의 addCount()메소드를 타지 않아 count가 계속 0으로 나오더라구요 프록시로 해결할 수 있는 경우가 있고 ObjectProvider로 해결해야하는 경우가 따로 있나요?
-
미해결실전! 스프링 데이터 JPA
질문있습니다.
안녕하세요 insert 벌크 쿼리에 관해 질문있습니다. 강의에서 말씀해주신 대로 해보니 delete와 update의 경우 한번에 처리되는 것을 확인할 수 있었습니다. 문제는 Insert 였습니다. 저는 MySQL 를 사용하면서 IDENTITY 전략을 사용해왔었는데 MySQL의 경우 벌크 INSERT 쿼리를 날리기 위해서는 찾아보니 Batch Insert를 사용하기 위해서는 IDENTITY 전략이 아니라 TABLE 전략을 사용해야 한다고 하더라구요. 제가 궁금한 점은 아래와 같습니다. 1. 다른 ENTITY들은 IDENTITY 전략을 사용하고 Batch Insert가 필요한 특정 ENTITY만 TABLE 전략으로 변경해도 괜찮을까요? 2. 실무에서는 INSERT 쿼리를 한 번에 날리기 위해서는 어떤 방식을 사용하나요?? 감사합니다 :) 2.
-
미해결스프링 핵심 원리 - 기본편
강의 복습하다가 생긴 질문 및 다음 커리큘럼에 대한 질문
1. 업로드해주신 pdf 파일 기준 18페이지, 19페이지에 주문과 관련된 클래스 및 인터페이스가 Order, OrderService, OrderSerivceImpl 이렇게 총 3개가 나오는데요 OrderSerivce은 말 그대로 역할을 위한 interface이고 OrderServiceImpl은 OrderService를 상속받은 클래스인데, 왜 Order라는 클래스를 하나 더 만드셨는지 궁금합니다. (Order안에 OrderServiceImpl의 내용을 다 넣어도 되지 않았을까? 굳이 왜 저렇게 소스를 작성하셨는지가 궁금합니다. 궁금한 점을 명확하게 표현하기가 어려운데, 주문이라는 행위 하나에 왜 Order과 OrderServiceImpl 두개의 클래스를 만들었는지?가 궁금합니다. OrderServiceImpl은 주문하는 과정이고 , Order은 영수증이라고 보면 되는걸까요?) - 2. 그리고 강의를 모두 수강 했는데, 강의 마지막에 JPA 실무 완전 정복 로드맵 (야생형) 수강하는 것을 추천하셨는데 최근에 남기신 댓글에서는 김영한의 스프링 완전 정복 MVC1편까지 보고 JPA 실무 완전 정복 로드맵 (야생형) 을 추천하시더라구요 스프링 완전 정복 로드맵( MVC2편 까지) 다 수강하고 JPA 실무 완전 정복 로드맵 (야생형) 으로 넘어가면 될까요 ?? 아니면 MVC1편만 수강하고 JPA 실무 완전 정복 로드맵 (야생형) 로 공부한다음에 돌아와서 MVC2편을 수강하면 되는건가요 ? 강의 매번 잘 듣고 있습니다. 좋은 강의 감사합니다.
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
레포지토리에 @Transactional을 안붙이는 이유
Service에는 Transactional 어노테이션을 달지만 레포지토리에는 달지 않는 이유가 궁금합니다. 서비스에만 어노테이션을 달아도 서비스에서 레포지토리의 메소드를 호출하니 레포지토리에까지 Transactional 어노테이션이 적용되어서 그런건가요??
-
미해결스프링 핵심 원리 - 기본편
NetworkClient setUrl 질문
빈 생명주기 콜백 예시 중 빈 생성후 연결단계에서 setUrl로 연결처리 해주셨는데.. 한가지 궁금한건 이전 강의에서 싱글톤 주의점으로 외부에서 빈의 변수를 수정할 수 있으면 바뀔 수 있는 위험이 있으니 저렇게 setUrl을 퍼블릭 메소드로 두면 안되지 않나요? 그런데 또 NetworkClient 생성자에 url 파라메터로 주지말고 역할을 따로 줘야한다고 해서 두가지가 헷갈랍니다.
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
빈 이름 설정 관련 질문
안녕하세요 김영한님 항상 좋은 강의 강의 너무 잘 듣고 있습니다! 스프링 빈이 등록될 때 빈 이름은 기본적으로 클래스 명을 따라가되 맨 앞글자만 소문자로 바뀌는거 아닌가요? @Component("helloBean") static class HelloBean { public String hello(String data) { return "Hello " + data; } } 해당 내용을 다음과 같이 수정해서 @Component static class HelloBean { public String hello(String data) { return "Hello " + data; } } 타임리프에 @helloBean 으로 적용하면 NoSuchBeanDefinitionException이 발생하네요 ㅠㅠ...
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
dto 로 변환 단계에 대해 질문드립니다!
안녕하세요! entity를 dto로 변환하는게 좋다 하셨는데 repository에서 service로 넘겨줄때 dto를 넘기는게 맞나요 아니면 repository에서는 entity를 넘겨주고 service에서 controller로 넘겨줄때 dto로 변환해서 넘겨주는게 맞나요??
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
no operatin
안녕하세요. ${data}에는 값이 있으니까 _(no operation)을선택하지 않고, ${nullData}는 null이니 _(no operation)을선택하게 돼서 연산을 수행하지 않고 그냥 원래 html이 보여지게 하잖아요. 그럼 그냥 <span th:text="${data}">데이터가 없습니다.</span><span th:text="${nullData}">데이터가 없습니다.</span>이렇게 써도 결과에 차이가 없어보이는데 왜 저걸 사용하는건가요?
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
세션 저장소
안녕하세요~ 이 강의에선 Map을 세션저장소로 사용했는데요, 실제로는 어떤 저장소를 주로 사용하나요? 궁금합니다! 서버가 여러개 일때는 세션 data를 어떻게 일관성을 유지하는 지도 궁금합니다!
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
request에 대한 질문입니다.
위에 17:28 초 쯤에 설명해주시는 Test 코드에 대해 질문이 있습니다. 다름이 아니라 HttpRequest 를 보낸 이후에 응답인 HttpResponse에 Cookie를 담아서 돌려주는 부분은 이해가 되는데 왜 Request에 해당하는 부분도 response 에서 꺼낸 cookie를 request 에 setCookie로 담아주어야 하나요 ? 순서적인 부분에서 좀 헷갈리는 부분이 생겨 질문 드립니다..! 늘 좋은 강의 감사드립니다..!
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
API 서버 기능 국제화에 대한 질문입니다
항상 좋은 강의 감사드립니다. 다름이 아니라 국제화 기능에 대한 강의를 듣던 중 질문이 생겨서 글 남깁니다! 말씀하신 국제화 기능은 타임리프에서 해당 내용들을 치환해서 사용하는 것으로 이해를 하였는데요, 만약 현재 API 서버를 만들고 있고, 해당 API 서버에서 앱에 접속한 유저의 국적에 따라 API 에서 내려주는 데이터의 언어를 맞춰서 줘야할 경우에 어떻게 해야할 지 감이 안잡혀서 질문을 드립니다. 구체적인 상황을 가정하여 말씀드려보면, 예를들어 배달의 민족 서비스 어플에서 각 가게들의 정보 및 메뉴들이 핸드폰 기기언어가 한국어 일시 한국어로, 영어일 시 영어로 나와야 한다고 가정하고 질문드려보려고 합니다 1. 먼저 데이터베이스에 테이블 설계를 어떻게 하는것이 효율적인지 궁금합니다. 단순하게 생각하면 가게 데이터베이스 칼럼을 영어칼럼을 하나씩 다 만드는 경우가 있을것 같은데, 이렇게하면 요구사항에 대응해야하는 언어가 늘어날 때마다 칼럼을 추가해야해서 비효율적이지 않을까 생각이 듭니다... 아니면 번역 테이블을 따로 만들어서 한국어, 영어, 기타언어.. 등의 방식으로 만들어 놓고 비즈니스 로직중에 번역 테이블을 조회하여 해당 데이터들을 조회한 언어로 치환하는 방법이 있을 것 같은데 이 방법은 언어가 바뀌어야 하는 비즈니스 로직 모두를 손봐야 해서 복잡할 것 같다는 생각이 듭니다. 어떤 방법이 좋을지, 실무에서 어떻게 이러한 문제를 해결하는 지 궁금합니다! 2. 기존 코드에 대한 이식성 좋게 언어대응하는 방법이 궁금합니다. 한국어 서비스를 출시하고 서비스가 잘 되어서 API 서버가 주는 데이터가 기타 언어까지 확장해야 한다는 요구사항이 들어왔을 때 1번에서 말씀드린 방법들로 해결하고자 하면 기존 코드를 모두 손봐야하는 상황이 발생합니다. 혹시 이러한 상황을 해결할 수 있는 다른 방법이 있는지 궁금합니다. 저 혼자서 생각을 해보았을 때는 Response Advice 등으로 response 로 나가는 데이터를 json 으로 convert 하기 전에 가로채서 Reflection 으로 응답으로 나간 객체의 데이터를 샅샅이(?) 뒤져서 String 형태의 문자열이 있으면 1번에서 말씀드린 번역테이블에 조회하여 번역해야 하는 언어로 교체하는 방법.. 정도가 떠오르는데 이게 맞는건지 모르겠습니다ㅠㅠ 해당 이슈 해결방법에 대한 강사님의 의견이 궁금합니다! 긴 글 읽어주셔서 감사합니다:)
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
assertThrows 오류 관련
안녕하세요. serviceTest를 하던중에 막혀서 이것저것 다 해봤지만 안돼서 질문드립니다. 다음 사진과 같이 assertThrow에서 오류가 발생합니다. 그래서 이전 코드들도 쭉 봤는데 그렇다기엔 try catch 문에서는 정상적으로 작동합니다. 뭐가 문제일까요?
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
컨버터에 대해서 질문있습니다.
강의를 들어보니까 이미 스프링에서 다 컨버터를 만들어서 제공해주고 있다고 말씀하시는데요 그러면 실무에서 개발자가 직접 코딩할일은 없고 만들어진 컨버터를 사용하기만 하면 되는건가요?? 개발자가 컨버터를 직접만들어서 사용할 경우가 있는지 궁금합니다.
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
message 처리 질문
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 안녕하세요 제가 이번 강의를 듣고 제 토이 프로젝트에 메세지 처리를 추가 하고 싶어서 Bean Validation을 이용한 검증 코딩을 해봤는데요 @Getter@NoArgsConstructor(access = AccessLevel.PROTECTED)public class LoginRequest { @NotBlank @Size(min = 2) @Email private String email; @NotBlank @Size(min = 8, max = 20) private String password;}------------------------------------------------------------------------------------------------- @Getter@NoArgsConstructor(access = AccessLevel.PROTECTED)public class UserCreateRequest { @NotBlank @Size(min = 2) @Email private String email; @NotBlank @Size(min = 8, max = 20) private String password; @NotBlank @Size(min = 2) private String name;} 위와 같이 DTO를 만들고 @PostMapping("createUser")public Result<UserResponse> createUser(@RequestBody @Valid UserCreateRequest request) throws NotFoundException { return Result.success(userService.createUser(request));} 컨트롤러에서 @Valid 어노테이션을 줘서 회원가입을 검증하도록 했습니다. 저는 LoginRequest와 UserCreateRequest의 fieldName이 같고 제약 조건도 거의 똑같다고 생각해서 message 처리를 범용성 있게 하면 좋겠다고 생각했고 그래서 validation-properties를 만들고 그 안에 errorCode + objectName + fieldName 보다는 errorCode + fieldName에 관한 메세지 처리를 했는데요 yml server: port: 8060spring: application: name: potato-velog-user datasource: url: jdbc:h2:mem:testdb driver-class-name: org.h2.Driver h2: console: enabled: true settings: web-allow-others: true path: /h2-console messages: basename: validation encoding: UTF-8eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:8761/eureka validation-properties NotBlank.email = 이메일을 입력해주세요.NotBlank.password = 비밀번호를 입력해주세요.NotBlank.name = 이름을 입력해주세요Size.email = 이메일은 최소 {0}글자 이상이어야 합니다.Size.password = 비밀번호는 최소 {0}글자 최대 {1}글자 이하여야 합니다.Size.name = 이름은 최소 {0}글자 이상이어야 합니다.Email = 이메일 형식이어야 합니다.NotBlank = 공백 안돼요Size = 사이즈 지키세요 그리고 나서 저는 postMan을 이용해 검증을 시도해 봤는데 { "email" : "aaa@naver.com", "password" : "11111111", "name" : "a" } 제가 예상했던건 UserCreateRequest의 name이 Size 조건을 만족하지 못헀기 때문에 Size.name에 관한 메세지(이름은 최소 2글자 이상이어야 합니다) 가 나올거라 생각했는데 Validation failed for argument [0] in public com.velog.veloguser.domain.utils.Result<com.velog.veloguser.domain.dto.response.UserResponse> com.velog.veloguser.controller.UserController.createUser(com.velog.veloguser.domain.dto.request.UserCreateRequest) throws javassist.NotFoundException: [Field error in object 'userCreateRequest' on field 'name': rejected value [a]; codes [Size.userCreateRequest.name,Size.name,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userCreateRequest.name,name]; arguments []; default message [name],2147483647,2]; default message [크기가 2에서 2147483647 사이여야 합니다]] 위와 같이 DefaultMessage가 '크기가 2에서 2147483647 사이여야 합니다' 라고 나옵니다. 저는 왜 메세지가 저렇게 나오는지 이해가 안가고 만약 Size.name에 관한 메세지를 찾지 못했더라도 Size = 사이즈 지키세요 라는 메세지가 validation-properties에 있기 때문에 '사이즈 지키세요' 라는 메세지가 출력되었어야 하는거 아닌가요?