묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결토비의 스프링 6 - 이해와 원리
도메인 모델 아키텍처 패턴 추가 리팩토링
추가적인 리팩토링 해보기PaymentService에서 exRate 계산을 Payment가 직접 하도록 할 수 있음exRateProvider를 Payment 안으로 넣어주면됨시간계산은 Clock을 Payment 안으로 넣어줘도 됨추가 리팩토링을 진행하면 Payment의 prepare 메서드의 내부 로직은 한 줄이면 끝남강의 중 말씀 해주신 위의 설명을 토대로PaymentService, Payment 클래스를 리팩토링하고 PaymentTest 클래스를 수정 해 보았습니다.PaymentService의 prepare 메서드@Component public class PaymentService { private final ExRateProvider exRateProvider; private final Clock clock; public PaymentService(ExRateProvider exRateProvider, Clock clock) { this.exRateProvider = exRateProvider; this.clock = clock; } public Payment prepare(Long orderId, String currency, BigDecimal foreginCurrencyAmount) throws IOException { return Payment.createPrepared(orderId, currency, foreginCurrencyAmount, this.exRateProvider, this.clock); } }Payment의 createdPrepared 메서드public static Payment createPrepared(Long orderId, String currency, BigDecimal foreginCurrencyAmount, ExRateProvider exRateProvider, Clock clock) throws IOException { BigDecimal exRate = exRateProvider.getExRate(currency); BigDecimal convertedAmount = foreginCurrencyAmount.multiply(exRate); LocalDateTime validUntil = LocalDateTime.now(clock).plusMinutes(30); return new Payment(orderId, currency, foreginCurrencyAmount, exRate, convertedAmount, validUntil); } PaymentTestclass PaymentTest { @Test void createPrepared() throws IOException { Clock clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); ExRateProviderStub exRateProvider = new ExRateProviderStub(valueOf(1_000)); Payment payment = Payment.createPrepared( 1L, "USD", BigDecimal.TEN, exRateProvider, clock ); Assertions.assertThat(payment.getConvertedAmount()).isEqualByComparingTo(valueOf(10_000)); Assertions.assertThat(payment.getValidUntil()).isEqualTo(LocalDateTime.now(clock).plusMinutes(30)); } @Test void isValid() throws IOException { Clock clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); ExRateProviderStub exRateProvider = new ExRateProviderStub(valueOf(1_000)); Payment payment = Payment.createPrepared( 1L, "USD", BigDecimal.TEN, exRateProvider, clock ); Assertions.assertThat(payment.isValid(clock)).isTrue(); Assertions.assertThat( payment.isValid(Clock.offset(clock, Duration.of(30, ChronoUnit.MINUTES)))).isFalse(); } } 질문제가 진행한 리팩토링이 올바르게 행하였는지 궁금합니다. Test를 진행할 때 exRateProvider를 사용하기 위해서 기존에 작성하였던 ExRateProviderStub오브젝트를 생성하여 테스트를 진행해 주는 것이 맞는지 궁금합니다. 처음에 ExRateProviderStub exRateProvider = null; 을 사용해 봤더니 java.lang.NullPointerException: Cannot invoke "tobyspring.hellospring.payment.ExRateProvider.getExRate(String)" because "exRateProvider" is null이와 같은 에러가 발생하였습니다. 제가 ExRateProvider 객체가 null로 설정해서 발생한 에러인걸 이해 하고, ExRateProvider를 구현한 객체가 필요하기 때문에 ExRateProviderStub오브젝트를 생성하여 exRate를 넣어 주었습니다. 3. ExRateProviderStub오브젝트를 생성하여 exRate(적용환율)을 넣고 생성하는 이유는 실제 api가 아닌 일부 기능을 테스트하기 위해서 저희가 직접 적용환율을 적용해보고 외화금액과 곱해서 계산된게 맞는지 테스트하는 목적이다. 라고 제가 이해하였는데 올바르게 이해한 것인지 궁금합니다. PS. 제가 아직 배운 내용을 완전히 소화하지 못한 부분이 있을 수 있어, 질문에 대한 설명이 부족할 수 있습니다. 혹시 잘못된 부분이나 추가적인 조언이 있다면 피드백 부탁드립니다. 감사합니다.
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
다음으로에 나온 실전 REST API 강의
다음으로에 나온 실전 REST API 강의는 아직 나오지 않은 상태일까요? 아니면 다른 강의에 녹아있는걸까요
-
미해결스프링 시큐리티 OAuth2
시큐리티 완전정복(6.x 개정판) 쿠폰
안녕하세요!!수원님의 시큐리티 강의를 듣고 있습니다!!좋은 강의 해주셔서 감사합니다!다름이 아니라, 제가 메일을 늦게 확인하여서기존 수강생에게 제공되는 50%할인 쿠폰을 사용하지 못했는데,혹시 다시 쿠폰 발급이 가능한지 여쭤봐도 되겠습니까?!감사합니다.
-
미해결Practical Testing: 실용적인 테스트 가이드
안녕하세요 스프링 시큐리티 테스트에 대한 질문이 있습니다.
스프링 시큐리티를 사용하고 시큐리티 설정안에서 아래와 같은 예외 핸들링을 해주었을때http.exceptionHandling(e -> e.authenticationEntryPoint((request, response, authException) -> {CustomResponseUtil.fail(response, "로그인을 진행해 주세요", HttpStatus.UNAUTHORIZED);}));http.exceptionHandling(e -> e.accessDeniedHandler((request, response, accessDeniedException) -> {CustomResponseUtil.fail(response, "권한이 없습니다", HttpStatus.FORBIDDEN);}));컨트롤러 테스트에서 @WebMvcTest(AccountController.class)class AccountControllerTest {테스트를 하면 예외 핸들링이 안되는거 같은데 맞을까요?이러한 해결방법으로@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)이렇게 사용하면될거같은데 1. @WebMvcTest(AccountController.class) 방식으로도 해결할수 있는 방법이 있을까?2. 어떤 방식을 더 추천하실까요?
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
복구 불가능한 예외
강의에서 설명하신 복구 불가능한 예외에 대해서 질문드립니다. 말씀하신 복구 불가능한 예외라는게 구체적으로 어떤것을 의미하는것인지 이해를 잘 못하겠습니다. 앞서 배운것처럼 해당 예외가 발생하면 애플리케이션 로직에서 try~catch를 통해 예외를 잡아서 처리하면 되는것 아닌가요??
-
미해결토비의 스프링 부트 - 이해와 원리
IntelliJ project jenerator spring initailizr
IntelliJ Ultimate를 사용중인데, project jenerator에서 spring initailizr가 나타나지 않습니다. 구글링을 해보아도 못 찾겠고,, 왜 이런 건가요..?
-
미해결스프링 DB 2편 - 데이터 접근 활용 기술
mybatis xml파일을 만드는중 sql문법 질문
[질문 내용]안녕하세요 열심히 강의를 듣던 중 MyBatis 적용1-기본 강의 11:37초 쯤에 and item_name...라는 sql구문을 쓰셨는데 이렇게 앞에 and가 들어가면select * from item where and item_name...이런 식으로 sql문이 쓰여지는거 아닌가요??앞에 and가 꼭 필요한건지 알아서 떼지는건지 궁금합니다!
-
미해결스프링 DB 2편 - 데이터 접근 활용 기술
Q클래스 파일 생성 오류
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]상황: build tool는 Gradle를 사용하고 있습니다.Gradle -> Tasks -> build -> clean Gradle -> Tasks -> other -> compileJava위에 작업을 실행해도 generated폴더에 Q클래스가 생성되지 않습니다. 참고로 generated도 생성되지 않습니다.다른 분들처럼 오류가 발생하지는 않습니다!!
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
SpringMemberFormControllerV1 404에러
SpringMemberFormControllerV1에서 @Controller를 붙이고실행하면 폼이 정상적으로 뜨는데 이렇게@Controller를 주석처리하고@Component@RequestMapping 를 붙이고실행하면 404가 에러가 뜹니다. 게다가이렇게 testcontroller를 해서 실행해도 마찬가지로 404가 에러가 뜹니다 어떻게 해야 되나요?
-
미해결Java 마이크로서비스(MSA) 프로젝트 실습
마이크로 서비스 최종정리 msa 화면 흐름도?를보고 이해되지않아 문의드립니다
authentication-server는 어떤역활인가요?강의 마지막에 볼때..클라이언트가 GateWay-server에 요청할경우 config-server 와 Eureka-server를 보내고아이템서비스와 히스토리 서비스에 데이터 전달하는데authentication-server는 아이템서비스로 봐야하는지아니면 별도의 서버인지 궁금합니다.14장 pdf파일에 두번째 그림보고 궁금해서 문의드립니다.제가 느끼기엔 item-microservice와 유사한 기능이라 생각됩니다만.. 제가 이해하는게 맞을까요?
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
타임리프html
<li>${user.username} = <span th:text="${user.username}"></span></li>제가 html에서 태그를 잘 알지 못해서 어느정도 영역까지 html을 알아야 하는지 감이 안잡혀서요예를 들어 현재 예시에서 해당지역에 th:text로 타임리프를 사용하는것은 알겠지만 span태그와 같은것을 사용해야 한다는것 또한 알아야 하나요?? 아니면 프론트 분들이 span 태그를 사용해야 한다는것을 남겨주시는 건가요??p태그, a태그, tr태그.. 등등 다양하게 변수를 감싸서 사용하는 것 같아서 알아야하는 부분인지 궁금합니다
-
미해결견고한 결제 시스템 구축
R2DBC 관련해서 질문 드립니다.
안녕하세요.강의 잘 듣고 있습니다.R2DBC로 실습 환경을 구축해주셨는데요. R2DBC 이용하면서 DatabaseClient 를 이용해주셨는데요.혹시 Jooq 를 이용안하신 이유가 있을까요?그리고 실무에서도 DatabaseClient 를 이용하시는지 궁금합니다. 추가로 DatabaseClient 를 사용시에 동적 쿼리를 어떻게 작성을 해야 하는지 팁 주시면 감사하겠습니다! (where 절 고정이 아닌 특정값이 있을 경우에만 where절 생성 이라던지 ㅎ ) 감사합니다!
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
bindingResult 질문입니다
MVC2 강의를 듣고 복습하는 겸 직접 상품관리 페이지를 만들어보고 있습니다.validation 부분에서 상품 추가까지는 잘 작동하게 되었는데, 수정 부분에서 문제가 생겼습니다.어느 부분이 문제인지 아무리 찾아봐도 모르겠어서 질문드립니다.@Data public class ItemUpdateForm { @NotNull private Long id; @NotBlank private String itemName; @NotNull @Range(min = 1000, max = 1000000) private Integer price; private Integer quantity; public ItemUpdateForm(Long id, String itemName, Integer price, Integer quantity) { this.id = id; this.itemName = itemName; this.price = price; this.quantity = quantity; } }@PostMapping("/edit/{itemId}") public String editItem(@PathVariable Long itemId, @Validated @ModelAttribute("item") ItemUpdateForm form, BindingResult bindingResult) { log.info("*** edit post 요청 ***"); log.info("itemUpdateForm: {}", form); if (bindingResult.hasErrors()) { log.info("bindingResult= {}", bindingResult); return "item/edit"; } itemService.updateItem(itemId, form); return "redirect:/item/detail/{itemId}"; }<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .field-error { border-color: red; color: red; } </style> </head> <body> <div> <div th:replace="fragment/bodyHeader :: bodyHeader" /> <div> <h2>상품 수정</h2> </div> <form method="post" th:object="${item}" th:action> <div> <label>ID</label> <input type="text" th:field="*{id}" readonly> </div> <div> <label>상품명</label> <input type="text" th:field="*{itemName}" th:errorclass="field-error" placeholder="상품명을 입력하세요."> <div class="field-error" th:errors="*{itemName}"> 상품명 오류 </div> </div> <div> <label>가격</label> <input type="text" th:field="*{price}" th:errorclass="field-error" placeholder="가격을 입력하세요."> <div class="field-error" th:errors="*{price}"> 가격 오류 </div> </div> <div> <label>수량</label> <input type="text" th:field="*{quantity}" th:errorclass="field-error" placeholder="수량을 입력하세요."> <div class="field-error" th:errors="*{quantity}"> 수량 오류 </div> </div> <button type="submit">저장</button> </form> </div> </body> </html>상품 수정 페이지에서 다른 경우에는 잘 작동하는데, typeMismatch가 발생한 경우에는 bindingResult에 다른 에러는 담기지 않고 typeMismatch 에러만 담기고 있습니다.다음은 에러 코드입니다.2024-08-25T17:50:41.455+09:00 INFO 15096 --- [nio-8080-exec-3] community.demo.web.ItemController : *** edit post 요청 ***2024-08-25T17:50:41.455+09:00 INFO 15096 --- [nio-8080-exec-3] community.demo.web.ItemController : itemUpdateForm: ItemUpdateForm(id=1, itemName=, price=10, quantity=null)2024-08-25T17:50:41.455+09:00 INFO 15096 --- [nio-8080-exec-3] community.demo.web.ItemController : bindingResult= org.springframework.validation.BeanPropertyBindingResult: 1 errorsField error in object 'item' on field 'quantity': rejected value [100a]; codes [typeMismatch.item.quantity,typeMismatch.quantity,typeMismatch.java.lang.Integer,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [item.quantity,quantity]; arguments []; default message [quantity]]; default message [Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; For input string: "100a"]2024-08-25T17:50:41.456+09:00 WARN 15096 --- [nio-8080-exec-3] actStandardFragmentInsertionTagProcessor : [THYMELEAF][http-nio-8080-exec-3][item/edit] Deprecated unwrapped fragment expression "fragment/bodyHeader :: bodyHeader" found in template item/edit, line 15, col 10. Please use the complete syntax of fragment expressions instead ("~{fragment/bodyHeader :: bodyHeader}"). The old, unwrapped syntax for fragment expressions will be removed in future versions of Thymeleaf. 다음은 코드파일입니다.https://drive.google.com/file/d/1aDFEYzno4e6slRN8K2Tm5EFEYUb5WDJP/view?usp=sharing
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]https://drive.google.com/drive/folders/1jHYkBAHDuUoSr5hjn0Kp5CzTAWLem3Zu?usp=drive_link 코드를 쭉 작성해봤는데 마지막에 submit할 때 whiteError페이지가 나옵니다. gpt에 해결책을 물어봤을 때에러 로그를 보면, Thymeleaf 템플릿을 처리하는 동안 문제가 발생한 것을 알 수 있습니다. 특히, item.orderItems[0].item.name라는 표현식에서 문제가 발생했습니다.에러의 원인에러 메시지 중에서 가장 중요한 부분은 다음과 같습니다:Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1025E: The collection has '0' elements, index '0' is invalid 이 메시지는 item.orderItems[0]에서 인덱스를 사용하여 컬렉션의 첫 번째 요소에 접근하려고 했지만, orderItems 컬렉션이 비어 있어서 인덱스 0이 유효하지 않다는 것을 의미합니다. 즉, orderItems 컬렉션이 비어있거나 null일 때 이 표현식을 평가하려다가 오류가 발생한 것입니다.해결 방법컬렉션이 비어있을 경우에 대한 처리:Thymeleaf 템플릿에서 컬렉션이 비어있는 경우를 대비하여 조건문을 추가할 수 있습니다. 예를 들어, orderItems가 비어있지 않은 경우에만 접근하도록 할 수 있습니다.<div th:if="${item.orderItems.size() > 0}"> <span th:text="${item.orderItems[0].item.name}">Item Name</span> </div> 안전한 접근을 위한 기본값 제공:orderItems 컬렉션이 비어있을 때 안전하게 처리하기 위해, th:text 속성에서 기본값을 제공할 수 있습니다.<span th:text="${item.orderItems.size() > 0 ? item.orderItems[0].item.name : 'No items'}">Item Name</span> 서버 측에서 데이터 처리:서버 코드에서 orderItems가 비어있는 경우에 대해 적절히 처리하도록 할 수도 있습니다. 예를 들어, orderItems가 비어있다면 기본값을 설정하거나, 비어있음을 표시하는 별도의 로직을 추가할 수 있습니다.템플릿 구조 개선:템플릿 구조를 개선하여, orderItems가 비어있을 때는 특정 HTML 요소를 렌더링하지 않도록 할 수 있습니다.결론에러의 원인은 item.orderItems[0].item.name에서, orderItems 컬렉션이 비어있을 때 인덱스 0에 접근하려고 했기 때문입니다. 이를 해결하려면 위의 방법 중 하나를 사용하여, orderItems가 비어있는 경우를 안전하게 처리해야 합니다. 템플릿에서 Thymeleaf의 조건문이나 기본값 제공 기능을 사용하여 이 문제를 해결할 수 있습니다. 이런식으로 나왔고 h2데이터베이스의 order자체에 값이 잘 저장된 것은 확인했는데 무엇이 문제인지 잘 모르겠어서 질문드립니다
-
해결됨서버개발자 과제전형 완벽가이드 - 1편
포트폴리오 질문
이 강의를 기반으로 포트폴리오도 만들어보려고합니다. 포트폴리오 만들때 여러가지 기술들을 더 적용해보는게 좋을까요 아니면 강의에 나온 기술만 활용해도 충분할까요?
-
미해결스프링 핵심 원리 - 기본편
스프링부트 질문이 있습니다
제가 현재 자바와 스프링 부트를 함께 배우는 비전공자 부트 캠프를 다니는 중인데부트캠프에서 자세한 내용은 배우기 시간이 촉박한 관계로 강사님이 자세한 설명은 스킵합니다. 이로 인해 비전공자임에도 개발자의 꿈을 꾸는 저는 추가로 강의를 들어서 보충학습을 하고자하는데현재 제가 강의로 배우고 있는 내용은 스프링으로 심화적인 스프링부트의 이해를 위해서 필요한지 아니면 스킵하고 바로 스프링 부트쪽으로 넘어갈지 고민이되서 질문드립니다
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
테스트코드 데이터소스 분리
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]테스트 application.properties와 메인의 application.properties의 설정으로테스트와 실제 어플의 db 동작을 분리 할수 있는데만약에 테스트에서도 테스트 패키지 혹은 테스트 별로db를 다르게 사용하려면 어떻게 해야하나요?단위 테스트 할 기능중에 db종속적인 부분이 있어서질문 드려요!
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
RequestMappingHandlerMapping 의 작동 과정에 대한 질문입니다
@RequestMapping이 컨트롤러에 붙지 않고 내부 메서드에만 붙어도 핸들러(컨트롤러)로 인식한다고 보면 될까요?
-
미해결실전! 스프링 데이터 JPA
EntityManager DI
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.EntityManager을 @RequiredArgsConstructor을 통한 생성자 주입을 통해 넣는것이 이해가 안됩니다. EntityManeger을 bean으로 생성하지 않았는데 오류없이 실행된 이유는 다른 파일에서 EntityManager을 @PersistenceContext을 통해 bean으로 생성했기 때문인가요??
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
네임드락과 분산락
네임드락에 대해 더 공부해보려고 구글링하는데네임드락이 MySQL에서 제공하는 분산락이라고 하더라구요 그럼 네임드락이 여러 개로 스케일 아웃된 DB 환경 혹은 스케일 아웃된 서버에서도 잘 동작한다는건데전자의 경우 (DB 분산) 네임드락도 결국 쿼리로 하나의 데이터베이스(MySQL)의 메타데이터에 락을 거는 것이기 때문에 다른 데이터베이스에서는 그게 안걸려 정합성 문제 해결이 안되지 않나요? 이렇게 되면 분산락이 아닌 것 같은데 왜 분산락일까요?ㅜㅜ후자의 경우라면 비관적락, 낙관적락, 네임드락 모두 잘 동작할 것 같은데(데이터베이스는 하나인 경우) 왜 분산락이라는게 따로 있는 걸까요..?