- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 먼저, 유익한 강의를 나눠 주셔서 감사합니다. springboot 3.1버전을 사용 하면서 안되는 부분에 대해서 질문드립니다. 강의 간에 진행되는 springboot 버전을 2.7 버전으로 설정 하셨는데, end of support가 11월로 예정이 되어 있더라구요,, 현재 섹션 9. OAuth 2.0 Client - Social Login (Google, Naver, KaKao) + FormLogin 파트까지 3.1 버전으로 마이그레이션 진행 하려 했으나, config의 메서드가 Deprecated 된 부분을 해결 해야했습니다. 공식 문서를 참고해서 일단 제가 바꾼 부분은 다음과 같습니다. authorizeRequests -> authorizeHttpRequests antMatchers -> requestMatchers http.formLogin(), http.logout() -> 람다 사용 import io.security.oauth2.springsecurityoauth2.service.CustomOAuth2UserService; import io.security.oauth2.springsecurityoauth2.service.CustomOidcUserService; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.web.SecurityFilterChain; @RequiredArgsConstructor @EnableWebSecurity public class OAuth2ClientConfig { private final CustomOAuth2UserService customOAuth2UserService; private final CustomOidcUserService customOidcUserService; @Bean public WebSecurityCustomizer webSecurityCustomizer() { return (web) -> web.ignoring().requestMatchers("/static/js/**", "/static/images/**", "/static/css/**", "/static/scss/**"); } @Bean SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests((requests) -> requests .requestMatchers("/api/user") .hasAnyRole("SCOPE_profile','SCOPE_email") // .access("hasAuthority('SCOPE_profile')") .requestMatchers("/api/oidc") .hasRole("SCOPE_openid") //.access("hasAuthority('SCOPE_openid')") .requestMatchers("/") .permitAll() .anyRequest().authenticated()); http.oauth2Login(oauth2 -> oauth2.userInfoEndpoint( userInfoEndpointConfig -> userInfoEndpointConfig .userService(customOAuth2UserService) .oidcUserService(customOidcUserService))); http.logout(form -> form.logoutSuccessUrl("/")); return http.build(); } /*@Bean // hasAuthority 일경우 정의하지 않는다 public GrantedAuthoritiesMapper grantedAuthoritiesMapper(){ SimpleAuthorityMapper simpleAuthorityMapper = new SimpleAuthorityMapper(); simpleAuthorityMapper.setPrefix("ROLE_"); return simpleAuthorityMapper; }*/ @Bean public GrantedAuthoritiesMapper customAuthorityMapper() { return new CustomAuthorityMapper(); } } 이렇게 수정을 하니 메인 페이지("/")가 무조건 로그인 페이지("/login)로 리다이렉트 되는 문제(?)를 발견 했습니다. 이 부분에 대해서 어떻게 해결해야할지 여쭤보고 싶습니다.
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] 질문 수정 테스트 코드에 @Rollback(value = false) 어노테이션을 넣고 실행했더니 INSERT 쿼리도 로깅되는 것을 확인했습니다!! 생각해 보니, 롤백이 되지 않으면 그때 한 번에 쿼리를 보내는 것이 자연스러운 것 같네요..! 롤백될 쿼리까지 로그에 남으면 개발자 입장에서 원인을 파악하기 더 힘들 것 같고요. 원래 롤백이 되는 쿼리는 로깅이 안 되는 것이 정상인 거겠죠?? 기존 질문 위 사진과 같이 create table 쿼리는 로깅이 잘 되지만, insert 쿼리는 로깅이 되지 않습니다! 이유가 무엇인지 알 수 있을까요?? 관련 코드 및 로그 첨부하겠습니다. application.yml 설정 spring: datasource: url: jdbc:h2:tcp://localhost/~/Programming/h2/jpashop username: sa password: driver-class-name: org.h2.Driver jpa: hibernate: ddl-auto: create properties: hibernate: show_sql: true format_sql: true logging: level: org.hibernate.sql: debug 실행한 테스트 코드 @Test @Transactional void testMember() { // given final Member member = new Member(); member.setUsername("memberA"); // when final Long savedId = memberRepository.save(member); final Member findMember = memberRepository.find(savedId); // then assertThat(findMember.getId()).isEqualTo(member.getId()); assertThat(findMember.getUsername()).isEqualTo(member.getUsername()); assertThat(findMember).isEqualTo(member); } 로그 (원인을 파악하여, 글이 길어지지 않기 위해 로그는 첨부하지 않겠습니다.)
@JsonIgnore는 양방향 관계의 무한루프를 막기 위해 설정하는 것이고, @GetMapping("/api/v1/orders") public List<Order> ordersV1() { List<Order> all = orderRepository.findAllByString(new OrderSearch()); for (Order order : all) { order.getMember().getName(); order.getDelivery().getAddress(); List<OrderItem> orderItems = order.getOrderItems(); orderItems.forEach(o -> o.getItem().getName()); } return all; } 위에 처럼 프록시 초기화(하지만 실제 엔티티의 참조만 가질뿐 객체는 여전히 프록시)를 해주는 이유는 실제 엔티티의 참조를 가지게 하려고 설정하는 것이고, @Bean Hibernate5Module hibernate5Module() { return new Hibernate5Module(); } 위에 처럼 Hibernate5Module을 해주는 이유는 프록시 초기화를 해도 객체는 여전히 프록시기 때문에 Json으로 반환할 수 있게 하려는 것이라고 이해했습니다. 여기 까지 이해한 부분이 옳게 이해한 것일까요? 그리고 마지막으로 @Bean Hibernate5Module hibernate5Module() { Hibernate5Module hibernate5Module = new Hibernate5Module(); // 강제 지연 로딩 설정 hibernate5Module.configure(Hibernate5Module.Feature.FORCE_LAZY_LOADING, true); return new Hibernate5Module(); } 위에 처럼 강제 지연 로딩 설정을 왜 쓰는지는 잘 모르겠습니다. 강제 지연 로딩 설정이라는 말이 무엇인가요!? 혹시 하이버네이트가 @ToOne은 기본이 eager인데 엔티티에서 직접 lazy 설정해준걸 안해도 된다는 소리인가요? 질문이 크게 숫자로 표시한 두가지 입니다! 감사합니다.
1+n문제에서 n이 1에서 조회한 갯수 라고 하셨는데요. order 2개를 찾았을 때 member와 delivery를 불러와야 하므로 1 + 2*2 인 것 같습니다. 만약 멤버와 딜리버리 말고 찾아야하는 지연 로딩 속성이 10개 라면 1+2*10 이니까 사실은 1+N이 자세히 보면 1+N*M 문제 라고 혼자 나름대로 이해를 해도 괜찮을까요? M은 상수라서 생략하는 거 같은데 혹시 맞을까요?
안녕하세요. 좋은 강의 항상 감사드립니다. Coupon 도메인 중복 관련해서 질문이 있습니다. consume 모듈을 새로 생성하면서 Coupon 도메인을 api 모듈에서 복붙을 하셨는데요. gradle 멀티 모듈을 만들 때 부모/자식 관계로 만들면 Coupon 도메인을 중복되지 않게 사용할 수 있을 것 같은데 강의에서는 시간상 패스한 것인가요?
안녕하세요, 좋은 강의 올려주셔서 잘 배우고 있습니다 :) 강의에서 Kafka 도입 이유에 대한 궁금증이 생겨 질문 드립니다. 'Redis를 활용하여 문제 해결하기' - '문제점' 강의에서 해당 쿠폰 API에 요청이 몰리면 DB 서버에 부하가 갈 수 있다고 설명해주셨는데요. 그 해결방법으로 Kafka를 사용하셨고 API에서 직접 쿠폰을 생성할 때와 다르게 처리량을 조절해서 부하를 줄일 수 있다고 하였습니다. 이 내용 중 "처리량을 조절한다"는 의미는 어떻게 이해하면 좋을까요? 컨슈머 애플리케이션에서 처리량을 조절하는 로직을 추가하여 RDB 부하를 분산시키는 걸까요? 혹은 카프카에서 그러한 기능을 지원하는 걸까요? 혹은 마지막 강의에 있는 에러를 발생했을 때, 백업 데이터를 통해 실패 처리를 하는 경우에 대한 이야기일까요?
안녕하세요 호돌맨님 !! 강의 하면서 항상 궁금했던 점인데, 저는 Controller Test 를 End-To-End Test 용도로 자주 활용하고 있는데요, 이러면 Repository Method 를 Controller Test 에서 직접적으로 사용하는 것보다 Service 단 로직을 거쳐 Repository 의 Method 가 호출되도록 하는게 맞는걸까요 ? 호돌맨님은 항상 Controller Test 로직 짜실 때 Repository 의 save() 와 같은 메서드를 한번에 호출해서 사용하는 걸보고 질문 드립니다 !
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 안녕하세요. 프로젝트 생성부분 강의에서 openjdk 11.0.19 버전과 스프링부트 2.7.12버전으로 start.spring.io 사이트에서 파일을 받아서 진행하고 있는데 요런 warning이 나오고 있어서 질문드립니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 강의 5분쯤에 나오는 memberService.findOne(saveId).get() 과 memberSrvice.findOne(saveId)의 차이점이 뭘까요 .. ? 반환이 둘 다 Optional 로 감싼 member라고 생각 했는데 get()으로 값을 꺼내면 optional의 value 값이 나오는 걸까요 .. ? optional을 잘 이해를 못해서 그런건지 이 부분 잘 이해가 안 가는데 어떤 내용을 더 학습해야 이해에 도움이 될까요 ...
현 시점에서 강의 들을 때 부트3.0이상에 자바17 쓰라고 안내되어있어 현재 환경은 이렇습니다 스프링부트 3.0.6 java17 인텔리제이 커뮤니티 23.1.1 컴파일 에러라 run을 해볼 수 없는 상황입니다ㅠㅜ 검색하면서 IntelliJ 에서 InvalidateCaches는 해봤는데 안됩니다ㅠㅠ 컴파일 에러메세지 Cannot resolve method 'findById' in 'MemoryMemberRepositoryTest' 강의와 다른 특이점 강의에서 junit 임포트 하라고 할 때도 임포트가 안뜨고 classpath 설정하라고 추천이 떴고 이때 junit 5.8.1로 추천하는 걸로 하고 나서 import가 뜨길래 이렇게 junit 임포트했습니다 @Test public void save(){ Member member = new Member(); member.setName("spring"); repository.save (member); Member result = repository.findById(member.getId()).get(); // 검증하기 findById로 // get()으로 값을 바로 꺼내는 방법은 좋지 않으니 테스트코드에서는 상관x System. out .println("result = " + (result == member)); // 글자로 보는 건 불편하니 Assertions라는 기능이 있음 Assertions. assertEquals (member,result); // .assertEquals(기대되는값expected, 실제결과actual) 파라미터
- 안녕하세요! 강의 정말 잘 듣고 있습니다. 강의를 듣다가 궁금한점이 생겨서요! - keycloak 관련해서 로그인처리할 때 지금은 keycloak에서 제공하는 로그인 페이지를 사용하고 있는데, 만약 그 로그인페이지를 사용하지 않고 Front에서 만든 로그인 페이지를 사용하고, POST 요청으로 사용하면 http://localhost:8080/realms/bts/protocol/openid-connect/token URL로 직접 호출해서 토큰을 받는게 맞을지... 궁금합니다.
안녕하세요 강사님. 매번 너무나도 좋은 강의 감사드립니다. 강의 내용 중 OIDC 부분을 학습하다 궁금증이 생겨 질문드립니다. 위의 이미지는 제공해주신 ppt 자료 중 96번 슬라이드의 내용입니다. 이전 내용에서 OIDC를 사용하지 않는 클라이언트의 요청을 확인하여 액세스 토큰을 발급하는 주체는 인가 서버라고 설명을 해 주셨는데 위의 이미지에서는 OP가 ID토큰과 액세스 토큰을 발급한다고 설명을 해 주셨습니다. 혹시 OIDC를 사용하는 경우에는 OpenID Provider가 인가 서버의 역할을 같이 하는 것이라고 생각해도 될까요? 감사합니다.
시큐리티 + jwt만을 사용한다면 회원가입하고 로그인하면 jwt를 클라이언트에게 보내줘서 다른 요청을 할 때 jwt를 함께 보내고 게시판이 해당 유저인지 판별할 때 예전에는 세션으로 사용했지만 이제는 jwt로 구별한다고 알고있습니다. 그러면 Oauth2 + jwt는 회원가입, 로그인만 소셜로그인 즉, 외부로 빼기만 한거고 소셜 로그인이 성공하면 jwt를 클라이언트에게 주고 그걸로 로그인을 유지한다던지 나머지 역할은 같나요? 소셜 로그인하면 accessToken을 발급해주는데 그거는 단지 서버에서 소셜로그인할 때 연결하기 위한거고 클라이언트에겐 따로 jwt를 만들어서 accessToken, refreshToken을 발급해줘야 하는건가요?