본문 바로가기
개발

Kotlin으로 웹개발하기

by 공덕뉸나 2023. 7. 4.

항상 Java로만 개발하다가 Kotlin을 사용하여 프로젝트를 진행한 적이 있다.

이 때 SpringBoot 3버전을 처음 사용해봤는데 설정 방식이 기존 방식과 다르거나 Java와 사용법이 다른 부분들이 있어 몇 가지 정리해 보았다.

코드는 IntelliJ에서 작성된 것임을 참고하자.

 

Querydsl 설정하기 (23.2 기준)

우선 Springboot 버전이 변경되면서 javax가 아닌 jakarta로 변경되었다.

  • build.gradle.kts
plugins{
		...
		kotlin("kapt")version"1.7.10"
}

dependencies {
	  implementation("com.infobip:infobip-spring-data-jpa-querydsl-boot-starter:8.1.0")
    kapt("com.querydsl:querydsl-apt:5.0.0:jakarta")
    kapt("org.springframework.boot:spring-boot-configuration-processor")
}

기존과는 다르게 Q객체가 만들어지는 경로는 별도로 지정해 줄 필요가 없다.

 

  • QuerydslConfig.kt
package com.aceent.y23okr.config

import com.querydsl.jpa.impl.JPAQueryFactory
import jakarta.persistence.EntityManager
import jakarta.persistence.PersistenceContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration
class QuerydslConfig (
    @PersistenceContext
    private val entityManager: EntityManager
    ) {
        @Bean
        fun jpaQueryFactory(): JPAQueryFactory {
            return JPAQueryFactory(this.entityManager)
    }
}

 

설정이 끝난 뒤 Gradle → Tasks - build - clean 한 뒤 other - compileKotlin 실행해서 Q객체 만들어지는지 확인해보자.

참고로 나같은 경우 Autowired 문제가 발생했는데 이는 인텔리제이 버그였고 최신 버전으로 업데이트하니 에러가 사라졌다.

 

Querydsl을 Kotlin으로 개발하다보니 Java로 개발할 때와 차이점이 있었다. 

내가 사용하면서 다른 점 몇 가지를 정리해봤다.

 

Kotlin과 Java의 차이?

 

1. subquery 사용

var subQuery: JPQLQuery<Long>? = JPAExpressions.select(qResult.count())
            .from(qResult)
            .where(qResult.resultId.eq(qResult.resultId))

JPAExpressions를 사용하여 필요한 코드를 작성했다.

 

2. alias 지정

ExpressionUtils.`as`(subQuery, alias명)

subQuery 자리에 alias를 지정하고 싶은 코드를 작성하면 되며 alias명 자리에 alias명을 지정해주면 된다.

나는 별칭을 지정하고 싶은 코드가 서브쿼리여서 subQuery로 따로 선언해 준 뒤 alias명을 지정했다.

 

3. 컬렉션 함수 사용

Kotlin과 Java 코드 비교

 

- Kotlin

fun getProducts(productIds: Set<Long?>?): Map<Long?, ProductResponse?>? {
        val converter = Mappers.getMapper(ProductMapper::class.java)

        return productRepo.findByProductIdIn(productIds)?.map { converter.convertProductListDto(it) }
            ?.associate { (it?.productId ?: 0) to it}
    }

- Java

public Map<Long, ProductListDto> getProduct(Set<Long> productIds) {

        return productRepo.findByProductIdIn(productIds).stream().map(Product::convertListDto)
            .collect(Collectors.toMap(ProductListDto::getProductId, Function.identity()));
    }

 

Kotlin에서는 stream을 사용할 필요 없이 조금 더 간결한 컬렉션 함수를 제공한다.

Kotlin에서 사용된 associate에 대해 간단하게 알아보자.

  • 어떤 데이터를 Map으로 만들어 key, value로 묶어줄 수 있다.
  • Pair의 형태로 key와 value를 만든다.
  • List를 Map 형태로 변형시킬 수 있다.

4. 문자열 비교

대소문자를 구분하지 않고 문자열을 비교할 때 사용법이 달랐다.

코드를 비교해보자.

 

- Kotlin

@JsonCreator
    open fun of(name: String?): UIType? {
        for (obj in values()) {
            if (obj.name.equals(name, ignoreCase = true)) {
                return obj
            }
        }
        return null
    }

Kotlin에서는 equals에서 ignoreCase = true를 지정해주면 된다.

 

- Java

@JsonCreator
    public static City of(String name) {
        for (City obj : City.values()) {
            if (obj.name().equalsIgnoreCase(name)) {
                return obj;
            }
        }
        return null;
    }

Java에서는 equalsIgnoreCase를 사용하면 된다.

 

Kotlin을 사용하면서 Java와 비슷한듯 많이 다른 문법에 처음에는 좀 헤매면서 개발을 진행했다.

하다보니 조금 더 간결한 코드에 익숙해지면 편리할 것 같다는 생각을 했지만 확실히 아직은 Java가 편하다.. 

부족한 부분이 많은 Kotlin 내용 정리이지만 나중에 다시 코틀린에 도전할 나한테도 도움이 되길 바라며 글 마친다! 망망