학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. isEmpty() 메서드 관련해서 제네릭은 실행 시점에 타입이 정해지는데 단순 null 인지만 확인하는것이 아닌 기본형,참조형 각각의 타입별로 비어있는지를 구현해야 하지 않나 싶습니다. 아래와 같이 test를 해보면 잘못된 값이 나옵니다. public class ContainerTest { public static void main(String[] args) { Container<Integer> integerContainer = new Container<>(); System.out.println("빈값 확인1: " + integerContainer.isEmpty()); } }
학습 관련 질문을 최대한 상세히 남겨주세요! 고민 과정도 같이 나열해주셔도 좋습니다. 먼저 유사한 질문이 있었는지 검색해보세요. 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 해당 강의 마지막 부분의 handleEventIfScoreUpdatedEventTest()에서 given(event.getType()).willReturn(mock(EventType.class)); 위의 코드로 test하신 이유가 단순히 게시글 생성과 게시글 삭제만 아니면 되어서, 그냥 아무 class로 테스트하신게 맞으실까요?? 아래 코드로도 가능하긴 하지만 그냥 게시글 생성과 게시글 삭제만 아니면, test 가능하니로 이해하면 될까요? given(event.getType()).willReturn(EventType.ARTICLE_UPDATED);
1 의문 ................................................ 강의 내용중에서 oauth2Login(Customizer.withDefaults()) 없이 oauth2Client(Customizer.withDefaults()) 만 사용한 경우에는 인가 처리만 하기 때문에 따로 인증 처리를 해주는 과정을 보여주셨는데 2 배경지식 ................................................ oauth2Client 와 oauth2Login 의 차이는 1단계 처리 필터 : OAuth2AuthorizationRequestRedirectFilter 로 동일 2단계 를 처리필터: OAuth2LoginAuthenticationFilter 대신 여기선 OAuth2AuthorizationCodeGrantFilter 사용 즉 OAuth2LoginAuthenticationFilter 를 거치지않아 OAuth2LoginAuthenticationFilter에서 사용하는 OidcAuthorizationCodeAuthenticationProvider에서 IdToken 을 추출해 OidcIdToken를 만들고 OidcUser 를 로드하는 부분의 유무가 핵심적인 차이라고 생각이드는데요 그리고 OAuth2User는 인가 개념만 있지 인증 개념은 없다고 들었습니다 3 질문 ....................................................... 단순히 OAuth2User를 만들어 OAuth2AuthenticationToken을 SecurityContextHolder에 수동 저장한다고 해서 "인증된 사용자"로 간주되는 않아서 로그아웃도 제대로 동작하지 않습니다 . 물론 스프링 시큐리티 자체에서 세션,쿠키,SecurityContextHolder에 강제로 저장한 Authentication 없애기를 통해 일부는 처리는 되지만 질문1 : keycloak 에서의 실제 세션은 로그아웃을 못하지않나요 ? @GetMapping("/logout") public String logout( HttpServletRequest request, HttpServletResponse response){ Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); // 로그아웃 처리 SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler(); logoutHandler.logout(request, response, authentication); // 로그아웃 요청을 위한 Keycloak 로그아웃 URL String logoutUrl = "http://localhost:8080/realms/oauth2/protocol/openid-connect/logout"; // 로그아웃 후 리디렉션할 URI String redirectUri = "http://localhost:8081/login"; // 로그아웃 후 돌아올 URL // 실제 ID Token을 가져오는 코드 // 로그아웃 URL에 필요한 파라미터들을 추가 String logoutRequestUrl = logoutUrl + "?id_token_hint=" + idTokenHint + "&post_logout_redirect_uri=" + redirectUri; // 로그아웃 요청을 Keycloak으로 리디렉션 return "redirect:" + logoutRequestUrl; } 이런식으로 강제로 형식 만들려고 해도 mvc 에서 id_token을 참조할 수 있는 방법이없습니다 . 디버깅으로 확인해보니 scope 에 openId 를 추가해서 id_token이 있을거라고 생각했는데 OAuth2AuthorizationCodeGrantFilter의 OAuth2AuthorizationCodeGrantFilter에서 authenticationResult 에 additionalParameters = {HashMap@7785} size = 4 "id_token" -> "ㅁㄴㅇㄹㄴㅇㅁㄻㄴㅇㅁㄴㅇㄹ" "session_state" -> "7a3b7dbb-ec62-4a07-8ef8-f67b17b2f3ac" "refresh_expires_in" -> {Integer@7818} 1800 "not-before-policy" -> {Integer@7820} 1746349855 이런식으로 있긴하지만 사용하지않고 authenticationResult로부터 authenticationResult.getClientRegistration() 추출해서 OAuth2AuthorizedClient 만들어서 저장하고 끝내내요 private void processAuthorizationResponse(HttpServletRequest request, HttpServletResponse response) throws IOException { OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestRepository.removeAuthorizationRequest(request, response); String registrationId = (String)authorizationRequest.getAttribute("registration_id"); ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId); MultiValueMap<String, String> params = OAuth2AuthorizationResponseUtils.toMultiMap(request.getParameterMap()); String redirectUri = UrlUtils.buildFullRequestUrl(request); OAuth2AuthorizationResponse authorizationResponse = OAuth2AuthorizationResponseUtils.convert(params, redirectUri); OAuth2AuthorizationCodeAuthenticationToken authenticationRequest = new OAuth2AuthorizationCodeAuthenticationToken(clientRegistration, new OAuth2AuthorizationExchange(authorizationRequest, authorizationResponse)); authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request)); OAuth2AuthorizationCodeAuthenticationToken authenticationResult; try { authenticationResult = (OAuth2AuthorizationCodeAuthenticationToken)this.authenticationManager.authenticate(authenticationRequest); } catch (OAuth2AuthorizationException var16) { OAuth2AuthorizationException ex = var16; OAuth2Error error = ex.getError(); UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(authorizationRequest.getRedirectUri()).queryParam("error", new Object[]{error.getErrorCode()}); if (StringUtils.hasLength(error.getDescription())) { uriBuilder.queryParam("error_description", new Object[]{error.getDescription()}); } if (StringUtils.hasLength(error.getUri())) { uriBuilder.queryParam("error_uri", new Object[]{error.getUri()}); } this.redirectStrategy.sendRedirect(request, response, uriBuilder.build().encode().toString()); return; } Authentication currentAuthentication = this.securityContextHolderStrategy.getContext().getAuthentication(); String principalName = currentAuthentication != null ? currentAuthentication.getName() : "anonymousUser"; OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(authenticationResult.getClientRegistration(), principalName, authenticationResult.getAccessToken(), authenticationResult.getRefreshToken()); this.authorizedClientRepository.saveAuthorizedClient(authorizedClient, currentAuthentication, request, response); String redirectUrl = authorizationRequest.getRedirectUri(); SavedRequest savedRequest = this.requestCache.getRequest(request, response); if (savedRequest != null) { redirectUrl = savedRequest.getRedirectUrl(); this.requestCache.removeRequest(request, response); } this.redirectStrategy.sendRedirect(request, response, redirectUrl); } 질문 2 : 강의(OAuth2AuthorizedClient 이해 및 활용)에서는 OAuth2User를 만들어 OAuth2AuthenticationToken 을 저장하는 식으로 처리하셨는데 수업을 듣다 보니 이렇게 처리한 이유가 궁금해 질문 드립니다 .
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 이 부분 관련해서 반복적으로 학습중인데 이해가 잘 되지 않아 질문드립니다! /* 취소 */ @Transactional public void cancelOrder(Long orderId) { //주문 엔티티 조회 Order order = orderRepository.findOne(orderId); //주문취소 order.cancel(); } 이 부분에서 orderId "주문 PK" 를 인자로 받아 주문에 대한 데이터 order 를 조회해왔습니다. 그다음 order.cancel(); 메서드를 호출하는데 해당 메서드에는 파라미터로 아무것도 넣지 않았습니다. //==비즈니스 로직==// /** * 주문 취소 */ public void cancel(){ if (delivery.getStatus() == DeliveryStatus.COMP) { throw new IllegalStateException("이미 배송완료된 상품은 취소가 불가능합니다."); } this.setStatus(OrderStatus.CANCEL); for (OrderItem orderItem : orderItems) { orderItem.cancel(); } } 그 다음 위의 Order 엔티티의 cancel 메서드가 호출이 되는데 예외처리 부분을 지나 이제 "해당 주문에 포함된(저장된) 주문품목(OrderItem) 의 addStock() 하는 메서드까지 연결이 됩니다. OrderService > Order > OrderItem > Item 까지의 순차적인 cancel 및 addStock() 메서드까지 실행이 완료되면 OrderService의 cancelOrder메서드의 트랜잭션이 종료가 되어 flush가 발생/DB 쿼리가 날라감 까지 제가 이해를 하고 있습니다. 혹시 틀린 부분이 있다면 말씀부탁드리겠습니다! 가장 헷갈리는 부분이 이건데, Order order.cancel() 이 부분에서 order 라는 Order 엔티티 객체에 바로 cancel() 메서드를 사용했는데 /** * 주문 취소 */ public void cancel(){ if (delivery.getStatus() == DeliveryStatus.COMP) { throw new IllegalStateException("이미 배송완료된 상품은 취소가 불가능합니다."); } this.setStatus(OrderStatus.CANCEL); for (OrderItem orderItem : orderItems) { orderItem.cancel(); } }조회한 데이터는 Order 뿐인데 다음 코드가 delivery.getStatus() 입니다. 갑자기 delivery가 어디서 나온건지.. 모르겠습니다. 예외처리가 끝나면 나오는 orderItem 또한 갑자기 무슨 데이터를 가지고 반복문을 돌리는지 모르겠습니다. 제 짧은 지식의 추측상 예외처리시에 delivery.getStatus() 는 Order엔티티와 1:1 관계이기에 delivery가 사용하게 될 때 지연로딩을 이용하여 delivery 데이터를 조회하여 사용하고 OrderItem 또한 Order와 일대다관계이기에 for (OrderItem orderItem : orderItems) { orderItem.cancel(); } 이렇게 사용될 때 지연로딩을 이용하여 Order pk를 가진 OrderItem 의 데이터를 가지고와 반복문을 돌리게 되는건가요?? 너무 헷갈리네요.. 제가 이해하고 있는게 맞나요?
파이어베이스와 수파 베이스 를 사용하고 있습니다. API 폴더에 해당 통신 로직을 정의해서 사용하면 보안과 API 명세에 대한 로직을 잘 관리 할 수 있다는 것을 강의내용을 통해 알았습니다 BAAS 서비스를 이용하면 API 폴더에 넣고 관리하게 된다면 통신 로직이 중복되는 것같은데 API -> BBAS 통신 이럴 경우 어떻게 사용하는게 좋은지 궁금합니다!!
1. 현재 학습 진도 몇 챕터/몇 강을 수강 중이신가요? 2챕터/5강 수강중입니다. 여기까지 이해하신 내용은 무엇인가요? 도커와 모니터링에 대해 전반적인 틀을 이해했습니다. 질문 설명에서는 private subnet2에 데이터 베이스 서버를 배포 한다고 하셨는데 아래 도표에서 public서브넷으로 표기 되어있어서 혼동이 있습니다 ! private 서브넷이 맞는건가요 ?
상황 :같은 테스트를 진행했는데 저는 성능이 너무 안나와서 고민입니다. 문제 :이전 개인 프로젝트에서도 클라우드상에서 기본 API 응답 시간이 2초 가량 소요됐었는데, 그 때 당시에는 비지니스 로직이 무거워서 그랬나보나 싶었는데 이번 실습에서도 이렇게나 느린 걸 보면 개인 PC의 성능이 안좋은 것 같습니다. (게임도 잘 돌아가고 네트워크도 절대 느린 편이 아닌데 말이죠...) 질문 : 이력서에 성능 시간에 관해 쓸 때 잘 만들어진 코드임에도 이렇게 느리면 담당관 입장에서는 "이렇게 느린데 무슨 성능 향상을 했다는거야?" 하는 생각이 들 것 같습니다. 실제로 http_reqs가 1.036077/s로 1초에 1명밖에 받지 못하고 있는데, 이 상태로는 이력서에 쓰는게 의미가 없을 거 같아서 어떤 식으로 테스트를 하는 게 좋을지 궁금합니다. 아 참고로 이 테스트는 Bad Test 입니다.
========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 예 2. 인프런의 질문 게시판과 자주 하는 질문에 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예 [질문 내용] 여기에 질문 내용을 남겨주세요. 전부 해봤습니다. gradlew.bat 을 직접 폴더 내에서 눌러서 실행해보면 오류 코드고 뭐고 아무것도 확인할 수도 없이 바로 꺼져버립니다. jdk 24입니다. 그리고 커맨드를 열어서 cd 로 폴더 연결 후 이대로 해보려고 해도 첫번째 사진처럼만 뜹니다. 다른 질문들을 다 찾아봐도 gradlew.bat 을 누르자마자 뭔가 보이기도 전에 꺼져버리는 케이스는 없어서 너무 고통스럽습니다. 도움을 주실 분 안 계실까요? https://drive.google.com/drive/folders/1r2uKWeNTWgDPhZMBnix_aDlhLFZClxPO?usp=sharing 파일 드라이브입니다
안녕하세요! 2.20 강의를 듣고 Vercel에 배포까지 한 뒤에 궁금한 점이 생겨 질문 드립니다! 이전 강의 실습에서는 인덱스 페이지의 추천 도서를 On-Demand ISR 방식으로 적용한 뒤 직접 주소를 입력해 페이지 요청을 보내서 바꾸었는데 Vercel에 배포한 뒤에는 어떻게 요청을 보내서 추천 도서 목록을 바꿀 수 있나요? 아니면 시간 단위로 업데이트하는 방식으로 다시 바꾸어서 작성한 뒤 재배포하나요?
@Bean public SimpleMessageListenerContainer container(ConnectionFactory connectionFactor, MessageListenerAdapter listenerAdapter) { SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); container.setConnectionFactory(connectionFactor); container.setQueueNames(QUEUE_NAME); container.setMessageListener(listenerAdapter); return container; } @Bean public MessageListenerAdapter listenerAdapter(Receiver receiver) { return new MessageListenerAdapter(receiver, "receiveMessage"); // Receiver의 메소드명 } 안녕하세요. 좋은 강의해주셔서 감사합니다. 만약 하나의 큐에서 여러 컨슈머를 통해 동시에 여러개를 소비하고자한다면 Receiver를 추가해서 새롭게 MessageLisnterAdaper 빈을 추가하는걸까요? 어떤식으로 하는것인지 궁금합니다. 여러큐와 거기에 따른 여러 컨슈머 구성시에는 어떤식으로 환경설정하면 될까요? 감사합니다.
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? 예 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요?예 안녕하세요 직접 구현하는 연결리스트 3 추가와 삭제 2편을 복습하다 궁금한 점이 생겨 여쭤보게 되었습니다 ! 지금 Object remove 메서드에 else 구절을 보면 (첫번째 노드를 삭제하는 경우가 아닌 경우) getNode(index-1).next = removedNode.next;로 구현이 되어있습니다 ! 여기에서 스스로 복습하는 과정에서 저는 getNode(index-1).next = getNode(index+1);로 생각을 했었는데, 혹시 이 로직으로 해도 문제가 되지 않는지가 궁금하네요 ..! 그리고 바로 하단에 removeNode.item = null; removeNode.next = null;로 직접 null 값으로 비워주는 이유가 있을까요 ? getNode(index-1).next = getNode(index+1);로 두면 삭제할 노드인 getNode(index)는 연결이 끊기기에 자동으로 GC의 대상이 된다고 생각해서 여쭤봅니다 ! 복습하면서 많은 것들을 처음에는 보이지 않던 것들을 많이 얻어가는 중입니다 좋은 강의 제공해주셔서 감사드립니다 !
Kafka Cluster 강의 약 11분 38초 쯤에서 Broker 2(topic 1, partition 2)에 장애가 발생하면, 다른 정상 Broker에서 Leader를 재선출 한다고 하셨는데, 그렇다면 해당 그림의 경우 Broker 1의 topic 1의 Leader가 partition 1에서 partition 2로 바뀌는 것인가요? 기존에 정상적으로 있던 Broker 1의 topic 1의 partition 1은 Leader의 자격을 잃는 것인가요? 다시 말씀드리면, 정상 Broker에서 Leader를 재선출하면, 기존 토픽에 있는 Leader Partition이 어떻게 되는지 궁금합니다..!