使用kotlin集成springboot開(kāi)發(fā)的超詳細(xì)教程
目前大多數(shù)都在使用java集成 springboot進(jìn)行開(kāi)發(fā),本文演示僅僅將 java換成 kotlin,其他不變的情況下進(jìn)行開(kāi)發(fā)。
一、安裝支持插件
在 idea中安裝 kotlin插件(大多數(shù)情況下會(huì)默認(rèn)安裝了)

二、maven配置 注意
kotlin目前不支持 lombok所以不能使用或引用 lombok相關(guān)的插件或依賴包,下面是一個(gè)排除示例,同時(shí)也不支持 maven-enforcer-plugin
<dependency>
<groupId>com.ayouran.common</groupId>
<artifactId>a-common</artifactId>
<version>1.0.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclusion>
</exclusions>
</dependency>
maven的屬性配置
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<kotlin.version>1.3.21</kotlin.version>
<!--增量編譯-->
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
<!--關(guān)閉協(xié)程編譯警告-->
<experimentalCoroutines>enable</experimentalCoroutines>
<spring-boot.version>2.2.4.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
<swagger.version>2.7.0</swagger.version>
<main.class>com.lc.github.KotlinDemoApplication</main.class>
<querydsl.version>4.2.1</querydsl.version>
<mapstruct.version>1.3.1.Final</mapstruct.version>
</properties>
必要的依賴
<dependencies>
<!--反射支持包,不需要可以去掉-->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>${kotlin.version}</version>
</dependency>
<!--jdk8下的 kotlin支持包-->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
編譯部分
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<correctErrorTypes>true</correctErrorTypes>
<languageVersion>${kotlin.language.version}</languageVersion>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>kapt</id>
<goals>
<goal>kapt</goal>
</goals>
<configuration>
<correctErrorTypes>true</correctErrorTypes>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
<sourceDir>src/main/java</sourceDir>
</sourceDirs>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>2.9</version>
</annotationProcessorPath>
<annotationProcessorPath>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<classifier>jpa</classifier>
</annotationProcessorPath>
<annotationProcessorPath>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
<sourceDir>src/main/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-kapt</id>
<goals>
<goal>test-kapt</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/test/kotlin</sourceDir>
<sourceDir>src/test/java</sourceDir>
</sourceDirs>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>2.9</version>
</annotationProcessorPath>
<annotationProcessorPath>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<classifier>jpa</classifier>
</annotationProcessorPath>
<annotationProcessorPath>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/test/kotlin</sourceDir>
<sourceDir>src/test/java</sourceDir>
<sourceDir>target/generated-sources/kapt/test</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<proc>none</proc>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-Amapstruct.suppressGeneratorTimestamp=true</arg>
<arg>-Amapstruct.defaultComponentModel=spring</arg>
</compilerArgs>
</configuration>
<executions>
<!-- Replacing default-compile as it is treated specially by maven -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- Replacing default-testCompile as it is treated specially by maven -->
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>${main.class}</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
有 java與 kotlin混合的情況,在上面的 <plugins>下加入下面的編譯插件
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<proc>none</proc>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-Amapstruct.suppressGeneratorTimestamp=true</arg>
<arg>-Amapstruct.defaultComponentModel=spring</arg>
</compilerArgs>
</configuration>
<executions>
<!-- Replacing default-compile as it is treated specially by maven -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- Replacing default-testCompile as it is treated specially by maven -->
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
此 maven配置集成了 querydsl、mapstruct、dagger2的編譯,基本上能滿足常規(guī)的使用
三、創(chuàng)建入口函數(shù)類

四、編寫(xiě)入口函數(shù)
springboot的啟動(dòng)方法及 swagger的配置
@EnableAsync
@EnableSwagger2
@EnableScheduling
@SpringBootApplication
class KotlinDemoApplication : CommandLineRunner {
companion object {
@JvmStatic
fun main(args: Array<String>) {
SpringApplication.run(KotlinDemoApplication::class.java, *args)
}
}
@Bean
fun api(): Docket {
return Docket(DocumentationType.SWAGGER_2)
.ignoredParameterTypes(Session::class.java)
.select()
// .apis(RequestHandlerSelectors.any())
.apis(RequestHandlerSelectors.basePackage("com.ayouran.flow.controllers"))
.paths(PathSelectors.any())
.build()
.apiInfo(ApiInfoBuilder()
.description("ayouram-flow相關(guān)API")
.title("ayouram-flow")
.version("1.0")
.build())
.pathMapping("/")
}
override fun run(vararg args: String?) {
println("*************************** ok ***********************************")
}
}
五、創(chuàng)建數(shù)據(jù)庫(kù)對(duì)象
import com.fasterxml.jackson.annotation.JsonFormat
import org.hibernate.annotations.DynamicInsert
import org.hibernate.annotations.DynamicUpdate
import java.util.*
import javax.persistence.*
/****
* 設(shè)備流量規(guī)則
*/
@Entity
@Table(name = "device_rules",
indexes = [Index(name = "device_no", columnList = "device_no"),
Index(name = "rules_no", columnList = "rules_no"),
Index(name = "deleted", columnList = "deleted")],
uniqueConstraints = [UniqueConstraint(name = "device_no_rules_no", columnNames = ["device_no", "rules_no"])])
@DynamicUpdate
@DynamicInsert
class DeviceRules {
@Id
@Column(name = "id", columnDefinition = "bigint(20) COMMENT 'ID,自增'")
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long? = null
@Column(name = "device_no", columnDefinition = "varchar(18) COMMENT '設(shè)備編號(hào)'")
var deviceNo: String? = null
@Column(name = "rules_no", columnDefinition = "varchar(18) COMMENT '規(guī)則編號(hào)'")
var rulesNo: String? = null
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Column(name = "create_at", columnDefinition = "datetime COMMENT '創(chuàng)建時(shí)間'")
var createAt: Date? = null
@Column(name = "update_at", columnDefinition = "datetime COMMENT '修改時(shí)間'")
var updateAt: Date? = null
/**
* 觸發(fā)jpa update代碼需要執(zhí)行的邏輯
*/
@PreUpdate
fun preUpdate() {
updateAt = Date()
}
/**
* 自動(dòng)設(shè)置必要字段的值
*/
@PrePersist
fun prePersist() {
updateAt = Date()
createAt = updateAt
deleted = BaseEnum.NOT_REMOVE.index
}
}
注解使用了 hibernate的功能主要用于自動(dòng)創(chuàng)建/更新表結(jié)構(gòu)以及索引的生成,如果需要 mybatis版本的,只需要去掉這里面的注釋就好。
六、創(chuàng)建倉(cāng)庫(kù)操作接口
基于 springboot-data-jpa的 repository
@Repository
interface DeviceRulesRepository : JpaRepository<DeviceRules, Long>,
JpaSpecificationExecutor<DeviceRules>, QuerydslPredicateExecutor<DeviceRules> {
fun getAllByDeviceNoAndDeleted(deviceNo: String, deleted: Int): Optional<MutableList<DeviceRules>>
}
七、創(chuàng)建一個(gè)業(yè)務(wù)接口來(lái)聲明業(yè)務(wù)
interface DeviceService {
/**
* 查詢?cè)O(shè)備的路由規(guī)則
*/
fun queryDeviceFlowRules(aPageRequest: APageRequest): PageResult<QueryDeviceFlowRulesVO>
}
八、創(chuàng)建一個(gè)業(yè)務(wù)接口實(shí)現(xiàn)來(lái)實(shí)現(xiàn)聲明的業(yè)務(wù)
@Service
class DeviceServiceImpl @Autowired
constructor(private val deviceRepository: DeviceRepository,
private val deviceRulesRepository: DeviceRulesRepository,
private val querydslUtlis: QuerydslUtlis,
private val deviceMapstruct: DeviceMapstruct) : DeviceService {
private val logger = LoggerFactory.getLogger(javaClass)
override fun queryDeviceFlowRules(aPageRequest: APageRequest): PageResult<QueryDeviceFlowRulesVO> {
val qDeviceRules = QDeviceRules.deviceRules
val qFlowRules = QFlowRules.flowRules
var rredicate: Predicate? = null
if (StringUtils.isNotBlank(aPageRequest.query)) rredicate = qDeviceRules.deviceNo.eq(aPageRequest.query)
val exprs = arrayOf<Expression<*>>(qDeviceRules.deviceNo, qDeviceRules.deleted, qFlowRules.rulesNo, qFlowRules.flowMax,
qFlowRules.startTime, qFlowRules.endTime)
val results = querydslUtlis.getQueryFactory()
.select(*exprs)
.from(qDeviceRules)
.where(ExpressionUtils.allOf(rredicate))
.leftJoin(qFlowRules)
.on(qDeviceRules.rulesNo.eq(qFlowRules.rulesNo))
.orderBy(qDeviceRules.createAt.desc())
.offset((aPageRequest.pageIndex!! - 1) * aPageRequest.pageSize!!)
.limit(aPageRequest.pageSize!!)
.fetchResults()
return PageUtlis.retPage(results, querydslUtlis.getCollection(results.results, exprs, QueryDeviceFlowRulesVO::class.java) as Collection<QueryDeviceFlowRulesVO>)
}
}
這里使用了 querydsl來(lái)完成一個(gè)多表查詢
九、創(chuàng)建一個(gè) http服務(wù)接口
@RestWrapper
@RestController
@RequestMapping("/device")
@Api(value = "device", description = "設(shè)備相關(guān)接口", tags = ["device"])
class DeviceController @Autowired
constructor(private val deviceService: DeviceService) {
@GetMapping("/query_device")
fun queryDevice(aPageRequest: APageRequest) = deviceService.queryDevice(aPageRequest)
@GetMapping("/query_device_flow_rules")
fun queryDeviceFlowRules(aPageRequest: APageRequest) = deviceService.queryDeviceFlowRules(aPageRequest)
}
至此完成一個(gè)基本的開(kāi)發(fā)過(guò)程,大多數(shù)情況下可以直接將 java代碼粘貼到 kotlin文件中,會(huì)自動(dòng)轉(zhuǎn)換成合適的 kotlin代碼(偶爾需要自己調(diào)整,畢竟編輯器不是萬(wàn)能的)
到此這篇關(guān)于使用kotlin集成springboot開(kāi)發(fā)的文章就介紹到這了,更多相關(guān)kotlin集成springboot開(kāi)發(fā)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot項(xiàng)目打包發(fā)布到外部tomcat(出現(xiàn)各種異常的解決)
這篇文章主要介紹了SpringBoot項(xiàng)目打包發(fā)布到外部tomcat(出現(xiàn)各種異常的解決),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Java基于裝飾者模式實(shí)現(xiàn)的圖片工具類實(shí)例【附demo源碼下載】
這篇文章主要介紹了Java基于裝飾者模式實(shí)現(xiàn)的圖片工具類,結(jié)合完整實(shí)例形式分析了裝飾者模式實(shí)現(xiàn)圖片的判斷、水印、縮放、復(fù)制等功能,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2017-09-09
Spring BeanPostProcessor源碼示例解析
這篇文章主要為大家介紹了Spring BeanPostProcessor源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
java非公平鎖知識(shí)點(diǎn)實(shí)例詳解
在本篇文章里小編給大家整理了一篇關(guān)于java非公平鎖知識(shí)點(diǎn)實(shí)例詳解,有興趣的朋友們可以學(xué)習(xí)參考下。2021-10-10
maven打包上傳到私有倉(cāng)庫(kù)的實(shí)現(xiàn)步驟
這篇文章主要介紹了maven打包上傳到私有倉(cāng)庫(kù)的實(shí)現(xiàn)步驟,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01
詳解Java面試官最愛(ài)問(wèn)的volatile關(guān)鍵字
這篇文章主要介紹了詳解Java面試官最愛(ài)問(wèn)的volatile關(guān)鍵字,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
Java字符編碼原理(動(dòng)力節(jié)點(diǎn)Java學(xué)院整理)
Java開(kāi)發(fā)中,常常會(huì)遇到亂碼的問(wèn)題,一旦遇到這種問(wèn)題,常常比較煩惱,大家都不想承認(rèn)是自己的代碼問(wèn)題,其實(shí)搞明白編碼的本質(zhì)過(guò)程就簡(jiǎn)單多了,接下來(lái)小編給大家?guī)?lái)java字符編碼原理,要求看看吧2017-04-04

