Original address: Liang Guizhao’s blog

Blog address: blog.720ui.com

Welcome to reprint, reprint please indicate the author and source, thank you!

This article shows you how to use Kotlin with Spring Boot2 as a base for seamless integration and perfect blending. In order to familiarize readers with Kotlin’s syntactic sugar, I will talk about Kotlin’s new features and syntactic sugar in a few future articles.

Environment depends on

Modify the POM file to add spring Boot dependencies.

<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>
Copy the code

Next, we need to add mysql dependencies.

< the 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>Copy the code

Finally, add the Kotlin dependency.

<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>
Copy the code

Note that in Kotlin, data class has no no-argument constructor by default, and data class is final by default and cannot be inherited. Note that if we were using Spring + Kotlin’s pattern, we might run into this problem with @Autowared. Therefore, we can add NoArg to generate a no-argument constructor for the annotated class. AllOpen is used to remove final from the tagged class, allowing it to be inherited.

<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>
Copy the code

At this point, our Maven dependency environment is roughly configured. For the complete source code, see GitHub repository at the end of this article.

The data source

Scenario 1 uses the default Spring Boot configuration

With the Spring Boot default configuration, there is no need to create dataSource and jdbcTemplate beans.

In the SRC/main/resources/application. The properties in the configuration data source information.

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3307/springboot_db
spring.datasource.username=root
spring.datasource.password=root

Solution 2 Create one manually

In the SRC/main/resources/config/source. The properties in the configuration data source information.

# mysql
source.driverClassName = com.mysql.jdbc.Driver
source.url = jdbc:mysql://localhost:3306/springboot_db
source.username = root
source.password = root
Copy the code

Here, create the dataSource and 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
    }
}
Copy the code

Script initialization

Initialize the SQL script to be used.

CREATE DATABASE /*! 32312 IF NOT EXISTS*/`springboot_db` /*! 40100 DEFAULT CHARACTER SET utf8 */; USE `springboot_db`; DROP TABLE IF EXISTS `t_author`; CREATE TABLE `t_author` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT'user ID',
  `real_name` varchar(32) NOT NULL COMMENT 'User name',
  `nick_name` varchar(32) NOT NULL COMMENT 'User anonymous',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
Copy the code

Use the JdbcTemplate operation

Entity objects

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

The DAO related

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>
}
Copy the code

Let’s define the implementation class for the data access operations defined by the JdbcTemplate.

@Repository
open 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))
        returnlist? .get(0); } override fun findAuthorList(): List<Author> {return jdbcTemplate.query("select * from t_author", arrayOf(), BeanPropertyRowMapper(Author::class.java))
    }
}
Copy the code

The Service related

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>
}
Copy the code

Let’s define the implementation class. The Service layer calls the methods of the Dao layer. This is a typical pattern.

@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()
    }
}
Copy the code

The Controller related

To demonstrate this, let’s define a simple set of RESTful apis to test.

@RestController
@RequestMapping(value = "/authors") class AuthorController { @Autowired private lateinit var 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
        returnParam} /** * query user information */ @requestMapping (value ="/{userId:\\d+}", method = [RequestMethod.GET])
    fun getAuthor(@PathVariable userId: Long, request: HttpServletRequest): Author {
        returnauthorService.findAuthor(userId) ? : throw RuntimeException("Query error"} /** * add(@requestBody jsonObject) 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("New error"}} /** * update method */ @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("Update error"}} /** * delete method */ @requestMapping (value ="/{userId:\\d+}", method = [RequestMethod.DELETE])
    fun delete(@PathVariable userId: Long) {
        try {
            this.authorService.delete(userId)
        } catch (e: Exception) {
            throw RuntimeException("Delete error")}}}Copy the code

Finally, we run the program through the SpringKotlinApplication.

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

About the test

Here, I recommend the Editor REST Client of IDEA. The Editor REST Client for IDEA was supported in IntelliJ IDEA 2017.3, and many features were added in 2018.1. In fact, it is an HTTP Client plug-in for IntelliJ IDEA. Before you see my another article: quick test apis interface new skills | Liang Guizhao blog

### Query user listGET http://localhost:8080/authors Accept : application/json Content-Type : application/json; charset=UTF-8### query user informationGET http://localhost:8080/authors/15 Accept : application/json Content-Type : application/json; charset=UTF-8### Add method
POST http://localhost:8080/authors
Content-Type: application/json

{
    "user_id": "21"."real_name": "Liang Gui-zhao"."nick_name": "Liang Gui-zhao"
}

### Update method
PUT http://localhost:8080/authors/21
Content-Type: application/json

{
    "real_name" : "lianggzone"."nick_name": "lianggzone"
}


### delete methodDELETE http://localhost:8080/authors/21 Accept : application/json Content-Type : application/json; charset=UTF-8Copy the code

conclusion

This simple example shows how easy it is to integrate Kotlin with Spring Boot and simplify the initial setup and development process of Spring applications. In order to familiarize readers with Kotlin’s syntactic sugar, I will talk about Kotlin’s new features and syntactic sugar in a few future articles.

The source code

Related sample complete code: spring-Kotlin-samples

(End, reprint please indicate the author and source.)

More wonderful articles, all in the “server-side thinking”!