'섹션 5. 클라우드에서 내 서비스 띄우기: AWS로 배포하기' - '26. AWS EC2 서버에 애플리케이션 배포' 강의를 듣던 중 문제가 생겨 AI를 활용해 문제를 해결해보다가 해결을 못 했습니다. 이미 너무 많이 만져서 원래 상태로 복구하긴 힘들 거 같네요. 강의를 처음부터 다시 들으면서 다시 만들어야 할까요? 깃허브 같이 중간 결과물을 다운 받을 수 있는 곳은 없나요?
안녕하세요, 토비님. 강의 초반에 말씀해 주신 것처럼, 리팩토링 과정에서 “제가 했다면 어떻게 했을까”를 계속 생각해 보며 토비님의 의사결정 과정을 따라가고 있습니다. MemberService.register() 메소드에서 emailSender.send(...) 를 sendWelcomeEmail() 로 분리하시는 과정을 보며 두 가지 고민이 생겼습니다. 첫째, 환영 이메일의 내용이나 정책이 변경될 때마다 MemberService 의 코드가 함께 변경되어야 한다면, 이는 SRP 위반에 해당하지 않는지에 대한 고민입니다. 이 경우 환영 이메일 전송에 대한 책임을 EmailSender 인터페이스 쪽으로 옮기는 것이 더 적절한지 궁금해졌습니다. 둘째, 만약 EmailSender 인터페이스에 해당 메소드를 추가한다면, 구현체가 늘어날수록 인터페이스가 비대해지거나 향후 구현 복잡도가 증가할 수 있다고 느꼈습니다. 이런 경우 default method 로 제공하는 방식에 대해서는 어떻게 생각하시는지도 궁금합니다.
22. REST 방식 컨트롤러 만들기(2)에서 포스트맨으로 글 등록 테스트 할 때 complete 필드가 없는 경우 Bad Request 400에러가 나는 걸 확인했습니다. { "title": "Test title", "writer": "testuser", "complete": false, "dueDate": "2026-02-04" } 위와같이 complete필드를 추가하니 잘 되었는데, 문제는 29강에서처럼 브라우저 화면에서 테스트 해보니 아래와같이 400에러가 발생합니다. 여기도 마찬가지로 입력폼에서 complete필드가 없어서 그런것 같은데 강의에서는 등록이 잘 되는게 이해가 안되네요. 섹션4까지 완성된 코드를 다운받아서 실행해보았지만 위의 사진처럼 브라우저에서 등록 시 400에러가 발생합니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 이 Like 검색에서 그냥 where like '%ㅁ%' 이렇게 앞뒤 같이 체크하는거면 그냥 Like 보다는 findByItemNameContaining 이렇게 Containing 을 쓰는게 더 맞을 거같은데 혹시 이걸 안쓰고 like 를 쓴 이유가 별도로 있을까요?!
api gateway 에서 jwt 검증을 해서 분기를 시키는데, 세션-쿠키 방식일때도 api-gateway에서 처리 하나요 ? 만약 세션-쿠키 방식일 때,user-service 에서 인증 처리한다고 하면, order 서비스에서 인증이 필요한 경우, user-service로 http 통신으로 인증을 확인하나요 ?
'섹션 3. 데이터를 저장하기, MySQL로 시작하기' - '17. MySQL 데이터베이스 설정하기 (Docker)' 질문입니다. 제가 기존에 만들어둔 도커 컨테이너도 3306 포트를 쓰고 있어서 포트 문제 때문에 기존 컨테이너를 삭제하고 진행했습니다. 여러 컨테이너를 만들려면 어떻게 해야되나요? 안쓰는 포트 아무대나 만들면 되나요? 예를 들어 지금 3306 포트를 쓰고 있으니까 다음에 만들 컨테이너는 3307을 쓰면 되는건가요? docker run --name mysql-twitter \ -e MYSQL_ROOT_PASSWORD=root123 \ -e MYSQL_DATABASE=twitterdb \ -e MYSQL_USER=dev \ -e MYSQL_PASSWORD=dev123 \ -p 3306:3306 \ -d \ mysql:9.3 3306 포트 말고 다른 포트를 사용할 경우 위 명령어에서 -p 3306:3306 는 어떤 식으로 바꾸면 되나요?
'섹션 2. 데이터 주고받기, Spring Boot API 서버 만들기' - '10. Postman으로 API 테스트하기' 질문 입니다. 오타로 @PostMapping과 @GetMapping의 URL이 불일치해서 포스트맨에서 제대로된 값이 안나왔더라고요. 이럴 경우 오류도 안떠서 해결하기가 힘든데, URL 오타를 방지하는 방법이 있을까요?
안녕하세요~ 현재 아래 기술 스택을 사용한 API 서버가 존재합니다. Spring Boot 3 Kotlin JPA(JDBC) WebClient 예를 들면 아래와 같이 구성되어 있고, @RestController class SampleController( private val service: SampleService ) { @GetMapping("/sample") suspend fun start() { service.withoutDispatchers() } } @Component class SampleClient { private val webClient: WebClient by lazy { WebClient.builder() .baseUrl("https://api.com") .build() } suspend fun fetch(): Int { return webClient.get() .uri { uriBuilder -> uriBuilder.path("/number").build() } .retrieve() .awaitBody() } } interface SampleRepository : JpaRepository<SampleEntity, Long> @Service class SampleService( private val client: SampleClient, private val repository: SampleRepository, ) { suspend fun withoutDispatchers(): Int = coroutineScope { // non-blocking val deferred: Deferred<Int> = async { client.fetch() } // blocking val entity: List<SampleEntity> = repository.findAll() deferred.await() + entity.size } } Controller에서부터 suspend function으로 시작되면 Dispatchers.Unconfined를 사용하여 API 요청에 의해 할당받은 Tomcat 스레드를 그대로 사용하는 것으로 알고 있습니다. 이후 Service 레이어에서 suspend function이 동일하게 Dispatchers.Unconfined를 유지하기 때문에 요청 시 Tomcat 스레드는 그대로 사용되고 WebClient 요청 시 Dispatchers.IO를 사용하면, Tomcat 스레드와 별개로 Dispatchers 스레드 풀에서 스레드를 가져와 사용하는 것으로 알고 있습니다. 1번의 요청에서 Tomcat 스레드 1개 + Dispatchers 스레드 1개 = 총 2개가 사용됩니다. WebClient 요청 시 Dispatchers.IO를 생략하고 Dispatchers.Unconfined를 유지하면 , 코루틴의 재개 시 WebClient 응답을 동일한 Tomcat 스레드가 처리하게 하여 스레드 1개만을 사용하는 것이 서버에 더 효율적이지 않을까? 하는 생각이 들었습니다. 스레드가 Blocking되어도 WebClient의 NIO 이벤트 루프에 들어온 요청은 처리되어 응답에 대한 처리만 대기하고 있을 것이고, 테스트해보았을 때도 WebClient의 요청을 시작한 스레드가 JPARepository를 사용하는 코드에 의해 Blocking되어도 await()에서 문제 없이 응답을 받아올 수 있었습니다. 혹시 제가 생각하지 못한 또 다른 문제가 있을까요? 제가 혹시 잘못 알고 있는 부분이 있거나 Dispatchers.IO를 생략하지 못 하는 이유가 있다면 설명해주시면 감사하겠습니다!
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter 여기 보시면 현재 기준 버전이 4.0.1 나왔습니다. build.gradle의 dependencies에 //MyBatis 스프링 부트 4.0.1 추가 implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:4.0.1' 로 버전 수정하면 잘 됩니다.
자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
ddl-auto: create로 설정되어 있어서 자동으로 테이블이 생성되게 되어 있다는 말은 이해가 되는데요. BOOK, USER, USER_LOAN_HISTORY의 테이블 컬럼명과 컬럼의 특성등은 따로 어디에 명시해둬야 참고를 해서라도 만들지 않나요? mysql에서 만들때는 저희가 직접 console창에서 직접 설정해서 create해줬는데, 해당 테이블 구조는 테이블이 생성될때 무엇을 참고해서 만들고 있는건지 문의 드립니다. 감사합니다.
소스 내용은 @Override public TodoDTO get(Long tno) { Optional<Todo> result = todoRepository.findById(tno); Todo todo = result.orElseThrow(); TodoDTO dto = modelMapper.map(todo, TodoDTO.class); return dto; } 에러 메시지 입니다. 참말로... 이해를 못하겠네요... 테스트가 계속 실패하는데 어디를 확인을 해봐야 할까요? ㅡㅡ;; (등록 testRegister는 잘 test 되고요)
services: springboot-twitter: container_name: springboot-twitter image: springboot-twitter:latest ports: - "8080:8080" environment: - SPRING_DATASOURCE_URL=jdbc:mysql://mysql-twitter:3306/twitterdb - SPRING_DATASOURCE_USERNAME=dev - SPRING_DATASOURCE_PASSWORD=dev123 networks: - twitter-network depends_on: mysql-twitter: condition: service_healthy mysql-twitter: container_name: mysql-twitter image: mysql:9.3 environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: twitterdb MYSQL_USER: dev MYSQL_PASSWORD: dev123 healthcheck: test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ] interval: 10s timeout: 5s retries: 5 ports: - "3307:3306" networks: - twitter-network networks: twitter-network: driver: bridge 로컬 환경에서 mysql에 대한 이미지가 떠있어야 spring boot application을 실행해야 DB connection도 잘 이루어진다고 이해했습니다. 여기서 궁금한 점이 있습니다. 로컬 환경에서 docker compose up -d를 한 경우 compose 파일에서 spring boot 이미지도 함께 띄워놔서 application을 실행할 때 8080 already in use 오류가 발생합니다. 이렇게 될 경우에는 docker-compose.yaml을 수정하거나 docker compose up -d mysql-twitter 커맨드를 실행해서 mysql만 띄워야 하는지 궁금합니다.
docker buildx build --platform linux/amd64 -t {이미지 이름} . 해당 명령어를 통해서 Dockerfile 기반으로 Docker Hub에 컨테이너를 생성하고, Docker Compose를 통해서 생성된 컨테이너 안에 이미지들을 다운받아와서 실행되는 구조가 맞는걸까요 ??
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 안녕하세요 코드를 따라 치는 과정에서 아래와 같이 작성 했더니 BeanCreationException 이 발생하는 것을 확인 할 수 있었습니다. public void dbInit1(){ Member member = new Member(); member.setName("userA"); member.setAddress(new Address("서울", "1", "111")); em.persist(member); Book book = new Book(); book.setName("JPA1 BOOK"); book.setPrice(10000); book.setStockQuantity(100); em.persist(book); Book book2 = new Book(); book.setName("JPA2 BOOK"); book.setPrice(20000); book.setStockQuantity(100); // book2.setName("JPA2 BOOK"); // book2.setPrice(20000); // book2.setStockQuantity(100); em.persist(book2); OrderItem orderItem1 = OrderItem.createOrderItem(book, 10000, 1); OrderItem orderItem2 = OrderItem.createOrderItem(book2, 20000, 2); Delivery delivery = new Delivery(); delivery.setAddress(member.getAddress()); em.persist(delivery); Order order = Order.createOrder(member, delivery, orderItem1, orderItem2); em.persist(order); } 이때 위의 코드에서 주석 처리된 부분처럼 고쳤더니 정상적으로 코드가 실행되는 것을 확인했습니다. 그런데 이게 어떤 문제에서 오류가 발생한건지 정확히 알 수 없어 질문드립니다. 처음에는 book2의 값이 아무것도 없어서 null에 관한 엔터티 제약조건 관련해서 문제가 발생했나 생각해지만 notnull 같은 제약조건이 없었고 Book이 Item과 상속관계이고 싱글 테이블 전략을 사용해서 DTYPE 값이 book2 생성시 자동으로 생성 된다고 기억해서 특별히 값이 비었다고 생기는 오류가 아니라고 생각이 들었습니다. 결론적으로는 정확히 어떤 원인에서 발생한 문제인지 궁금해서 질문 남깁니다.
섹션 19 부분은 예전에 강의하셨을 때 쓰신 스프링부트 2점대 버전을 3점대 버전으로 업그레이드하는 강의인가요? 최신 강의 기준 업데이트 하신 3점대 버전으로 강의를 듣고 있는데 섹션 19에서 강의가 정확히 어떤 강의인지 궁금합니다. 만약 2점대 버전을 3점대 버전으로 업그레이드 하는 강의라면, 섹션 19에서 분산 트레이싱, swagger, kubernates 부분만 들어도 되는걸까요?