월 15,400원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
assertThat import 문제
안녕하세요 강의를 진행하던 도중 assertThat의 import가이런 식으로 hamcrest의 import만 존재하는 이유가 무엇일까요?수동으로 import를 작성하면 문제없이 진행은 되고 있습니다.인터넷에 찾아보니 testImplementation 'org.assertj:assertj-core:3.20.2'을 추가하라는데 이미 spring-boot-start-test에 포함되어있어 문제는 없어보입니다.인텔리제이의 오류일까요?감사합니다!
- 해결됨실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
빌드 도구를 Gradle이 아닌 IntelliJ로 했을 때의 인식 오류(해결)
안녕하세요.강의 코드를 작성하던 도중 QUser 클래스가 UserRepositoryCustomImpl에서 인식이 되지 않는 오류가 발생하였습니다. 빌드도 다시 해보고, build 파일을 삭제하고 다시 빌드 해보고, 캐시도 삭제해봤는데도 인식이 안되길래, 혹시나 해서 설정에서 '다음을 사용하여 빌드 및 실행' 부분을 Gradle로 바꾸어주니 바로 인식이 되더라구요. 혹시나 저와 같은 상황에서 삽질하고 계신 분들을 위해 글 남깁니다 ㅎㅎ자세히 다시 읽어보니 일부 플러그인을 사용 시에 제대로 빌드가 되지 않을 수 있다고 적혀있네요..
- 해결됨실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
예외 처리 리팩토링 질문
안녕하세요.강의 들으며 재밌고 공부하고 있습니다. 감사합니다.예외 처리를 util패지키에 모아서 처리하는 것은 이해했습니다. 약간 궁금증 생겨서 문의 남겨봅니다!BookService의 코드 일부분 입니다. 여기서 보면 UserRepository와 BookRepository의 findByName에서 모두 fail()로 예외 처리를 하는데요, 이걸 그냥 리포지토리 계층의 메서드 자체에서 예외를 처리해주면 더 깔끔하지 않을까 하는 궁금증이 생겼습니다. 제가 지금까지 공부하면서는 리포지토리 계층에서 디폴트 메서드를 통해서 처리하는 코드도 봤고, 서비스 계층에서 처리하는 코드도 봐서 어떤 방식을 선호하시는지, 권장 하시는지 궁금합니다! 좋은 강의 감사합니다!
- 미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
갑자기 test시 Build Failed이 발생합니다
안녕하세요.15강까지 강의를 듣고서 강사님처럼 마지막에 전체 테스트를 돌렸더니다음과 같이 빌드가 실패합니다 제가 뭘 잘못한걸까요? ㅜ
- 해결됨실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
assertThat import 문제
assertThat import 안되는 문제선생님 안녕하세요. 이번에 새로 수강하고 있는 수강생입니다.프로젝트 다운 받고 실행을 시켜려고 하는데 실행이 안돼서 따로 설정해서 돌리고 있습니다.Junit5까지는 진행했지만 assertThat 코드를 호출하는 진도에서 실행이 안되고 있습니다.혹시 어떤 방법으로 해결 할 수 있을까요? 찾아도 안나오네요 ㅠㅜbuild.gradle.kts 파일입니다import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id("org.springframework.boot") version "3.0.6" id("io.spring.dependency-management") version "1.1.0" id("java") id("org.jetbrains.kotlin.plugin.jpa") version "1.7.22" // id("org.jetbrains.kotlin.plugin.spring") version "1.7.22" id("org.jetbrains.kotlin.kapt") version "1.7.22" kotlin("jvm") version "1.7.22" kotlin("plugin.spring") version "1.7.22" } group = "com.example.kotlin" version = "0.0.1-SNAPSHOT" java.sourceCompatibility = JavaVersion.VERSION_17 configurations { compileOnly { extendsFrom(configurations.annotationProcessor.get()) } } repositories { mavenCentral() } dependencies { implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect:1.7.22") implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.3") implementation("org.junit.jupiter:junit-jupiter:5.8.1") implementation("com.querydsl:querydsl-jpa:5.0.0") kapt("com.querydsl:querydsl-apt:5.0.0:jpa") kapt("org.springframework.boot:spring-boot-configuration-processor") runtimeOnly("com.h2database:h2") testImplementation("org.assertj:assertj-core:3.21.0") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-web-services") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation("org.jetbrains.kotlin:kotlin-reflect") developmentOnly("org.springframework.boot:spring-boot-devtools") annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation(kotlin("test")) } tasks { test { useJUnitPlatform() } withType<KotlinCompile> { kotlinOptions { freeCompilerArgs = listOf("-Xjsr305=strict") jvmTarget = "17" } } withType<Test> { useJUnitPlatform() } }
- 미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
강사님 안녕하십니까 코틀린 var 선언에 대해서 질문이 있습니다.
var 를 선언하게 되면 setter 를 사용한 것 처럼 외부에서도 클래스 내부 필드에 접근하게 되어 캡슐화가 되지 않아서 setter 를 막아주고 싶습니다. 만약 그렇게 하고싶다면 모든 필드에 private set 을 선언해야할 것 같은데 중복코드의 느낌도 있고, 코틀린의 간결함이랑 멀어진다는 생각이 들었습니다. 보통 실무에서는 도메인, jpa 엔티티를 분리하는 방법이 아닌 set 을 막으려면 어떻게 처리를 하는지 궁금합니다.
- 해결됨실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
DTO의 개수가 많아질 경우에는 어떻게 관리하는게 좋을까요?
안녕하세요 강사님. 별도로 코프링 프로젝트를 진행하던 도중 궁금한 점이 생겨서 질문드립니다!프로젝트를 진행하다 보면 API가 늘어날수록 DTO의 개수도 어마어마하게 많아지는 경우가 많은데, 이 경우 코틀린에서는 어떻게 DTO를 관리하는게 좋을지 고민입니다.코틀린은 자바와 달리 public 클래스를 파일과 1:1로 대응시킬 필요가 없다보니 하나의 파일 마다 각 엔티티별로 연관된 DTO를 모아놓는 사례도 보이더라구요.이런 경우에 기존에는 자바를 쓸때처럼 패키지로 나눠서 DTO를 관리하고 있었는데 1번 그림처럼 하나의 파일에 연관된 DTO를 모아서 관리하는 것과 2번 그림처럼 패키지로 나눠서 DTO를 관리하는 것 중에 어느게 더 좋은 방법일까요?
- 해결됨실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
Service와 Dto
강의를 보던 중에 궁금한 점이 있어서 질문 남겨요!결론부터 말씀드리자면 Service 레이어에서 dto를 사용해도 되는지, dto는 어떤 계층까지 사용해도 되는지에 대해 궁금합니다!저는 보통 사용할 때 UI <-> Controller 사이에서 데이터를 교환하기 위해 dto를 사용하고, Service 에서는 비즈니스 로직 수행 후 엔티티를 반환하는? 그런 식으로 진행해왔는데 강의에서 보면 Sevice에서도 dto를 바로 반환해서 사용하더라구요..dto라는게 data transfer object라는 의미를 가지고 있으니 굳이 UI와 Controller 관계가 아니여도 계층과 계층간의 데이터를 이동할 때 dto를 만들어서 사용해도 되는 건가요?? 감사합니다!!
- 미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
Enum 관련하여 질문 드립니다.
Book Model에서 type을 String으로 지정해 주었는데, Test Code에서 isEqualTo("COMPUTER") 라고 하면 테스트가 실패합니다.출력을 보니 String이 아닌 듯 한데, 그럼 어떤 타입인 것인지 궁금합니다!Spring에서는 Enum으로만 다루고, DB에만 String으로 저장되는 것인가요?좋은 강의 감사드립니다 !
- 미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
isReturn을 val로 선언해서 얻는 이점이 있을까요?
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 선생님의 이전 강의를 들을 때도 신기하면서도 의아하기도 했던 부분인데요그냥 그런가보다 하고 넘어갔는데 보면 볼수록 궁금해서 여쭤보게 되었습니다 fun isReturn(): Boolean { this.status == LoanStatus.RETURNED } 이 코드랑 비교했을 때 val isReturn을 필드처럼 사용하는 게 어떤 부분에서 이점이 있는 것인지 궁금합니다.별다른 이점이 없다면 오히려 팀원들이 익숙한 방향(함수 사용)으로 가는 게 맞는 것 같아서요!!
- 미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
named arguements를 늘 작성하시나요?
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.코틀린에서 제시해주는 컨벤션을 보면 named arguements를 작성하는 걸 권장하고 있고, 선생님께서도 늘 작성하시는 것 같은데 실무에서도 똑같이 적용 중이신지 궁금합니다한 편으로는 가독성이 좋게 느껴지면서도, 한 편으로는 어차피 ide에서 해당 필드가 무엇인지 표기해주는데 공수가 늘어나는 것이 아닌가 고민이 있습니다만약 쓸거라면 아예 컨벤션 룰로 정하고 다 함께 쓰던지 말던지 하는 게 좋을 것 같아서요..
- 미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
와 진짜 대박이네요 디폴트 파라미터 하나로 이렇게 편해질수가 ㅜ
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 자바 스프링에서는 테스트용 생성자 메서드가 있어도, 매번 일일히 null을 넣어준다거나 하는 문제점들이 있어서 결국 Builder를 사용했었는데코틀린에서는 롬복 Builder가 지원되지 않는다고 해서 엄청 고민 중이였습니다근데 이번 강의 보니까 그냥 온전한 객체 만들어주는 팩터리 메서드 하나 만들어놓고 테스트용으로 필요한 인자 값들만 설정해주면 되는 거였군요진짜 미쳤다.. 갓틀린..잘 배워갑니다..
- 해결됨실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
@AfterEach 대신 @Transactional 사용 시 오류
안녕하세요 강사님, 좋은 강의 제공해주셔서 감사합니다 :) "9강. 책 관련 기능 테스트 작성하기" 강의를 듣던 도중 궁금한 점이 생겨 이렇게 질문을 드립니다. 해당 강의에서 @AfterEach()를 사용하며, 아래와 같이 returnBookTest()를 테스트합니다.@AfterEach를 사용했을 경우, 위와 같이 정상적으로 테스트를 통과합니다. 그러나, @AfterEach 대신 @Transacctional을 사용할 경우, 동일한 테스트에서 다음과 같이 실패합니다.@Transactional은 테스트 케이스 종료 후 db를 롤백시킨다고 알고 있습니다. 그러므로 @AfterEach 대신 @Transactional을 사용해도 잘 돌아갈 것으로 예상하고 돌려봤으나, 테스트에 실패한다고 떴습니다.(@Transactional을 사용 시, BookServiceTest class를 open class BookServiceTest로 수정했습니다) 왜 @AfterEach 대신 @Transactional을 사용했을 경우 해당 상황에서 실패하는지 알 수 있을까요?
- 미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
allopen vs spring
안녕하세요 강의 듣다 궁금한 점이 있어 질문드립니다!"org.jetbrains.kotlin.plugin.allopen" 플러그인을 사용하여 allopen으로 지정되어 있는 상태가 아닌가요?그런데, 'org.jetbrains.kotlin.plugin.spring'를 다시 추가해야 하니 두 플러그인의 차이를 모르겠습니다 !
- 해결됨실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
무결성 제약조건이 위배되는 경우에 대한 예외처리에 대해 질문드립니다
안녕하세요 강사님. Kotlin + JPA에 대해 마땅히 질문남길 곳이 없어서 질문드리게 되었습니다😅 Book 엔티티에서 name을 유니크 키로 지정해서 중복된 값을 설정하려고 하면 아래처럼IllegalArgumentException을 던져주게 하는 코드를 작성하고자 했습니다.@Transactional fun saveBook(request: BookRequest) { val book = Book(request.name, request.type) try { bookRepository.save(book) } catch (e: DataIntegrityViolationException) { throw IllegalArgumentException("이미 등록된 도서입니다.") } }그런데 JPA의 영속성 컨텍스트로 인해 @Transactional이 붙은 메소드에서 DataIntegrityViolationException를 처리해주기 위해선 flush()를 직접 호출해서 쿼리를 실행시켜야 한다는 것을 알게되어 아래와 같이 코드를 수정했고, 테스트 코드에서 정상적으로 IllegalArgumentException이 처리되는 것을 확인할 수 있었습니다.@Transactional fun saveBook(request: BookRequest) { val book = Book(request.name, request.type) try { bookRepository.save(book) bookRepository.flush() } catch (e: DataIntegrityViolationException) { throw IllegalArgumentException("이미 등록된 도서입니다.") } }이렇게 코드를 작성해놓고 보니 하나의 메소드에서만 이렇게 무결성 제약조건 위배에 대한 처리를 한다면 상관이 없겠지만 여러 메소드에서 무결성 제약조건을 위배하는 경우에 대해 각기 다른 메시지를 담은 예외를 던지게 된다면 중복 코드가 너무 많이 발생할 것 같다는 생각이 들더라구요. 이런 경우에 아래처럼 확장함수와 람다를 사용해서 예외 처리를 해도 괜찮을까요?inline fun <reified T, ID, R> JpaRepository<T, ID>.flushOrThrow(exception: Throwable, block: JpaRepository<T, ID>.() -> R): R { try { val result = block() flush() return result } catch (e: DataIntegrityViolationException) { throw exception } }@Transactional fun saveBook(request: BookRequest) { val book = Book(request.name, request.type) bookRepository.flushOrThrow(IllegalArgumentException("이미 등록된 도서입니다.")) { save(book) } }이런 방법을 썼을 때 코드가 너무 복잡해지진 않을지, 협업을 하는 경우에 문제가 되진 않을지, 이런 경우가 발생하면 다른 분들은 어떤 방법을 사용하시는지 고민되어 질문 남깁니다!🙏
- 미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
인텔리제이에서 kt 파일에 문법에러가 안뜹니다.
src > main > kotlin 에 있는 파일이 인식되지 않는건지 자동완성도 안되고 문법에러도 안뜨네요..test > kotlin 에 있는 .kt 파일에서는 잘 인식되는데 IDE 설정 문제일까요?
- 해결됨실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
Calculator 클래스에서 참조값이 다르다고 에러가 발생합니다.
안녕하세요. 강의 잘 듣고 있습니다! 7:28 분쯤에 테스트코드를 실행하는데Exception in thread "main" java.lang.IllegalStateException at com.group.libraryapp.calculator.CalculatorTest.addTest(CalculatorTest.kt:16) at com.group.libraryapp.calculator.CalculatorTestKt.main(CalculatorTest.kt:5) at com.group.libraryapp.calculator.CalculatorTestKt.main(CalculatorTest.kt) Process finished with exit code 1라는 에러가 발생하는데 확인해보니 equals 메서드가 오버라이드되어 있지 않아서 발생하는 에러라고 확인을 했습니다. override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is Calculator) return false return number == other.number }그래서 해당 코드를 추가해주었는데요.강의에서는 equals 오버라이드 하지 않아도 에러가 발생 안하는데 저는 발생하는 이유를 잘 몰라서 질문글에 문의를 남겨봅니다! 감사합니다.
- 미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
shared entitymanager proxy for target factory 빨간 줄 안내
import com.querydsl.jpa.impl.JPAQueryFactory import javax.persistence.EntityManager import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @Configuration class QuerydslConfig ( private val em: EntityManager //<--- 빨간 줄 발생 ) { @Bean fun querydsl(): JPAQueryFactory { return JPAQueryFactory(em) } } 안녕하세요! 강의 잘 듣고 있습니다. 들으며 따라치다 궁금한 점이 생겨 질문드려요.강의에 나온대로 configuration을 작성하면 다음과 같이 빨간 줄이 발생하는 데 빌드에는 이상이 없어서 어떤 개념인지 궁금합니다.
- 해결됨실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
테스트코드 질문드립니다.
안녕하세요, 강사님.강사님 덕분에 항상 코틀린 공부 재미있게 하고 있습니다!getUserLoanHistoriesTest2 테스트 코드 관련해서 질문드립니다.제가 강의를 보기 전에 혼자 작성해보았던 코드는 아래와 같은데요.// given val savedUser = userRepository.save(User("A", null)) savedUser.loanBook(Book.fixture("book1")) savedUser.loanBook(Book.fixture("book2")) savedUser.loanBook(Book.fixture("book3")) savedUser.returnBook("book3") userRepository.save(savedUser)테스트는 통과가 되는데, 위와 같이 해도 테스트 코드로서 의미가 있는지, 그런면에서 userLoanHistoryRepository.saveAll()을 사용하는 것이 더 적절한 건지 궁금합니다.
- 미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
9강 returnBookTest() 문의드립니다!
안녕하세요. 9강 returnBookTest() 질문 드립니다.저는 강의 내용을 듣기 전에 미리 제가 테스트코드를 짜보고 이후에 비교해가면서 강의를 수강하는데요. 제가 짠 코드는 실패를 해서 문의드려봅니다.@Test @DisplayName("책 반납 성공") fun returnTest(){ //given val user = User("phd",31) userRepository.save(user) val book = Book("testBook") bookRepository.save(book) val loanHistory = UserLoanHistory(user,"testBook",false) userLoanHistoryRepository.save(loanHistory) //when assertThat(loanHistory.isReturn).isFalse() bookService.returnBook(BookReturnRequest(user.name, "testBook")) //then assertThat(loanHistory.isReturn).isTrue() }저는 loanHistory 엔티티가 영속성 컨텍스트에 있기 때문에 user.userLoanHistroy 엔티티가 바뀔 때 loanHIstroy 객체의 상태 값 도 바뀔거라고 생각했는데요. 생각해보니까 각 엔티티를 save() 하는 메소드들의 트랜잭션이 각각 달라서 영속성 컨텍스트에 loanHistroy 객체가 없었을것 같아요. 뭔가 제대로 확인 할 방법은 없어서 그렇게 유추만 하고 있는데, 제가 유추한 내용이 맞을까요?... 강의 언제나 잘 보고 있습니다. 감사합니다!