不可否认的是 JPA 使用是非常方便的,极简化的配置,只需要使用注解,无需任何 xml 的配置文件,语义简单易懂,但是,以上的一切都建立在单表查询的前提下的,我们可以使用 JPA 默认提供的方法,简单加轻松的完成 CRUD 操作。
但是如果涉及到多表动态查询, JPA 的功能就显得有些捉襟见肘了,虽然我们可以使用注解 @Query
,在这个注解中写 SQL 或者 HQL 都是在拼接字符串,并且拼接后的字符串可读性非常的差,当然 JPA 还为我们提供了 Specification
来做这件事情,从我个人使用体验上来讲,可读性虽然还不错,但是在初学者上手的时候, Predicate
和 CriteriaBuilder
使用方式估计能劝退不少人,而且如果直接执行 SQL 连表查询,获得是一个 Object[]
,类型是什么?字段名是什么?这些都无法直观的获得,还需我们手动将 Object[]
映射到我们需要的 Model
类里面去,这种使用体验无疑是极其糟糕的。
这一切都在 QueryDSL 出世以后终结了, QueryDSL 语法与 SQL 非常相似,代码可读性非常强,异常简介优美,,并且与 JPA 高度集成,无需多余的配置,从笔者个人使用体验上来讲是非常棒的。可以这么说,只要会写 SQL ,基本上只需要看一下示例代码完全可以达到入门的级别。
网上很多例子是用Maven来生成QueryDSL的Q文件的例子,为了方便使用Gradle的网友,我特意写了一份用Gradle来生成QueryDSL的Q文件的例子.
废话不说,直接上build.gradle
源码
buildscript {
repositories {
mavenLocal()
maven { url "https://maven.aliyun.com/nexus/content/groups/public/" } //优先使用阿里的镜像
mavenCentral()
}
dependencies {
//classpath 'org.apache.commons:commons-csv:1.0'
}
}
plugins {
id 'org.springframework.boot' version '2.3.12.RELEASE'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
ext {
queryDslVersion = '4.4.0'
querydslGeneratedSourcesDir = file("$projectDir/src/main/generated")
}
sourceSets {
main {
java {
srcDirs += [querydslGeneratedSourcesDir]
}
}
}
group = 'org.wjw'
version = '1.7.3'
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
[compileJava, compileTestJava]*.options*.compilerArgs << "-parameters" << "-Xlint:deprecation" //编译参数
[compileJava, compileTestJava]*.options*.deprecation = true
//单独运行QueryDSL的APT来生成Q源代码
task runAPT(type: JavaCompile) {
doFirst {
/*
* This is a workaround to delete the file that will be created by the annotation processor if it already exists.
* There is a known bug in the Java compiler and JDK 8 which should be fixed at JDK 9.
* http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8067747 <-- Master report
* http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8146348 <-- duplicates master report
*/
if ( querydslGeneratedSourcesDir.exists() ) {
FileCollection collection = files { querydslGeneratedSourcesDir.listFiles() }
collection.each { delete it }
}
querydslGeneratedSourcesDir.mkdirs()
println "classpath:"+classpath.getFiles()
println "Generate QueryDsl CLass..."
println "options:"+options
println "options.compilerArgs:"+options.compilerArgs
println "AnnotationProcessorPath for $name is ${options.getAnnotationProcessorPath().getFiles()}"
}
source = sourceSets.main.java.srcDirs
destinationDir = sourceSets.main.java.outputDir
classpath = configurations.compileClasspath + configurations.annotationProcessor
options.annotationProcessorPath = classpath //@wjw_note: 设置这个annotationProcessorPath很关键
options.encoding = 'UTF-8'
options.deprecation = true
options.compilerArgs += ["-parameters","-Xlint:deprecation"]
options.compilerArgs += ['-proc:only']
options.compilerArgs += ['-processor', 'com.querydsl.apt.jpa.JPAAnnotationProcessor']
options.compilerArgs += ['-s', querydslGeneratedSourcesDir] //设定生成的Q类存放的位置
options.compilerArgs += ["-Aquerydsl.excludedPackages=xyz.erupt.upms,xyz.erupt.bi"] //设定QueryDsl要排除的包列表(逗号来分割)
}
compileJava {
doFirst {
/*
* This is a workaround to delete the file that will be created by the annotation processor if it already exists.
* There is a known bug in the Java compiler and JDK 8 which should be fixed at JDK 9.
* http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8067747 <-- Master report
* http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8146348 <-- duplicates master report
*/
if ( querydslGeneratedSourcesDir.exists() ) {
FileCollection collection = files { querydslGeneratedSourcesDir.listFiles() }
collection.each { delete it }
}
querydslGeneratedSourcesDir.mkdirs()
println "Generate QueryDsl CLass..."
println "options:"+options
println "options.compilerArgs:"+options.compilerArgs
println "AnnotationProcessorPath for $name is ${options.getAnnotationProcessorPath().getFiles()}"
}
options.encoding = 'UTF-8'
options.deprecation = true
options.compilerArgs += ["-parameters","-Xlint:deprecation"]
options.compilerArgs += ['-s', querydslGeneratedSourcesDir] //设定生成的Q类存放的位置
options.compilerArgs += ["-Aquerydsl.excludedPackages=org.wjw.jpa.dsl.entity2"] //设定QueryDsl要排除的包列表(逗号来分割)
}
repositories {
mavenLocal()
maven { url "https://maven.aliyun.com/nexus/content/groups/public/" } //优先使用阿里的镜像
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'mysql:mysql-connector-java:5.1.37'
// QueryDSL
implementation("com.querydsl:querydsl-jpa:${queryDslVersion}")
annotationProcessor("com.querydsl:querydsl-apt:${queryDslVersion}:jpa")
//单元测试
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//@wjw_comment: For Eclipse Run JUnit5
testImplementation 'org.junit.platform:junit-platform-launcher'
}
test {
useJUnitPlatform()
}
只生成Q文件,运行: gradlew clean runAPT
build,运行: gradlew clean build -x test