묻고 답해요
161만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 핵심 원리 - 기본편
의존관계 자동 주입 강의 관련 질문
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]의존관계 자동 주입 부분 강의듣고 있는데요 생성자 주입이랑 수정자 주입부분 설명하실때 코드에 this.memberRepository = memberRepository;이런 코드가 존재하는데 이는 필드값을 변경하는거 아닌가요?? 싱클톤 컨테이너 강의에서 싱글톤 방식의 주의점에서 특정 클라이언트가 값을 변경할수 있는 필드가 있으면 안된다고 하셨는데 그러면 위의 코드처럼 쓰면 안되는거 아닌가요??
-
미해결스프링 핵심 원리 - 기본편
수정자 주입
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]수정자 주입 부분 강의에서setter함수에 print문을 넣었을때 @Autowired 를 붙이면 프린트문이 출력이 되는데 @Autowired를 안 붙이면 프린트문이 출력이 안된다고 하셨는데 왜 그런건가요??AutoAppConfigTest를 실행시켰을때 setter 함수를 호출하지 않았는데 OrderServiceImpl에서 @Autowired를 붙여 수정자 주입을 붙였을때 setter의 프린트문이 출력되는 원리는 무엇인가요??
-
미해결스프링 핵심 원리 - 기본편
의존관계 자동 주입 - 생성자 주입
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]생성자 주입 부분에서 생성자 주입을 이용하면 setter 메서드를 쓰면 안된다고 하셨는데 왜 그런건가요??생성자 주입을 하면 setter 메서드는 아예 못쓰는 건가요???
-
미해결스프링 핵심 원리 - 기본편
싱글톤 패턴 문제점에 대해
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다.클라이언트 코드에서 getInstance() 메소드를 이용해서 싱글톤을 이용한다면 구체 클래스를 의존하므로 DIP에 위반된다. (AppConfig와 같이 설정 정보 클래스를 사용하지 않는 것을 전제)3. 생성자가 private로 자식 클래스를 만들기 어렵다.4. 클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높다. (AppConfig와 같이 설정 정보 클래스를 사용하지 않는 것을 전제)5. 내부 속성을 변경하거나 초기화 하기 어렵다.6. 테스트하기 어렵다.여기서 5, 6 부분이 잘 이해가 잘 되지 않는데예시를 보여줄 수 있을까요?
-
해결됨스프링 핵심 원리 - 기본편
아직 자동, 수동 실무 운영 기준이 안 와닿아요.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]저는 그래도 한 눈에 볼 수 있는 AppCofig가 더 좋은 것 같아요. 아직 배우는 중이고, 실무 경험이 없어서 그런거겠죠? 실무 경험이 많으시니 보통 Service, Repository, Controller같은 거는 거기서 거기이니 그러신 거겠죠? 저는 @Service, @Repository, @Cotroller는 최상단에 놓고, 나머지는 아래쪽에 넣고 줄바꿈 좀 해주고 주석 좀 넣어주고 그런 식으로 하는 게 좋을 것 같아요. rate fixed 같은 경우는 강의대로 따로 모아두고 ApplicationContext에 인자로 여러 개 추가할 수 있으니까..
-
미해결스프링 핵심 원리 - 기본편
컴포넌트 스캔 관련 질문
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]컴포넌트 스캔 강의를 듣다 질문이 있는데요 @ComponentScan 을 쓰면 @Configuration도 꼭 써줘야 되나요 아니면 그냥 @ComponentScan만 써도 되는건가요??? 두 개의 어노테이션의 차이는 뭔가요?그리고 앞선 강의인 싱글톤 컨테이너에서 @Configuration 과 @Bean 을 이용했을땐 따로 @Autowired 안써서 의존관계를 주입을 안해줬는데 그때는 따로 의존관계를 주입하지 않아도 되나요??
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
블로그 포스팅 관련 문의
안녕하세요 강사님먼저 좋은 강의 만들어주셔서 감사드립니다. 다름이 아니라 혹시 강의 내용과 pdf 강의 자료를 개인 블로그에 정리해서올려도 되는지 여쭙고자 글 남겨드렸습니다.다른 분들과 공유보다는 스스로 복습하는 용도로 글을 작성하는 목적이 크지만 인터넷에 올라오는 내용인 만큼 먼저 허락을 구하고자 합니다.최대한 지양하겠지만 가끔씩 강의 혹은 pdf 파일 속 그림이나 사진을 올리는 경우가 있을 수도 있을 것 같습니다만 이 때는 당연히 출처를 남기겠습니다.만약 불가하시다면 비공개 처리하여 공유 및 열람이 안 되도록 조치해놓겠습니다.감사합니다.
-
해결됨스프링 핵심 원리 - 기본편
@configuration 싱글톤
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]싱글톤으로 등록이 되는 이유는 AutoAppConfig에 @Configuration이 붙었기 때문인가요?
-
해결됨스프링 핵심 원리 - 기본편
ac.getBeansOfType(Object.class);
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]스프링 컨테이너에 설정 정보를 넣어주고 이를 기반으로 테이블을 만드는 것으로 인지했습니다.현재 AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class); 와 같이 설정하였고obj클래스는 스프링 컨테이너에 설정 정보를 넣어주지 않았는데 컨테이너 안에 왜 obj 빈이 존재하며 getBeansOfType을 할 수 있는 이유가 궁금합니다.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
MemberController 러닝 에러
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]4분 쯤에 강사님께서 @Autowired 설명하셨을 때 생성자의 파라미터인 memberService에 빨간 밑줄 에러표시가 떴는데 저는 그게 뜨지도 않았고, HelloSpringApplication을 실행하면 강사님과는 다르게 붉은 글씨들이 뜨네요.. 뭐가 잘못된 건지 모르겠습니다..
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
회원서비스테스트강의중 회원가입 테스트에 대한 궁금증이 생겨서 질문드립니다.
회원가입 테스트를 진행할때 밑에 검증하는 부분에서 궁금증이 생겼습니다. 강의상에서는 제가 작성한 부분에서는 findOneMember라는 회원의 이름을 이용하여 검증을 하고 있는걸로 알고 있습니다. 하지만 제가 추가로 작성한 마지막 줄에 있는 검증 코드처럼 findOneMember라는 회원의 이름으로 접근하지 않고 when부분에서 도출한 joinId와 given부분에서 생성한 기대하는 회원의 id를 이용하여 검증을 하면 혹시 안되는지 여쭈어보고 싶습니다. 추가로 이렇게 검증을 할 때 어떤 것을 검증하냐는 개발자의 마음인지도 궁금합니다. 감사합니다.
-
미해결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 2편 - 백엔드 웹 개발 활용 기술
ExceptionHandler와 BasicErrorController에 대한 궁금증
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? [질문 내용]안녕하세요. 강의를 듣던 도중 궁금한 점이 생겨 질문을 남겨 봅니다.API 예외를 처리할 때는 ExceptionHandler를 사용하여 처리하고,HTML 화면을 제공할 때 예외 처리는 BasicErrorController를 사용하는게 편하다고 강의에서 말씀해주셨는데요@Controller @Slf4j public class TestErrorController { @ExceptionHandler(IllegalArgumentException.class) @ResponseBody public ErrorResult IllegalArgumentException(IllegalArgumentException e) { log.info("IllegalArgumentException ", e); return new ErrorResult("BAD Argument", e.getMessage()); } @GetMapping("/test/error/{id}") public String testException(@PathVariable String id) { if (id.equals("bad")) { throw new IllegalArgumentException("bad argument"); } return "home"; } @GetMapping("/test/error2/{id}") @ResponseBody public String testException2(@PathVariable String id) { if (id.equals("bad")) { throw new IllegalArgumentException("bad argument"); } return "OK"; } }위와 같이 RestController가 아닌 Controller에서View를 반환해주는 메서드가 있고, HTTP 메시지바디에 문자열을 반환해주는 메서드가 있는 상태에서API 예외를 처리하는 @ExceptionHandler를 작성 하였고 테스트를 위해/test/error/bad, /test/error2/bad를 호출해보면 둘 다 @ExceptionHandler가 예외를 처리하여 JSON 문자열이 반환되어 지더라구요..여기서 궁금점이 생기게 되었는데요위와 같이 하나의 컨트롤러에서 View를 반환해주었을 때 IllegalArgumentException이 발생했다면 BasicErrorController처럼 오류페이지를 반환하고,API 의 경우 IllegalArgumentException이 발생하면 @ExceptionHandler에서 처리를 할 수 있는 방법은 없는 걸까요??만약 위의 질문에 대한 답이 없다 라고 한다면 실무에서 개발 설계를 할 때, API 컨트롤러와 View를 반환해주는 컨트롤러를 분리하여 설계를 하나요?
-
해결됨스프링 핵심 원리 - 기본편
Map<String, DiscountPolicy> 등록될 때 String
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]Map에 DiscountPolicy 주입될 때, getBean하는거랑 비슷하잖아요. 이 때 String도 자동으로 넣어주는.. 그런 부분이 잘.. 안 와닿아서요. 그러니까 Map 자체는 Key가 필요하기 때문에, 자동으로 맵 자체가 그러니까 따지자면 getBean(DiscountPolicy.class).toString()해서 자체적으로 넣어주는 거죠? 이걸 Map<>이 실행해주는거죠?
-
미해결스프링 시큐리티 OAuth2
소셜 로그인 후 JWT 발급과 요청 시 access token담아 보내기 에러
https://github.com/YuYoHan/project_study1 전체 링크입니다. 일단, 시큐리티 컨피그 중 Oauth2에 관련된 부분입니다. 방식은 REST 방식입니다. http // oauth2Login() 메서드는 OAuth 2.0 프로토콜을 사용하여 소셜 로그인을 처리하는 기능을 제공합니다. .oauth2Login() // .defaultSuccessUrl("/success-oauth") // OAuth2 로그인 성공 이후 사용자 정보를 가져올 때 설정 담당 .userInfoEndpoint() // OAuth2 로그인 성공 시, 후작업을 진행할 서비스 .userService(principalOauth2UserService) .and() .defaultSuccessUrl("/success-oauth"); 저는 현재 생각하는 방식이 소셜 로그인을 성공하면 PrincipalOauth2UserService 에서 Member 테이블에 넣어주고 save까지 해서 로직을 구현했습니다. 그리고 실행해본 결과 로그로 제대로 값이 등록되어 있는 것을 볼 수 있었습니다.package com.example.project1.config.oauth2; import com.example.project1.config.auth.PrincipalDetails; import com.example.project1.config.oauth2.provider.GoogleUserInfo; import com.example.project1.config.oauth2.provider.NaverUserInfo; import com.example.project1.config.oauth2.provider.OAuth2UserInfo; import com.example.project1.domain.member.UserType; import com.example.project1.entity.member.MemberEntity; import com.example.project1.repository.member.MemberRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Service; import java.util.Map; @Service @Slf4j @RequiredArgsConstructor public class PrincipalOauth2UserService extends DefaultOAuth2UserService { private final BCryptPasswordEncoder bCryptPasswordEncoder; private final MemberRepository memberRepository; // 구글로부터 받은 userReuest 데이터에 대한 후처리되는 함수 @Override public PrincipalDetails loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { // registrationId로 어떤 OAuth로 로그인 했는지 확인가능 log.info("clientRegistration : " + userRequest.getClientRegistration() ); log.info("accessToken : " + userRequest.getAccessToken().getTokenValue() ); OAuth2User oAuth2User = super.loadUser(userRequest); // 구글 로그인 버튼 클릭 →구글 로그인 창 → 로그인 완료 → code 를 리턴(OAuth-Client 라이브러리) → AccessToken 요청 // userRequest 정보 → 회원 프로필 받아야함(loadUser 함수 호출) → 구글로부터 회원 프로필을 받아준다. log.info("getAttributes : " + oAuth2User.getAttributes()); // 회원가입을 강제로 진행 OAuth2UserInfo oAuth2UserInfo = null; if(userRequest.getClientRegistration().getRegistrationId().equals("google")) { log.info("구글 로그인 요청"); oAuth2UserInfo = new GoogleUserInfo(oAuth2User.getAttributes()); } else if(userRequest.getClientRegistration().getRegistrationId().equals("naver")) { log.info("네이버 로그인 요청"); // 네이버는 response를 json으로 리턴을 해주는데 아래의 코드가 받아오는 코드다. // response={id=5SN-ML41CuX_iAUFH6-KWbuei8kRV9aTHdXOOXgL2K0, email=zxzz8014@naver.com, name=전혜영} // 위의 정보를 NaverUserInfo에 넘기면 oAuth2UserInfo = new NaverUserInfo((Map)oAuth2User.getAttributes().get("response")); } else { log.info("구글과 네이버만 지원합니다."); } // 사용자가 로그인한 소셜 서비스(provider)를 가져옵니다. // 예를 들어, "google" 또는 "naver"와 같은 값을 가질 수 있습니다. String provider = oAuth2UserInfo.getProvider(); // 사용자의 소셜 서비스(provider)에서 발급된 고유한 식별자를 가져옵니다. // 이 값은 해당 소셜 서비스에서 유니크한 사용자를 식별하는 용도로 사용됩니다. String providerId = oAuth2UserInfo.getProviderId(); // 예) google_109742856182916427686 String userName = provider + "_" + providerId; String password = bCryptPasswordEncoder.encode("get"); // 사용자의 이메일 주소를 가져옵니다. 소셜 서비스에서 제공하는 이메일 정보를 사용합니다. String email = oAuth2UserInfo.getEmail(); // 사용자의 권한 정보를 설정합니다. UserType. // 여기서는 소셜로그인으로 가입하면 무조건 User로 권한을 주는 방식으로 했습니다. UserType role = UserType.USER; // 이메일 주소를 사용하여 이미 해당 이메일로 가입된 사용자가 있는지 데이터베이스에서 조회합니다. MemberEntity member = memberRepository.findByUserEmail(email); if(member == null) { log.info("OAuth 로그인이 최초입니다."); log.info("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓"); log.info("OAuth 자동 회원가입을 진행합니다."); member = MemberEntity.builder() .userName(userName) .userPw(password) .userEmail(email) .userType(role) .provider(provider) .providerId(providerId) .build(); log.info("userEmail : " + member.getUserEmail()); log.info("userName : " + member.getUserName()); log.info("userPw : " + member.getUserPw()); log.info("userType : " + member.getUserType()); log.info("provider : " + member.getProvider()); log.info("providerId : " + member.getProviderId()); memberRepository.save(member); } else { log.info("로그인을 이미 한적이 있습니다. 당신은 자동회원가입이 되어 있습니다."); log.info("userEmail : " + member.getUserEmail()); log.info("userName : " + member.getUserName()); log.info("userPw : " + member.getUserPw()); log.info("userType : " + member.getUserType()); log.info("provider : " + member.getProvider()); log.info("providerId : " + member.getProviderId()); } // attributes가 있는 생성자를 사용하여 PrincipalDetails 객체 생성 // 소셜 로그인인 경우에는 attributes도 함께 가지고 있는 PrincipalDetails 객체를 생성하게 됩니다. return new PrincipalDetails(member, oAuth2User.getAttributes()); } } 이제 @AuthenticationPrincipal OAuth2User oAuth2User를 사용하면 소셜 로그인한 정보를 가져와서 JWT 발급하는데 사용할 수 있다고 들었는데 @GetMapping("/success-oauth") public ResponseEntity<?> createTokenForGoogle(@AuthenticationPrincipal OAuth2User oAuth2User) { if(oAuth2User == null) { log.info("받아올 정보가 없습니다 ㅠㅠ"); return ResponseEntity.status(HttpStatus.NOT_FOUND).body("정보가 없어...."); } else { log.info("oauth2User 정보를 받아오자 : " + oAuth2User); // OAuth2User에서 필요한 정보를 추출하여 UserDetails 객체를 생성합니다. ResponseEntity<TokenDTO> token = memberService.createToken(oAuth2User); log.info("token : " + token); return ResponseEntity.ok().body(token); } }@AuthenticationPrincipal OAuth2User oAuth2User를 사용해서 정보를 받아와서 null이 아닐 경우MemberService // 소셜 로그인 성공시 jwt 반환 // OAuth2User에서 필요한 정보를 추출하여 UserDetails 객체를 생성하는 메서드 public ResponseEntity<TokenDTO> createToken(OAuth2User oAuth2User) { String userEmail = oAuth2User.getAttribute("email"); log.info("userEmail in MemberService : " + userEmail); MemberEntity findMember = memberRepository.findByUserEmail(userEmail); // 권한 정보 추출 List<GrantedAuthority> authorities = getAuthoritiesForUser(findMember); // UserDetails 객체 생성 (사용자의 아이디 정보를 활용) // 첫 번째 인자 : username 사용자 아이디 // 두 번째 인자 : 사용자의 비밀번호 // 세 번째 인자 : 사용자의 권한 정보를 담은 컬렉션 UserDetails userDetails = new User(userEmail, null, authorities); log.info("userDetails in MemberService : " + userDetails); TokenDTO token = jwtProvider.createToken2(userDetails); log.info("token in MemberService : " + token); return ResponseEntity.ok().body(token); } private List<GrantedAuthority> getAuthoritiesForUser(MemberEntity member) { // 예시: 데이터베이스에서 사용자의 권한 정보를 조회하는 로직을 구현 // member 객체를 이용하여 데이터베이스에서 사용자의 권한 정보를 조회하는 예시로 대체합니다. UserType role = member.getUserType(); // 사용자의 권한 정보를 가져오는 로직 (예시) List<GrantedAuthority> authorities = new ArrayList<>(); authorities.add(new SimpleGrantedAuthority("ROLE_" +role.name())); log.info("role in MemberService : " + role.name()); log.info("authorities in MemberService : " + authorities); return authorities; }JwtProvider public TokenDTO createToken2(UserDetails userDetails) { long now = (new Date()).getTime(); Date now2 = new Date(); // userDetails.getAuthorities()는 사용자의 권한(authorities) 정보를 가져오는 메서드입니다. // claims.put("roles", userDetails.getAuthorities()) 코드는 사용자의 권한 정보를 클레임에 추가하는 것입니다. // 클레임에는 "roles"라는 키로 사용자의 권한 정보가 저장되며, 해당 권한 정보는 JWT의 페이로드 부분에 포함됩니다. Claims claims = Jwts.claims().setSubject(userDetails.getUsername()); claims.put("auth", userDetails.getAuthorities()); log.info("claims : " + claims); // access token Date accessTokenExpire = new Date(now + this.accessTokenTime); String accessToken = Jwts.builder() .setSubject(userDetails.getUsername()) .setClaims(claims) .setIssuedAt(now2) .setExpiration(accessTokenExpire) .signWith(key,SignatureAlgorithm.HS256) .compact(); // RefreshToken 생성 Date refreshTokenExpire = new Date(now + this.refreshTokenTime); String refreshToken = Jwts.builder() .setIssuedAt(now2) .setClaims(claims) .setExpiration(refreshTokenExpire) .signWith(key, SignatureAlgorithm.HS256) .compact(); return TokenDTO.builder() .grantType("Bearer ") .accessToken(accessToken) .refreshToken(refreshToken) .userEmail(userDetails.getUsername()) .build(); }이런식으로 로직을 짰는데 지금 생각하는 방식이 소셜 로그인이 성공했을 경우 주소, 권한(USER or ADMIN) 를 추가적으로 넣고 싶은데 소셜 로그인으로 어떻게 해야할지 감이 안잡힙니다 ㅠㅠ 그리고 컨트롤러에서 제대로 정보를 못가지고 오는거 같습니다.PrincipalOauth2UserService에서 return new PrincipalDetails(member, oAuth2User.getAttributes());이렇게 보내줬는데 PrincipalDetails에서package com.example.project1.config.auth; import com.example.project1.entity.member.MemberEntity; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.oauth2.core.user.OAuth2User; import java.util.ArrayList; import java.util.Collection; import java.util.Map; @Setter @Getter @ToString @NoArgsConstructor @Slf4j public class PrincipalDetails implements UserDetails, OAuth2User { // 일반 로그인 정보를 저장하기 위한 필드 private MemberEntity member; // OAuth2 로그인 정보를 저장하기 위한 필드 // attributes는 Spring Security에서 OAuth2 인증을 수행한 후에 사용자에 대한 추가 정보를 저장하는 데 사용되는 맵(Map)입니다. // OAuth2 인증은 사용자 인증 후에 액세스 토큰(Access Token)을 발급받게 되는데, // 이 토큰을 사용하여 OAuth2 서비스(provider)로부터 사용자의 프로필 정보를 요청할 수 있습니다. // 예를 들어, 소셜 로그인을 사용한 경우에는 attributes에는 사용자의 소셜 서비스(provider)에서 제공하는 프로필 정보가 담겨 있습니다. // 소셜 로그인 서비스(provider)마다 제공하는 프로필 정보가 다를 수 있습니다. // 일반적으로 attributes에는 사용자의 아이디(ID), 이름, 이메일 주소, 프로필 사진 URL 등의 정보가 포함됩니다. /* * 구글의 경우 * { "sub": "100882758450498962866", // 구글에서 발급하는 고유 사용자 ID "name": "John Doe", // 사용자 이름 "given_name": "John", // 이름(이름 부분) "family_name": "Doe", // 성(성(성) 부분) "picture": "https://lh3.googleusercontent.com/a/AAcHTtdzQomNwZCruCcM0Eurcf8hAgBHcgwvbXEBQdw3olPkSg=s96-c", // 프로필 사진 URL "email": "johndoe@example.com", // 이메일 주소 "email_verified": true, // 이메일 주소 인증 여부 "locale": "en" // 지역 설정 } * */ private Map<String, Object> attributes; // 일반 로그인 public PrincipalDetails(MemberEntity member) { this.member = member; } // OAuth2 로그인 public PrincipalDetails(MemberEntity member, Map<String, Object> attributes) { this.member = member; this.attributes = attributes; } // 해당 유저의 권한을 리턴하는 곳 @Override public Collection<? extends GrantedAuthority> getAuthorities() { Collection<GrantedAuthority> collection = new ArrayList<>(); collection.add(new SimpleGrantedAuthority("ROLE_" + member.getUserType().toString())); log.info("collection : " + collection); return collection; } // 사용자 패스워드를 반환 @Override public String getPassword() { return member.getUserPw(); } // 사용자 이름 반환 @Override public String getUsername() { return member.getUserEmail(); } // 계정 만료 여부 반환 @Override public boolean isAccountNonExpired() { // 만료되었는지 확인하는 로직 // true = 만료되지 않음 return true; } // 계정 잠금 여부 반환 @Override public boolean isAccountNonLocked() { // true = 잠금되지 않음 return true; } // 패스워드의 만료 여부 반환 @Override public boolean isCredentialsNonExpired() { // 패스워드가 만료되었는지 확인하는 로직 // true = 만료되지 않음 return true; } // 계정 사용 가능 여부 반환 @Override public boolean isEnabled() { // 계정이 사용 가능한지 확인하는 로직 // true = 사용 가능 return true; } @Override public Map<String, Object> getAttributes() { return attributes; } @Override // OAuth2 인증에서는 사용되지 않는 메서드이므로 null 반환 public String getName() { return null; } }생성자를 구현했지만 컨트롤러에서 못받고 있습니다. 추가 질문)postman에서 소셜로그인 테스트를 해서 성공해서 accesstoken을 받았는데 거기서 뭘 어떻게 진행해야 하나요? 거기서 소셜 로그인을 성공하면 바로 토큰을 발급해줘서 요청시 header에 담아서 보내주것을 어떤식으로 해야하나요??추가 질문2)소셜 로그인은 아니지만 발급 받은 access token을 header에 담아서 보내주는 것을 하는 도중java.lang.IllegalArgumentException: Cannot pass null or empty values to constructor at org.springframework.util.Assert.isTrue(Assert.java:121) ~[spring-core-5.3.28.jar:5.3.28] at org.springframework.security.core.userdetails.User.<init>(User.java:110) ~[spring-security-core-5.7.9.jar:5.7.9] at org.springframework.security.core.userdetails.User.<init>(User.java:87) ~[spring-security-core-5.7.9.jar:5.7.9] at com.example.project1.config.jwt.JwtProvider.getAuthentication(JwtProvider.java:231) ~[classes/:na] at com.example.project1.config.jwt.JwtAuthenticationFilter.doFilter(JwtAuthenticationFilter.java:62) ~[classes/:na] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:223) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.28.jar:5.3.28] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.28.jar:5.3.28] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:112) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.28.jar:5.3.28] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.28.jar:5.3.28] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:221) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) ~[spring-web-5.3.28.jar:5.3.28] at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) ~[spring-web-5.3.28.jar:5.3.28] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.28.jar:5.3.28] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.28.jar:5.3.28] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.28.jar:5.3.28] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.28.jar:5.3.28] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:661) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:427) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:357) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:294) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:373) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:237) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:319) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na] 2023-07-22 18:49:55.024 ERROR 11616 --- [nio-8080-exec-6] o.a.c.c.C.[Tomcat].[localhost] : Exception Processing ErrorPage[errorCode=0, location=/error] java.lang.IllegalArgumentException: Cannot pass null or empty values to constructor at org.springframework.util.Assert.isTrue(Assert.java:121) ~[spring-core-5.3.28.jar:5.3.28] at org.springframework.security.core.userdetails.User.<init>(User.java:110) ~[spring-security-core-5.7.9.jar:5.7.9] at org.springframework.security.core.userdetails.User.<init>(User.java:87) ~[spring-security-core-5.7.9.jar:5.7.9] at com.example.project1.config.jwt.JwtProvider.getAuthentication(JwtProvider.java:231) ~[classes/:na] at com.example.project1.config.jwt.JwtAuthenticationFilter.doFilter(JwtAuthenticationFilter.java:62) ~[classes/:na] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:223) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.28.jar:5.3.28] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.28.jar:5.3.28] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:112) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.28.jar:5.3.28] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.28.jar:5.3.28] at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:221) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186) ~[spring-security-web-5.7.9.jar:5.7.9] at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) ~[spring-web-5.3.28.jar:5.3.28] at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) ~[spring-web-5.3.28.jar:5.3.28] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.28.jar:5.3.28] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.28.jar:5.3.28] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.28.jar:5.3.28] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) ~[spring-web-5.3.28.jar:5.3.28] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:661) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:427) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:357) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:294) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:373) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:237) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:319) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.76.jar:9.0.76] at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na] 이런 에러가 발생합니다....보니까 public Authentication getAuthentication(String token) { // 토큰 복호화 메소드 Claims claims = parseClaims(token); log.info("claims in JwtProvider : " + claims); if(claims.get("auth") == null) { throw new RuntimeException("권한 정보가 없는 토큰입니다."); } Object auth = claims.get("auth"); log.info("auth in JwtProvider : " + auth); // 클레임 권한 정보 가져오기 List<String> authorityStrings = (List<String>) claims.get(AUTHORITIES_KEY); Collection<? extends GrantedAuthority> authorities = authorityStrings.stream() .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); // UserDetails 객체를 만들어서 Authentication 리턴 UserDetails principal = new User(claims.getSubject(), "", authorities); return new UsernamePasswordAuthenticationToken(principal, token, authorities); } 여기서 오류가 생기는거 같습니다. log.info("auth in JwtProvider : " + auth); 찍으면 auth in JwtProvider : [ROLE_USER] 이렇게 나옵니다
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
타임리프 파서 주석 궁금증
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]보면 <!--/* ... /--> 이 있고, <!--/*--> ... <!--*/--> 이 있는데, 본문에서는 그냥 한줄표현, 여러줄 표현이라고 하셨는데, 제가 해보니까 그런 차이는 아닌것 같더라구요.<!--/* ... */--> : 아예 소스 상 주석처리 상태. 그래서 절대경로로 열어도 뷰에는 안나옴<!--/*--> ... <!--*/--> : 소스상으론 주석처리 안된상태. 그래서 절대경로로 열면 뷰에 보임이렇게 해석했는데 맞는 내용일까요?
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
default_batch_fetch_size 크기 질문
강의에서default_batch_fetch_size가 100이고,OrderItem의 크기는 2개,Item의 크기는 4개 입니다default_batch_fetch_size를 정할때 OrderItem의 크기와 Item의 크기를 더한 값인가요? 아니면 OrderItem의 크기만 인건가요?
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
로그인 필터질문
로그인 필터 로직에서 if(session == null || session.getAttributes~~뒤에 조건은 왜 필요한가요??
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
메인 오류
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.실행시키면 실행이 되다가 갑자기 이런 오류가 뜹니다... 설정이나 설치 등은 그대로 따라했습니다.
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
질문있습니다
강사님이 올려주신 파일이 아니라 Spring Initializr여기서 직접 생성한 다음에 프로젝트를 진행하려고 하는데 이노테이션 ?에노테이션이 안먹습니다.. 아마 그래들 파일 문제인것 같은데 강사님 올려주신 동영상에는 그래들파일 수정하라는 말은 없었거든요 ;; 빠른답변 부탁드립니다 그리고 MYSQL 설치할떄도 디폴트디벨로퍼 항목이 없습니다;; 강좌 왜이런지 ;;