Spring Boot和Kotlin的无缝整合与完美交融

时间:2021-05-20

前言

本文讲解 Spring Boot2 基础下,如何使用 Kotlin,并无缝整合与完美交融。为了让读者更加熟悉 Kotlin 的语法糖,笔者会在未来的几篇文章中,聊聊 Kotlin 的新特性及其语法糖。下面话不多说了,来一起看看详细的介绍吧

环境依赖

修改 POM 文件,添加 spring boot 依赖。

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> <relativePath/></parent><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency></dependencies>

紧接着,我们需要添加 mysql 依赖。

<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.35</version></dependency><dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.14</version></dependency>

最后,添加 Kotlin 依赖。

<dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib-jdk8</artifactId></dependency><dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-reflect</artifactId></dependency><dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib</artifactId></dependency>

注意的是,在 Kotlin 中,data class 默认没有无参构造方法,并且 data class 默认为 final 类型,不可以被继承。注意的是,如果我们使用 Spring + Kotlin 的模式,那么使用 @autowared 就可能遇到这个问题。因此,我们可以添加 NoArg 为标注的类生成无参构造方法。使用 AllOpen 为被标注的类去掉 final,允许被继承。

<plugin> <artifactId>kotlin-maven-plugin</artifactId> <groupId>org.jetbrains.kotlin</groupId> <version>${kotlin.version}</version> <executions> <execution> <id>compile</id> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>test-compile</id> <goals> <goal>test-compile</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-noarg</artifactId> <version>${kotlin.version}</version> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-allopen</artifactId> <version>${kotlin.version}</version> </dependency> </dependencies></plugin>

至此,我们 Maven 的依赖环境大致配置完毕。完整的源码,可以参见文末 GitHub 仓库。

数据源

方案一 使用 Spring Boot 默认配置

使用 Spring Boot 默认配置,不需要在创建 dataSource 和 jdbcTemplate 的 Bean。

在 src/main/resources/application.properties 中配置数据源信息。

spring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3307/springboot_dbspring.datasource.username=rootspring.datasource.password=root

方案二 手动创建

在 src/main/resources/config/source.properties 中配置数据源信息。

# mysqlsource.driverClassName = com.mysql.jdbc.Driversource.url = jdbc:mysql://localhost:3306/springboot_dbsource.username = rootsource.password = root

这里, 创建 dataSource 和jdbcTemplate。

@Configuration@EnableTransactionManagement@PropertySource(value = *arrayOf("classpath:config/source.properties"))open class BeanConfig { @Autowired private lateinit var env: Environment @Bean open fun dataSource(): DataSource { val dataSource = DruidDataSource() dataSource.driverClassName = env!!.getProperty("source.driverClassName").trim() dataSource.url = env.getProperty("source.url").trim() dataSource.username = env.getProperty("source.username").trim() dataSource.password = env.getProperty("source.password").trim() return dataSource } @Bean open fun jdbcTemplate(): JdbcTemplate { val jdbcTemplate = JdbcTemplate() jdbcTemplate.dataSource = dataSource() return jdbcTemplate }}

脚本初始化

先初始化需要用到的 SQL 脚本。

CREATE DATABASE `springboot_db` ; USE `springboot_db`; DROP TABLE IF EXISTS `t_author`; CREATE TABLE `t_author` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID', `real_name` varchar(32) NOT NULL COMMENT '用户名称', `nick_name` varchar(32) NOT NULL COMMENT '用户匿名', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

使用 JdbcTemplate 操作

实体对象

class Author { var id: Long? = null var realName: String? = null var nickName: String? = null}

DAO相关

interface AuthorDao { fun add(author: Author): Int fun update(author: Author): Int fun delete(id: Long): Int fun findAuthor(id: Long): Author? fun findAuthorList(): List<Author>}

我们来定义实现类,通过 JdbcTemplate 定义的数据访问操作。

@Repositoryopen class AuthorDaoImpl : AuthorDao { @Autowired private lateinit var jdbcTemplate: JdbcTemplate override fun add(author: Author): Int { return jdbcTemplate.update("insert into t_author(real_name, nick_name) values(?, ?)", author.realName, author.nickName) } override fun update(author: Author): Int { return jdbcTemplate.update("update t_author set real_name = ?, nick_name = ? where id = ?", *arrayOf(author.realName, author.nickName, author.id)) } override fun delete(id: Long): Int { return jdbcTemplate.update("delete from t_author where id = ?", id) } override fun findAuthor(id: Long): Author? { val list = jdbcTemplate.query<Author>("select * from t_author where id = ?", arrayOf<Any>(id), BeanPropertyRowMapper(Author::class.java)) return list?.get(0); } override fun findAuthorList(): List<Author> { return jdbcTemplate.query("select * from t_author", arrayOf(), BeanPropertyRowMapper(Author::class.java)) }}

Service相关

interface AuthorService { fun add(author: Author): Int fun update(author: Author): Int fun delete(id: Long): Int fun findAuthor(id: Long): Author? fun findAuthorList(): List<Author>}

我们来定义实现类,Service 层调用 Dao 层的方法,这个是典型的套路。

@Service("authorService")open class AuthorServiceImpl : AuthorService { @Autowired private lateinit var authorDao: AuthorDao override fun update(author: Author): Int { return this.authorDao.update(author) } override fun add(author: Author): Int { return this.authorDao.add(author) } override fun delete(id: Long): Int { return this.authorDao.delete(id) } override fun findAuthor(id: Long): Author? { return this.authorDao.findAuthor(id) } override fun findAuthorList(): List<Author> { return this.authorDao.findAuthorList() }}

Controller相关

为了展现效果,我们先定义一组简单的 RESTful API 接口进行测试。

@RestController@RequestMapping(value = "/authors")class AuthorController { @Autowired private lateinit var authorService: AuthorService /** * 查询用户列表 */ @RequestMapping(method = [RequestMethod.GET]) fun getAuthorList(request: HttpServletRequest): Map<String, Any> { val authorList = this.authorService.findAuthorList() val param = HashMap<String, Any>() param["total"] = authorList.size param["rows"] = authorList return param } /** * 查询用户信息 */ @RequestMapping(value = "/{userId:\\d+}", method = [RequestMethod.GET]) fun getAuthor(@PathVariable userId: Long, request: HttpServletRequest): Author { return authorService.findAuthor(userId) ?: throw RuntimeException("查询错误") } /** * 新增方法 */ @RequestMapping(method = [RequestMethod.POST]) fun add(@RequestBody jsonObject: JSONObject) { val userId = jsonObject.getString("user_id") val realName = jsonObject.getString("real_name") val nickName = jsonObject.getString("nick_name") val author = Author() author.id = java.lang.Long.valueOf(userId) author.realName = realName author.nickName = nickName try { this.authorService.add(author) } catch (e: Exception) { throw RuntimeException("新增错误") } } /** * 更新方法 */ @RequestMapping(value = "/{userId:\\d+}", method = [RequestMethod.PUT]) fun update(@PathVariable userId: Long, @RequestBody jsonObject: JSONObject) { var author = this.authorService.findAuthor(userId) val realName = jsonObject.getString("real_name") val nickName = jsonObject.getString("nick_name") try { if (author != null) { author.realName = realName author.nickName = nickName this.authorService.update(author) } } catch (e: Exception) { throw RuntimeException("更新错误") } } /** * 删除方法 */ @RequestMapping(value = "/{userId:\\d+}", method = [RequestMethod.DELETE]) fun delete(@PathVariable userId: Long) { try { this.authorService.delete(userId) } catch (e: Exception) { throw RuntimeException("删除错误") } }}

最后,我们通过 SpringKotlinApplication 运行程序。

@SpringBootApplication(scanBasePackages = ["com.lianggzone.demo.kotlin"])open class SpringKotlinApplication{ fun main(args: Array<String>) { SpringApplication.run(SpringKotlinApplication::class.java, *args) }}

关于测试

这里,笔者推荐 IDEA 的 Editor REST Client。IDEA 的 Editor REST Client 在 IntelliJ IDEA 2017.3 版本就开始支持,在 2018.1 版本添加了很多的特性。事实上,它是 IntelliJ IDEA 的 HTTP Client 插件。参见笔者之前的另一篇文章: 快速测试 API 接口的新技能

### 查询用户列表GET http://localhost:8080/authorsAccept : application/jsonContent-Type : application/json;charset=UTF-8 ### 查询用户信息GET http://localhost:8080/authors/15Accept : application/jsonContent-Type : application/json;charset=UTF-8 ### 新增方法POST http://localhost:8080/authorsContent-Type: application/json { "user_id": "21", "real_name": "梁桂钊", "nick_name": "梁桂钊"} ### 更新方法PUT http://localhost:8080/authors/21Content-Type: application/json { "real_name" : "lianggzone", "nick_name": "lianggzone"} ### 删除方法DELETE http://localhost:8080/authors/21Accept : application/jsonContent-Type : application/json;charset=UTF-8

总结

通过,上面这个简单的案例,我们发现 Spring Boot 整合 Kotlin 非常容易,并简化 Spring 应用的初始搭建以及开发过程。为了让读者更加熟悉 Kotlin 的语法糖,笔者会在未来的几篇文章中,聊聊 Kotlin 的新特性及其语法糖。

源代码

相关示例完整代码: spring-kotlin-samples(本地下载)

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章