묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
EC2 중지후 재시작시 기존배포 애플리케이션에 대한 문의
EC2 중지후 다시 인스턴스를 실행 했는데 퍼블릭 ip주소가 바꼈습니다.그래서 다시 인스턴스 실행후 바뀐 퍼블릭 ip주소로 접속을 시도했는데보안설정도 그대로인데 접속이 안되서 보니 빌드 디렉토리는 존재하는데빌드 실행이 안된상태이고 어플리케이션도 종료가 되있는 상태였습니다 다시 빌드후 어플리케이션 재실행으로현재는 접속이 가능한 상태이지만 혹시 일레스틱을 사용하지 않는 경우나도메인을 따로 구입하지 않은경우에는인스턴스 중지후 재실행시 항상 이러한 절차를 거쳐야 하는건가요?
-
미해결스프링 시큐리티 OAuth2
OAuth2 인가서버로부터 access token 발급 후 저장 관련 질문
안녕하세요 강사님.OAuth2 인가 프레임워크 관련하여 학습 중 인가서버로부터 받은 access token을 어떻게 저장하고 어떻게 활용할 수 있을지 고민하다가 궁금한 점이 있어 질문드립니다. 제가 생각했던 프로세스는 이렇습니다.[리소스 오너가 소셜 로그인 시 (구글인 경우)]리소스 오너가 구글 로그인을 한다.클라이언트 (내가 만든 스프링 서버)는 구글의 인가서버로부터 리소스 오너의 userInfo 엔드포인트 접근 시 사용할 수 있는 access token을 받는다.access token을 활용해서 userInfo 엔드포인트에 접근하여 리소스 오너의 이메일, 이름 등의 정보를 가져온다. (이 부분은 내가 구현하지 않아도 스프링 시큐리티에서 제공)소셜 로그인 시 얻은 정보 (oidc 활성화 시 id-token, 리소스 오너가 허용한 userInfo 등)를 클라이언트의 세션에 저장한다.그리고 로그인 프로세스 완료되어 LoginSuccessHandler에서 이후 로직을 처리할 수 있다. [이후 로그인 된 상태에서 클라이언트의 API 호출 시]클라이언트의 API를 호출할 때 SecurityContextHolder에 userInfo를 담아 활용할 수 있다.access token은 클라이언트에 저장되어 있고, API 호출 시 꺼내어 리소스 서버에 접근할 수 있다. 그런데 SecurityContextHolder에 access token 정보가 보이지 않아 궁금한점이 생겼습니다.만약 로그인이 된 상태에서 userInfo 엔드포인트에 접속 시 매번 새로운 access token을 발급 받아서 요청하는 것일까요? (SecurityContextHolder에 access token이 없어서 조금 헷갈리고 있습니다.)100명의 리소스 오너가 로그인 할 때마다 access token을 발급받으면 총 100개의 access token이 발급되는게 맞을까요?이러한 경우 클라이언트에 100개의 access token을 저장 후 userInfo 엔드포인트 접근 시 사용하며, 만약 만료되었다면 refresh token으로 access token을 재발급 받아 다시 userInfo 엔드포인트에 접근하는게 맞을까요?만약 1개의 클라이언트에 100개의 accessToken을 저장 후 만료 전까지 사용하는 것이라면 클라이언트에 부하가 많이 발생하여 scale-out하는 경우에는 보통 어떻게 해결할 수 있을까요?Google, Naver, Kakao 등의 소셜에서 access token을 발급 받는 것 까지는 스프링 시큐리티가 지원해주지만 이후 다양한 엔드포인트를 호출하거나, access token 만료 시 refresh token으로 재발급 받는 로직 등은 제가 구현해야 하는게 맞을까요? 제가 아직 강의를 절반밖에 듣지 않아서 이후 강의해주시는 부분에 제가 질문드린 내용이 포함되어 있을 수도 있을 것 같습니다. 만약 포함되어 있다면 간략하게나마 어떤 강의 동영상을 참고하면 좋을 지 말씀해주시면 감사하겠습니다.감사합니다.
-
미해결스프링 부트 - 핵심 원리와 활용
외장 Tomcat에서 서블릿컨테이너 초기화 시 오류
안녕하세요~ 김영한 이사님 강의 너무나 재미있게 잘 듣고 있습니다~서블릿컨테이너 초기화를 교육과정에 따라 내장 Tomcat을 이용해서 실행하면 잘 실행됩니다.해당 코드를 외부 서버에 동일한 버전 Tomcat(V10)서버 webapps 폴더에 올려서 실행하면 아래와 같은 오류가 발생하는데 구글링을 해봐도 해답을 찾을 수 없어서 질문 드립니다. 16-Sep-2023 14:42:28.075 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/opt/tomcat/apache-tomcat-10.1.13/webapps/ROOT.war]16-Sep-2023 14:42:28.482 SEVERE [main] org.apache.catalina.startup.ContextConfig.processServletContainerInitializers Failed to detect ServletContainerInitializers for context with name [] java.io.IOException: java.lang.ClassCastException: Cannot cast hello.container.MyContainerInitV1 to jakarta.servlet.ServletContainerInitializer at org.apache.catalina.startup.WebappServiceLoader.loadServices(WebappServiceLoader.java:238)
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
hashMap 저장순서
hashMap에서는 값이 저장되는 순서가 보장이 되지 않는 다고 알고 있습니다. Map인터페이스의 values()메서드 또한 맵에 저장된 값들을 반환하지만 순서가 유지되지 않는 다고 알고 있는데요 그런데 전체 클래스 테스트시 findAll(), findByName(),save()순으로 실행이 되는 데 findAll()과 findByName() 에서 각 멤버 인스턴들이 save가 다 되고 난 후 System.out.println(repository.findAll());추가해 이를 통해 저장된 값들을 확인해 본 결과 findAll()의 System.out.println(repository.findAll()); 에서는 [hello.hellospring.domain.Member@589b3632, hello.hellospring.domain.Member@45f45fa1] findAll()이후에 실행된 findByName()의 System.out.println(repository.findAll()); 에서는 [hello.hellospring.domain.Member@589b3632, hello.hellospring.domain.Member@45f45fa1, hello.hellospring.domain.Member@67a20f67, hello.hellospring.Member@57c758ac] 값이 나왔는데 이 처럼 메소드가 실행된 순서와 각 인스턴스들이 save된대로 저장값의 순서 유지가 되서 출력값으로 나오는데 원래라면 hashMap과 values()메서드가 저장 순서를 보장하지 않으므로 System.out.println(repository.findAll()); 실행시 마다 Map에 저장된 값들을 저장순서 상관없이 랜덤하게 출력되야 되는 거 아닌가요? 제가 어떤 부분을 잘못알고 있는 지 궁금합니다.class MemoryMemberRepositoryTest { MemoryMemberRepository repository = new MemoryMemberRepository(); @Test public void save(){ Member member = new Member(); member.setName("spring"); repository.save(member); Member result = repository.findById(member.getId()).get(); assertThat(member).isEqualTo(result); } @Test public void findByName(){ Member member1 = new Member(); member1.setName("spring1"); repository.save(member1); Member member2 = new Member(); member2.setName("spring2"); repository.save(member2); Member result = repository.findByName("spring1").get(); System.out.println(repository.findAll()); assertThat(result).isEqualTo(member1); } @Test public void findAll(){ Member member1 = new Member(); member1.setName("spring1"); repository.save(member1); //hashMap 함수로 key로 id value로 member(id,name) 인스터스 저장 Member member2 = new Member(); member2.setName("spring2"); repository.save(member2); List<Member> result = repository.findAll(); System.out.println(repository.findAll()); assertThat(result.size()).isEqualTo(2); } }
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
hasIpAddress(), getRemoteAddr() 질문입니다.
이전에 이런 질문들((https://www.inflearn.com/questions/423204))이 있던 것을 확인하였으나 저는 해결이 되지 않아 질문을 남깁니다.postman으로 회원가입하고 로그인하려고 하면 401 Unauthorized가 나며 많이 보셨을 이런 에러가 나옵니다.java.lang.UnsupportedOperationException: public abstract java.lang.String javax.servlet.ServletRequest.getRemoteAddr() is not supported....이와 같은 에러의 질문과 답변을 보고 hasIpAddress()에서 .access("hasIpAddress('" + IP + "')")로 바꿔서 해보았는데도 또는 스프링 부트 버전을 바꾸어 시도해(2.6.2, 2.4.2 등)보았으나 해결이 되지 않아 질문을 드립니다.처음 설정한 spring boot 버전은 2.7.15입니다.build.gradleplugins { id 'java' id 'org.springframework.boot' version '2.7.15' id 'io.spring.dependency-management' version '1.0.15.RELEASE' } group = 'com.example' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '11' } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } ext { set('springCloudVersion', "2021.0.8") } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'com.h2database:h2:1.3.176' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.modelmapper:modelmapper:3.1.1' implementation 'org.springframework.boot:spring-boot-starter-security' testImplementation 'org.springframework.security:spring-security-test' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' } dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" } } tasks.named('test') { useJUnitPlatform() } WebSecurity은@Configuration @EnableWebSecurity public class WebSecurity extends WebSecurityConfigurerAdapter { private final Environment environment; private final UserService userService; private final BCryptPasswordEncoder bCryptPasswordEncoder; private String IP = "192.168.1.2"; @Autowired public WebSecurity(Environment environment, UserService userService, BCryptPasswordEncoder bCryptPasswordEncoder) { this.environment = environment; this.userService = userService; this.bCryptPasswordEncoder = bCryptPasswordEncoder; } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); http.authorizeRequests() .antMatchers("/**") // .hasIpAddress(IP) .access("hasIpAddress('" + IP + "')") .and() .addFilter(getAuthenticationFilter()); http.headers().frameOptions().disable(); } private AuthenticationFilter getAuthenticationFilter() throws Exception { AuthenticationFilter authenticationFilter = new AuthenticationFilter(authenticationManager(), userService, environment); return authenticationFilter; } // db password와 input password 비교 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService).passwordEncoder(bCryptPasswordEncoder); } }2.7 이후 버전에서는 https://www.inflearn.com/chats/789887와 같이 WebSecurityConfigurerAdapter 를 상속하지 않고 configure함수 오버라이드 대신 SecurityFilterChain을 사용해보았으나 이렇게 해도 되지 않았습니다.AuthenticationFilter에 unsuccessfulAuthentication를 오버라이드하여 확인해본 결과org.springframework.security.authentication.BadCredentialsException: 자격 증명에 실패하였습니다. at org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:80) at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:147) at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182) at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:201) at com.example.userservice.filter.AuthenticationFilter.attemptAuthentication(AuthenticationFilter.java:46)라고 오류가 나오는 것을 확인했습니다.AuthenticationFilter.java:46 부분은 return getAuthenticationManager().authenticate( 부분 입니다.AuthenticationFilter 코드는 다음과 같습니다.@Slf4j public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter { private final UserService userService; private final Environment environment; public AuthenticationFilter(AuthenticationManager authenticationManager, UserService userService, Environment environment) { super.setAuthenticationManager(authenticationManager); this.userService = userService; this.environment = environment; } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { try { RequestLogin creds = new ObjectMapper().readValue(request.getInputStream(), RequestLogin.class); return getAuthenticationManager().authenticate( new UsernamePasswordAuthenticationToken( creds.getEmail(), creds.getPassword(), new ArrayList<>() ) ); } catch (IOException e) { throw new RuntimeException(e); } } @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { // log.debug(((User)authResult.getPrincipal()).getUsername()); String userName = ((User)authResult.getPrincipal()).getUsername(); UserDto userDetails = userService.getUserDetailsByEmail(userName); System.out.println("details :" + userDetails); String token = Jwts.builder() .setSubject(userDetails.getUserId()) .setExpiration( new Date((System.currentTimeMillis() + Long.parseLong(environment.getProperty("token.expiration_time")))) ) .signWith(SignatureAlgorithm.HS512, environment.getProperty("token.secret")) .compact(); System.out.println("token :" + token); response.addHeader("token", token); response.addHeader("userId", userDetails.getUserId()); } @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { // super.unsuccessfulAuthentication(request, response, failed); failed.printStackTrace(); } } 어느 부분을 어떻게 수정하여 진행을 해야 할까요? AuthenticationFilter에서 attemptAuthentication 함수를 UsernamePasswordAuthenticationToken 받는 것으로 수정하여 디버깅해보니 아래 코드의 authenticationToken 값은 잘 나옵니다. 그런데 위의 질문처럼 getAuthenticationManager().authenticate 여기서 문제가 발생합니다.문제가 발생하는 부분은 AbstractAuthenticationProcessingFilter의 저 부분으로 잡히며AuthenticationFilter 코드는 다음과 같습니다.import com.example.userservice.dto.UserDto; import com.example.userservice.service.UserService; import com.example.userservice.vo.RequestLogin; import com.fasterxml.jackson.databind.ObjectMapper; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import lombok.extern.slf4j.Slf4j; import org.springframework.core.env.Environment; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.User; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.Date; @Slf4j public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter { private final UserService userService; private final Environment environment; public AuthenticationFilter(AuthenticationManager authenticationManager, UserService userService, Environment environment) { super.setAuthenticationManager(authenticationManager); this.userService = userService; this.environment = environment; } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { try { RequestLogin creds = new ObjectMapper().readValue(request.getInputStream(), RequestLogin.class); UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( creds.getEmail(), creds.getPassword(), new ArrayList<>()); return getAuthenticationManager().authenticate(authenticationToken); } catch (IOException e) { throw new RuntimeException(e); } } @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { // log.debug(((User)authResult.getPrincipal()).getUsername()); String userName = ((User)authResult.getPrincipal()).getUsername(); UserDto userDetails = userService.getUserDetailsByEmail(userName); System.out.println("details :" + userDetails); String token = Jwts.builder() .setSubject(userDetails.getUserId()) .setExpiration( new Date((System.currentTimeMillis() + Long.parseLong(environment.getProperty("token.expiration_time")))) ) .signWith(SignatureAlgorithm.HS512, environment.getProperty("token.secret")) .compact(); System.out.println("token :" + token); response.addHeader("token", token); response.addHeader("userId", userDetails.getUserId()); } // @Override // protected void unsuccessfulAuthentication(HttpServletRequest request, // HttpServletResponse response, // AuthenticationException failed) throws IOException, ServletException { //// super.unsuccessfulAuthentication(request, response, failed); // failed.printStackTrace(); // } } 해결 방법 좀 알려주시면 감사하겠습니다.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
중복 회원 예외 실패라고 나오는 이유
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]테스트 케이스 실행 시 결과값이 "이미 존재하는 회원입니다."라고 출력이 되는데, 콘솔 창에서는 tests failed 1 passed 1으로 나옵니다. 큰 오류는 아닌거같은데 failed라고 떠서 좀 찝찝한데 설정을 따로 바꾸는것인지 코드 자체 오류인지가 궁금합니다. Expacted와 Actual의 차이점도 궁금합니다. Click to see differences를 해도 무슨 차이인지 모르겠습니다...package hello.hellospring.service; import hello.hellospring.domain.Member; import hello.hellospring.repository.MemberRepository; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.transaction.annotation.Transactional; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @SpringBootTest @Transactional public class MemberServiceIntegrationTest { @Autowired MemberService memberService; @Autowired MemberRepository memberRepository; @Test public void 회원가입() throws Exception { //Given Member member = new Member(); member.setName("spring"); //When Long saveId = memberService.join(member); //Then Member findMember = memberService.findOne(saveId).get(); assertThat(member.getName()).isEqualTo(findMember.getName()); } @Test public 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("이미 존재하는 회원입니다."); } } 2023-09-15T21:34:27.857+09:00 INFO 15492 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2023-09-15T21:34:27.999+09:00 INFO 15492 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:tcp://localhost/~/test user=SA 2023-09-15T21:34:28.001+09:00 INFO 15492 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended org.opentest4j.AssertionFailedError: expected: "이미 존재하는 회원입니다." but was: "이미 존재하는 회원입니다" Expected :"이미 존재하는 회원입니다." Actual :"이미 존재하는 회원입니다" <Click to see difference> at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:67) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500) at hello.hellospring.service.MemberServiceIntegrationTest.중복_회원_예외(MemberServiceIntegrationTest.java:41) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) at java.base/java.lang.reflect.Method.invoke(Method.java:578) at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727) 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:156) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) 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.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:217) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86) at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86) at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57) at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
import 관련 질문합니다.!
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.안녕하세요 import할 때마다 궁금증이 생겨 찾아봤지만 이해가 잘 가지 않아 질문드립니다...!맨 위에것으로 import 하면 되는건 알지만 왜 두가지가 뜨는걸까요?하나는 클래스, 인터페이스 두개가 어떤 차이인지 알려주시면 감사하겠습니다 ㅠㅠ
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
default_batch_fetch_size: 100 으로 설정을 해줘도 쿼리가 한번에 가져오지 않습니다.
@GetMapping("api/v2/orders/{id}") // batch_fetch_size 검색용 public ResultMany findByBatchFetch(@PathVariable("id") Long id) { Customer customer = customerService.findCustomerById(id); List<Order> orders = orderRepository.findAllOrder(); return getOrderDtoList(orders); } public List<Order> findAllOrder() { return em.createQuery("select o from Order o", Order.class) .getResultList(); } private ResultMany getOrderDtoList(List<Order> orders) { List<OrderDto> orderDtos = orders.stream() .map(o -> new OrderDto(o)) .collect(Collectors.toList()); return new ResultMany<>(orders.size(), orderDtos); } @Data static class OrderDto { private Long id; private CustomerDto customer; private List<DiffuserProductRequestDto> diffuserProductRequest; public OrderDto (Order order) { id = order.getId(); customer = new CustomerDto(order.getCustomer()); diffuserProductRequest = order.getDiffuserProductRequests().stream() .map(diff -> new DiffuserProductRequestDto(diff)) .collect(Collectors.toList()); } } @Data static class DiffuserProductRequestDto { private Long id; private DiffuserDto diffuser; private int amount; private Deadline deadline; private ProductionStatus status; public DiffuserProductRequestDto (DiffuserProductRequest diffuserProductRequest) { id = diffuserProductRequest.getId(); diffuser = new DiffuserDto(diffuserProductRequest.getDiffuser()); amount = diffuserProductRequest.getAmount(); deadline = diffuserProductRequest.getDeadline(); status = diffuserProductRequest.getStatus(); } } 위에는 order클래스 연관된 클래스를 찾기위한 코드들인데 제가 27개의 오더를 만들고 get요청을 보내면 default_batch_fetch_size: 100으로 설정 해놓았기 때문에 27개를 한번에 가져올 것이라고 생각하고 있는데 결과는 그렇지 않습니다이렇게 두번의 쿼리로 찾아오는데 어떤게 문제인걸까요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
상품 수정부분에서 에러가 발생하는것 같습니다..
[질문 내용]섹션7의 상품수정 부분을 수강중입니다!강사님의 코드를 그대로 따라 쳤으나 상품 수정시 에러가 발생하는데 원인을 모르겠습니다. 다만, 아래와 같이 에러페이지가 나오나 홈으로 가서 다시 상품목록을 보면 수정이 반영되어었습니다... package jpabook.jpashop.controller; import jpabook.jpashop.domain.item.Book; import jpabook.jpashop.domain.item.Item; import jpabook.jpashop.service.ItemService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import java.util.List; @Controller @RequiredArgsConstructor public class ItemController { private final ItemService itemService; @GetMapping("/items/new") public String createForm(Model model) { model.addAttribute("form", new BookForm()); return "items/createItemForm"; } @PostMapping("/items/new") public String create(BookForm form) { Book book = new Book(); book.setName(form.getName()); book.setPrice(form.getPrice()); book.setStockQuantity(form.getStockQuantity()); book.setAuthor(form.getAuthor()); book.setIsbn(form.getIsbn()); itemService.saveItem(book); return "redirect:/"; } @GetMapping("/items") public String list(Model model) { List<Item> items = itemService.findItem(); model.addAttribute("items", items); return "items/itemList"; } @GetMapping("items/{itemId}/edit") public String updateItemForm(@PathVariable("itemId") Long itemId, Model model) { Book item = (Book) itemService.findOne(itemId); BookForm form = new BookForm(); form.setId(item.getId()); form.setName(item.getName()); form.setPrice(item.getPrice()); form.setStockQuantity(item.getStockQuantity()); form.setAuthor(item.getAuthor()); form.setIsbn(item.getIsbn()); model.addAttribute("form", form); return "items/updateItemForm"; } @PostMapping("items/{itemId}/edit") public String updateItem(@PathVariable String itemId, @ModelAttribute("form") BookForm form) { Book book = new Book(); book.setId(form.getId()); book.setName(form.getName()); book.setPrice(form.getPrice()); book.setStockQuantity(form.getStockQuantity()); book.setAuthor(form.getAuthor()); book.setIsbn(form.getIsbn()); itemService.saveItem(book); return "redirect:items"; } }package jpabook.jpashop.controller; import lombok.Getter; import lombok.Setter; @Getter @Setter public class BookForm { private Long id; private String name; private int price; private int stockQuantity; private String author; private String isbn; }
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
8분20초 강의에 hello.html이 404에러
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]hello.html 404에러뜹니다 무엇을 건드려야할까요
-
미해결실전! 스프링 데이터 JPA
findById 쿼리 질문
@Test public void findMemberLazy(){ //given //member1 -> teamA //member2 -> teamB Team teamA = new Team("teamA"); Team teamB = new Team("teamB"); teamRepository.save(teamA); teamRepository.save(teamB); memberRepository.save(new Member("member1", 10, teamA)); memberRepository.save(new Member("member2", 20, teamB)); //when Optional<Member> byId = memberRepository.findById(1L); }위와 같은 코드가 있을때 memberRepository.findById(1L); 를 하면 저는 em.find를 통해서 영속성컨테스트를 조회하기 때문에 select쿼리가 안나간다고 생각이 들었습니다.하지만 출력결과 select m1_0.member_id, m1_0.age, m1_0.team_id, m1_0.username from member m1_0 where m1_0.member_id=?select 쿼리가 나가는 것을 확인했습니다.https://www.inflearn.com/questions/1014206/%EA%B0%99%EC%9D%80-pk%EB%A1%9C-%EC%A1%B0%ED%9A%8C%EC%8B%9C-%EC%BF%BC%EB%A6%AC%EA%B0%80-2%EB%B2%88-%EB%82%98%EA%B0%80%EB%8A%94-%EC%9D%B4%EC%9C%A0제 예전 질문에서는 JpaRepository에서의 Method Naming Query의 경우 JPQL로 조회를 하기 때문에 실행전 em.flush()가 일어나서 Direct로 DB에 쿼리가 날아가고 findById는 JpaRepository Interface의 target인 SimpleJpaRepository에 있기 때문에 em.find를 한다고 보았는데 왜 select 쿼리가 나갔는지 궁금합니다.
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
OSIV OFF시 Sercice클래스 최적화
orderService.class를 예를들면 Order Entity를 저장하거나 find하거나 등 entity위주의 코드만 뒀습니다.허나 Order Entity뿐만 아니라 OrderForm, OrderDto를 변환해주는 코드가 필요하다면 각 형태를 변화해주는 Service를 따로 만들어야하는지 아님 하나의 Service클래스안에 다 둬야 하는지 궁금합니다.예로들어 OrderEntity => OrderForm 로바꿔주는서비스, OrderEntity => OrderDto로 바꿔주는 서비스,OrderEntity를 repository에 넘겨주는(DB에 저장하는) 서비스 이런식으로 각각 나눠서 여러개의 클래스로 만들어주나요??
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
궁금한점 있습니다
안녕하세요 강사님 궁금한것이 있어서 질문 남깁니다 public void returnBook(String bookName) { UserLoanHistory targetHistory = this.userLoanHistories.stream() .filter(history -> history.getBookName().equals(bookName)) .findFirst() .orElseThrow(IllegalAccessError::new); //findFist()는 옵셔널로 반홚나다 targetHistory.doReturn(); }이 로직에서 만약 한 책을 빌렸다가 반납하면 그 히스토리를 반납완료 상태로 만들어주고 끝내고다시 그 책을 빌리려고 한다면 새로운 히스토리를 만들어서 List에 저장할텐데 그럼 다시 그책을 반납할 경우 findFirst()를 해서 그 히스토리를 찾아왔을때 이미 반납된 책을 다시 반납하는 행위가 되는것이 아닌건지 궁금해서 질문 드립니다!
-
해결됨스프링 부트 - 핵심 원리와 활용
프로메테우스 기본 설정
안녕하세요.현재 서비스중인 사이트에 액츄에이터 적용중에 있습니다!웹에서는 /actuator/prometheus 접근은 되는데 프로메테우스 화면에서 보면 상태가 down이고 에러가 납니다. URL 링크 연결은 잘돼요..스프링 시큐리티쪽에서 별도로 처리를 해줘야되는건지... 예측되는 부분이 있을까요?
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
Service logic 질문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]현재 ItemService에서 update 로직을 수행하고 있습니다.혹시 Item Entity 에서 update 로직을 수행해도 되나요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
실행시 오류가 생겨서 데이터베이스에 업데이트가 안되는 현상을 겪고 있습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]이렇게 오류가 나는데 혹시 왜그런지 알 수 있을까요?
-
미해결실전! 스프링 데이터 JPA
Entity를 직접 반환할 때 Model에 담아서 보낸다면?
안녕하세요, 강의 정말 잘 듣고있습니다.다름이 아니라Entity 반환에 대해서 질문 있습니다.영한님께서 보안적인 문제, API 유지보수 문제 등 때문에 DTO로 변환하여 반환 하여한다고 하셨는데, 만약 RestApi가 아니라 view로 직접 전달할 때 받아온 Entity를 DTO로 변환 하지 않고 그대로 model에 담아서 보낸다면 어떠한 문제들이 있을까요? 질문 드리기 전에 제가 먼저 생각 해봤을 때 장점은굳이 새로운 dto 객체를 만들지 않아도 된다는 장점이 있고단점으론 불필요한 데이터도 반환 되는 문제와 api의 확장 가능성이 힘들다 정도 있다고 생각되는 더 많은 단점이 있을까요?
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
hello-spring run은 되는데 중지하면 오류가 나요
안녕하세요. 스프링부트는 2.7.15 다운 받았고 SDK는 모두 11로 설정해놨습니다.!!자꾸 옆 부분이 빨간색으로 뜨는 이유는 뭘까요...?RUN도 잘 되는데 중지하면 오류가 납니다...알려주시면 감사하겠습니다.!
-
해결됨토비의 스프링 부트 - 이해와 원리
커스톰 @Conditional 강의에서 질문입니다.
<해결됨>같은 질문 링크입니다. https://www.inflearn.com/chats/757401/x27-conditional%EA%B3%BC-condition-x27-%EA%B0%95%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B83-0-%EC%9D%B4%EC%83%81%EC%9C%BC%EB%A1%9C-%EC%95%88%EB%90%98%EB%8A%94%EB%B6%84%EB%93%A4 https://github.com/tobyspringboot/helloboot/commit/9db7fbb4b665ad0a21e18fa580d378179b44fa92spring boot 3에서 적용해보고 있습니다.제목의 강의에 해당하는 커밋은 위 링크일 것 같습니다. 해당 커밋에서 checkout 한 후, dependencies { implementation('org.springframework.boot:spring-boot-starter-web') { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' } implementation 'org.springframework.boot:spring-boot-starter-jetty' testImplementation 'org.springframework.boot:spring-boot-starter-test' } 위와 같이 jetty를 사용하게 해두고 어플리케이션을 실행하면 Unable to start web server, java.lang.NoClassDefFoundError: jakarta/servlet/http/HttpSessionContext 오류는 jakarta.servlet.http 패키지의 HttpSessionContext 자바 클래스를 찾을 수 없음이렇게 나오는 것 같습니다.어떻게 해결할 수 있을까요..?
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
스프링 JdbcTemplate에서 질문
public class JdbcTemplateMemberRepository implements MemberRepository{ private final JdbcTemplate jdbcTemplate; public JdbcTemplateMemberRepository(DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource); }이 코드 부분에서JdbcTemplate가 org.spring에 영한님 강의에서는 있던데제 꺼에서는 없더라고요. 이거 해결책이 궁금합니다.감사합니다.