[Project]Kotlin+SpringBoot+Querydslを使用してアドレスAPIを検索
20350 ワード
きっかけ
Stack
Server : Spring Boot, Spring Data Jpa, Querydsl
Database : MySQL
プロセス
1.Querydslバインド
build.gradle.kts
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.6.6"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
kotlin("jvm") version "1.6.10"
kotlin("plugin.spring") version "1.6.10"
kotlin("plugin.jpa") version "1.6.10"
kotlin("kapt") version "1.6.10" // kapt 등록
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_11
// Q파일 생성 경로
sourceSets["main"].withConvention(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::class) {
kotlin.srcDir("$buildDir/generated/source/kapt/main")
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
runtimeOnly("com.h2database:h2")
testImplementation("org.springframework.boot:spring-boot-starter-test")
runtimeOnly("mysql:mysql-connector-java")
// querydsl
api("com.querydsl:querydsl-jpa:")
kapt(group = "com.querydsl", name = "querydsl-apt", classifier = "jpa")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "11"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
application.yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/[dbname]?serverTimezone=UTC&characterEncoding=UTF-8
driver-class-name: com.mysql.cj.jdbc.Driver
username: [userid]
password: [userpassword]
jpa:
hibernate:
# ddl-auto: create
properties:
hibernate:
dialect: com.example.practice_qdsl.Dialect.CustomDialect # 커스텀한 Dialect 경로
# show_sql: true
format_sql: true
logging:
level:
org:
hibernate:
SQL: debug
type:
descriptor:
sql: trace
querydslConfig
package com.example.practice_qdsl.Configuration
import com.querydsl.jpa.impl.JPAQueryFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import javax.persistence.EntityManager
import javax.persistence.PersistenceContext
@Configuration
class QuerydslConfig(
@PersistenceContext
private val entityManager: EntityManager
) {
@Bean
fun jpaQueryFactory(): JPAQueryFactory {
return JPAQueryFactory(this.entityManager)
}
}
2.JPA Dialectを使用してマッチング用の機能を登録する
Dialect?
package com.example.practice_qdsl.Dialect
import org.hibernate.dialect.MySQL57Dialect
import org.hibernate.dialect.function.SQLFunctionTemplate
import org.hibernate.type.StandardBasicTypes
class CustomDialect: MySQL57Dialect() {
init{
registerFunction("match", SQLFunctionTemplate(StandardBasicTypes.INTEGER, "match(?1) against (?2 in boolean mode)"))
}
}
MySQL 57 Dialectを継承した後、FullText Searchを使用するために、構造関数でregSiterFunctionを使用してmatch-atting関数を登録します.
検索モードは、NATURAL LANGUAGE MODEとBOOLEAN MODEの2種類があります.ナチュラル言語検索モードでは、テーブル全体の50%以上のレコードに検索したキーワードがある場合、そのキーワードは検索語として意味がないと判断し、検索結果から除外する.もちろんアドレスデータは除外できませんので、BOOLEAN MODEを選択して各キーワードの含むか含まないかを判断します.
typeがStringではなくINTEGERの理由はExpressionsstringTemplate
Selectセクションでのみ使用可能です.(理由はよくわかりませんが…ご存知の方がいらっしゃいましたら、メッセージをお願いしますハハ)
3.エンティティとレポート
Entity
package com.example.practice_qdsl.Entity
import javax.persistence.*
@Entity(name = "ADDRESS_INFO")
data class AddressInfo(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
var id: Long = 0,
@Column(name = "address")
val address: String,
)
AddressInfoRepositoryCustom
package com.example.practice_qdsl.Repository
import com.example.practice_qdsl.Entity.AddressInfo
interface AddressInfoRepositoryCustom {
fun getAddressList(keyword : String) :List<AddressInfo>
fun getLists():List<AddressInfo>
}
AddressInfoRepositoryCustomImpl
package com.example.practice_qdsl.Repository.Impl
import com.example.practice_qdsl.Entity.AddressInfo
import com.example.practice_qdsl.Entity.QAddressInfo
import com.example.practice_qdsl.Repository.AddressInfoRepositoryCustom
import com.querydsl.core.types.dsl.Expressions
import com.querydsl.core.types.dsl.NumberTemplate
import com.querydsl.jpa.impl.JPAQueryFactory
import org.springframework.stereotype.Repository
@Repository
class AddressInfoRepositoryCustomImpl(
val jpaQueryFactory: JPAQueryFactory,
) : AddressInfoRepositoryCustom {
override fun getAddressList(keyword: String): List<AddressInfo> {
val booleanTemplate: NumberTemplate<*> = Expressions.numberTemplate(Integer::class.java,
"function('match',{0},{1})",
QAddressInfo.addressInfo.address, keyword)
return jpaQueryFactory.select(QAddressInfo.addressInfo).from(QAddressInfo.addressInfo).where(booleanTemplate.gt(0)).fetch()
}
override fun getLists(): List<AddressInfo> {
return jpaQueryFactory.selectFrom(QAddressInfo.addressInfo).fetch()
}
}
Expression 4.性能比較
1) %Like%
2) match-against
すなわち,検索語が長ければ長いほど性能が高くなり,マッチング対>>>>>%Like%となる.
注意:https://idlecomputer.tistory.com/337
Reference
この問題について([Project]Kotlin+SpringBoot+Querydslを使用してアドレスAPIを検索), 我々は、より多くの情報をここで見つけました https://velog.io/@daehoon12/Project-Kotlin-Spring-Boot-Querydsl을-이용한-주소-검색-APIテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol