- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章利用Kotlin + Spring Boot实现后端开发由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
前言 。
spring官方最近宣布,将在spring framework 5.0版本中正式支持kotlin语言。这意味着spring boot 2.x版本将为kotlin提供一流的支持.
这并不会令人意外,因为pivotal团队以广泛接纳jvm语言(如scala和groovy)而闻名.
kotlin 是一个基于 jvm 的编程语言,它的简洁、便利早已不言而喻。kotlin 能够胜任 java 做的所有事。目前,我们公司 c 端 的 android 产品全部采用 kotlin 编写。公司的后端项目也可能会使用 kotlin,所以我给他们做一些 demo 进行演示.
示例一:结合 redis 进行数据存储和查询 。
1.1 配置 gradle 。
在build.gradle中添加插件和依赖的库.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
plugins {
id
'java'
id
'org.jetbrains.kotlin.jvm'
version
'1.3.0'
}
ext {
libraries = [
rxjava :
"2.2.2"
,
logback :
"1.2.3"
,
spring_boot :
"2.1.0.release"
,
commons_pool2 :
"2.6.0"
,
fastjson :
"1.2.51"
]
}
group
'com.kotlin.tutorial'
version
'1.0-snapshot'
sourcecompatibility =
1.8
def libs = rootproject.ext.libraries
// 库
repositories {
mavencentral()
}
dependencies {
compile
"org.jetbrains.kotlin:kotlin-stdlib-jdk8"
compile
"org.jetbrains.kotlin:kotlin-reflect:1.3.0"
testcompile group:
'junit'
, name:
'junit'
, version:
'4.12'
implementation
"io.reactivex.rxjava2:rxjava:${libs.rxjava}"
implementation
"ch.qos.logback:logback-classic:${libs.logback}"
implementation
"ch.qos.logback:logback-core:${libs.logback}"
implementation
"ch.qos.logback:logback-access:${libs.logback}"
implementation
"org.springframework.boot:spring-boot-starter-web:${libs.spring_boot}"
implementation
"org.springframework.boot:spring-boot-starter-data-redis:${libs.spring_boot}"
implementation
"org.apache.commons:commons-pool2:${libs.commons_pool2}"
implementation
"com.alibaba:fastjson:${libs.fastjson}"
}
compilekotlin {
kotlinoptions.jvmtarget =
"1.8"
}
compiletestkotlin {
kotlinoptions.jvmtarget =
"1.8"
}
|
1.2 创建 springkotlinapplication:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import
org.springframework.boot.springapplication
import
org.springframework.boot.autoconfigure.springbootapplication
/**
* created by tony on 2018/11/13.
*/
@springbootapplication
open
class
springkotlinapplication
fun main(args: array<string>) {
springapplication.run(springkotlinapplication::
class
.java, *args)
}
|
需要注意open的使用,如果不加open会报如下的错误:
org.springframework.beans.factory.parsing.beandefinitionparsingexception: configuration problem: @configuration class 'springkotlinapplication' may not be final. remove the final modifier to continue. 。
因为 kotlin 的类默认是final的,所以这里需要使用open关键字.
1.3 配置 redis 。
在 application.yml 中添加 redis 的配置 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
spring:
redis:
#数据库索引
database:
0
host:
127.0
.
0.1
port:
6379
password:
lettuce:
pool:
#最大连接数
max-active:
8
#最大阻塞等待时间(负数表示没限制)
max-wait: -
1
#最大空闲
max-idle:
8
#最小空闲
min-idle:
0
#连接超时时间
timeout:
10000
|
接下来定义 redis 的序列化器,本文采用fastjson,当然使用gson、jackson等都可以,看个人喜好.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
import
com.alibaba.fastjson.json
import
com.alibaba.fastjson.serializer.serializerfeature
import
org.springframework.data.redis.serializer.redisserializer
import
org.springframework.data.redis.serializer.serializationexception
import
java.nio.charset.charset
/**
* created by tony on 2018/11/13.
*/
class
fastjsonredisserializer<t>(
private
val clazz:
class
<t>) : redisserializer<t> {
@throws
(serializationexception::
class
)
override fun serialize(t: t?) =
if
(
null
== t) {
bytearray(
0
)
}
else
json.tojsonstring(t, serializerfeature.writeclassname).tobytearray(default_charset)
@throws
(serializationexception::
class
)
override fun deserialize(bytes: bytearray?): t? {
if
(
null
== bytes || bytes.size <=
0
) {
return
null
}
val str = string(bytes, default_charset)
return
json.parseobject(str, clazz) as t
}
companion object {
private
val default_charset = charset.forname(
"utf-8"
)
}
}
|
创建 redisconfig 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
import
org.springframework.data.redis.core.redistemplate
import
org.springframework.data.redis.connection.redisconnectionfactory
import
org.springframework.context.annotation.bean
import
org.springframework.data.redis.cache.rediscachemanager
import
org.springframework.cache.cachemanager
import
org.springframework.cache.annotation.cachingconfigurersupport
import
org.springframework.cache.annotation.enablecaching
import
org.springframework.context.annotation.configuration
import
org.springframework.data.redis.serializer.stringredisserializer
import
org.springframework.boot.autoconfigure.condition.conditionalonmissingbean
import
org.springframework.boot.context.properties.enableconfigurationproperties
import
org.springframework.data.redis.core.redisoperations
import
org.springframework.boot.autoconfigure.condition.conditionalonclass
import
org.springframework.boot.autoconfigure.data.redis.redisproperties
/**
* created by tony on 2018/11/13.
*/
@enablecaching
@configuration
@conditionalonclass
(redisoperations::
class
)
@enableconfigurationproperties
(redisproperties::
class
)
open
class
redisconfig : cachingconfigurersupport() {
@bean
(name = arrayof(
"redistemplate"
))
@conditionalonmissingbean
(name = arrayof(
"redistemplate"
))
open fun redistemplate(redisconnectionfactory: redisconnectionfactory): redistemplate<any, any> {
val template = redistemplate<any, any>()
val fastjsonredisserializer = fastjsonredisserializer(any::
class
.java)
template.valueserializer = fastjsonredisserializer
template.hashvalueserializer = fastjsonredisserializer
template.keyserializer = stringredisserializer()
template.hashkeyserializer = stringredisserializer()
template.connectionfactory = redisconnectionfactory
return
template
}
//缓存管理器
@bean
open fun cachemanager(redisconnectionfactory: redisconnectionfactory): cachemanager {
val builder = rediscachemanager
.rediscachemanagerbuilder
.fromconnectionfactory(redisconnectionfactory)
return
builder.build()
}
}
|
这里也都需要使用open,理由同上.
1.4 创建 service 。
创建一个 user 对象,使用 datat class 类型.
1
|
data
class
user(var username:string,var password:string):serializable
|
创建操作 user 的service接口 。
1
2
3
4
5
6
7
8
9
10
11
|
import
com.kotlin.tutorial.user.user
/**
* created by tony on 2018/11/13.
*/
interface
iuserservice {
fun getuser(username: string): user
fun createuser(username: string,password: string)
}
|
创建 service 的实现类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
import
com.kotlin.tutorial.user.user
import
com.kotlin.tutorial.user.service.iuserservice
import
org.springframework.beans.factory.annotation.autowired
import
org.springframework.data.redis.core.redistemplate
import
org.springframework.stereotype.service
/**
* created by tony on 2018/11/13.
*/
@service
class
userserviceimpl : iuserservice {
@autowired
lateinit var redistemplate: redistemplate<any, any>
override fun getuser(username: string): user {
var user = redistemplate.opsforvalue().get(
"user_${username}"
)
if
(user ==
null
) {
user = user(
"default"
,
"000000"
)
}
return
user as user
}
override fun createuser(username: string, password: string) {
redistemplate.opsforvalue().set(
"user_${username}"
, user(username, password))
}
}
|
1.5 创建 controller 。
创建一个 usercontroller,包含 createuser、getuser 两个接口.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
import
com.kotlin.tutorial.user.user
import
com.kotlin.tutorial.user.service.iuserservice
import
com.kotlin.tutorial.web.dto.httpresponse
import
org.springframework.beans.factory.annotation.autowired
import
org.springframework.web.bind.annotation.getmapping
import
org.springframework.web.bind.annotation.requestmapping
import
org.springframework.web.bind.annotation.requestparam
import
org.springframework.web.bind.annotation.restcontroller
/**
* created by tony on 2018/11/13.
*/
@restcontroller
@requestmapping
(
"/user"
)
class
usercontroller {
@autowired
lateinit var userservice: iuserservice
@getmapping
(
"/getuser"
)
fun getuser(
@requestparam
(
"name"
) username: string): httpresponse<user> {
return
httpresponse(userservice.getuser(username))
}
@getmapping
(
"/createuser"
)
fun createuser(
@requestparam
(
"name"
) username: string,
@requestparam
(
"password"
) password: string): httpresponse<string> {
userservice.createuser(username,password)
return
httpresponse(
"create ${username} success"
)
}
}
|
创建完 controller 之后,可以进行测试了.
创建用户tony:
查询用户tony:
创建用户monica:
查询用户monica:
示例二:结合 rxjava 模拟顺序、并发地执行任务 。
2.1 创建 mocktask 。
首先定义一个任务接口,所有的任务都需要实现该接口:
1
2
3
4
5
6
7
|
/**
* created by tony on 2018/11/13.
*/
interface
itask {
fun execute()
}
|
再创建一个模拟的任务,其中delayinseconds用来模拟任务所花费的时间,单位是秒.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
import
java.util.concurrent.timeunit
import
com.kotlin.tutorial.task.itask
/**
* created by tony on 2018/11/13.
*/
class
mocktask(
private
val delayinseconds:
int
) : itask {
/**
* stores information if task was started.
*/
var started:
boolean
=
false
/**
* stores information if task was successfully finished.
*/
var finishedsuccessfully:
boolean
=
false
/**
* stores information if the task was interrupted.
* it can happen if the thread that is running this task was killed.
*/
var interrupted:
boolean
=
false
/**
* stores the thread identifier in which the task was executed.
*/
var threadid:
long
=
0
override fun execute() {
try
{
this
.threadid = thread.currentthread().id
this
.started =
true
timeunit.seconds.sleep(delayinseconds.tolong())
this
.finishedsuccessfully =
true
}
catch
(e: interruptedexception) {
this
.interrupted =
true
}
}
}
|
2.2 创建 concurrenttasksexecutor 。
顺序执行的话比较简单,一个任务接着一个任务地完成即可,是单线程的操作.
对于并发而言,在这里借助 rxjava 的 merge 操作符来将多个任务进行合并。还用到了 rxjava 的任务调度器 scheduler,createscheduler()是按照所需的线程数来创建scheduler的.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
import
com.kotlin.tutorial.task.itask
import
io.reactivex.completable
import
io.reactivex.schedulers.schedulers
import
org.slf4j.loggerfactory
import
org.springframework.util.collectionutils
import
java.util.*
import
java.util.concurrent.executors
import
java.util.stream.collectors
/**
* created by tony on 2018/11/13.
*/
class
concurrenttasksexecutor(
private
val numberofconcurrentthreads:
int
,
private
val tasks: collection<itask>?) : itask {
val log = loggerfactory.getlogger(
this
.javaclass)
constructor(numberofconcurrentthreads:
int
, vararg tasks: itask) :
this
(numberofconcurrentthreads,
if
(tasks ==
null
)
null
else
arrays.aslist<itask>(*tasks)) {}
init {
if
(numberofconcurrentthreads <
0
) {
throw
runtimeexception(
"amount of threads must be higher than zero."
)
}
}
/**
* converts collection of tasks (except null tasks) to collection of completable actions.
* each action will be executed in thread according to the scheduler created with [.createscheduler] method.
*
* @return list of completable actions
*/
private
val asconcurrenttasks: list<completable>
get() {
if
(tasks!=
null
) {
val scheduler = createscheduler()
return
tasks.stream()
.filter { task -> task !=
null
}
.map { task ->
completable
.fromaction {
task.execute()
}
.subscribeon(scheduler)
}
.collect(collectors.tolist())
}
else
{
return
arraylist<completable>()
}
}
/**
* checks whether tasks collection is empty.
*
* @return true if tasks collection is null or empty, false otherwise
*/
private
val istaskscollectionempty:
boolean
get() = collectionutils.isempty(tasks)
/**
* executes all tasks concurrent way only if collection of tasks is not empty.
* method completes when all of the tasks complete (or one of them fails).
* if one of the tasks failed the the exception will be rethrown so that it can be handled by mechanism that calls this method.
*/
override fun execute() {
if
(istaskscollectionempty) {
log.warn(
"there are no tasks to be executed."
)
return
}
log.debug(
"executing #{} tasks concurrent way."
, tasks?.size)
completable.merge(asconcurrenttasks).blockingawait()
}
/**
* creates a scheduler that will be used for executing tasks concurrent way.
* scheduler will use number of threads defined in [.numberofconcurrentthreads]
*
* @return scheduler
*/
private
fun createscheduler() = schedulers.from(executors.newfixedthreadpool(numberofconcurrentthreads))
}
|
2.3 创建 controller 。
创建一个 taskscontroller,包含 sequential、concurrent 两个接口,会分别把sequential 和 concurrent 执行任务的时间展示出来.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
import
com.kotlin.tutorial.task.impl.concurrenttasksexecutor
import
com.kotlin.tutorial.task.impl.mocktask
import
com.kotlin.tutorial.web.dto.taskresponse
import
com.kotlin.tutorial.web.dto.errorresponse
import
com.kotlin.tutorial.web.dto.httpresponse
import
org.springframework.http.httpstatus
import
org.springframework.util.stopwatch
import
org.springframework.web.bind.annotation.*
import
java.util.stream.collectors
import
java.util.stream.intstream
/**
* created by tony on 2018/11/13.
*/
@restcontroller
@requestmapping
(
"/tasks"
)
class
taskscontroller {
@getmapping
(
"/sequential"
)
fun sequential(
@requestparam
(
"task"
) taskdelaysinseconds: intarray): httpresponse<taskresponse> {
val watch = stopwatch()
watch.start()
intstream.of(*taskdelaysinseconds)
.maptoobj{
mocktask(it)
}
.foreach{
it.execute()
}
watch.stop()
return
httpresponse(taskresponse(watch.totaltimeseconds))
}
@getmapping
(
"/concurrent"
)
fun concurrent(
@requestparam
(
"task"
) taskdelaysinseconds: intarray,
@requestparam
(
"threads"
,required =
false
,defaultvalue =
"1"
) numberofconcurrentthreads:
int
): httpresponse<taskresponse> {
val watch = stopwatch()
watch.start()
val delayedtasks = intstream.of(*taskdelaysinseconds)
.maptoobj{
mocktask(it)
}
.collect(collectors.tolist())
concurrenttasksexecutor(numberofconcurrentthreads, delayedtasks).execute()
watch.stop()
return
httpresponse(taskresponse(watch.totaltimeseconds))
}
@exceptionhandler
(illegalargumentexception::
class
)
@responsestatus
(httpstatus.bad_request)
fun handleexception(e: illegalargumentexception) = errorresponse(e.message)
}
|
顺序地执行多个任务:http://localhost:8080/tasks/sequential?task=1&task=2&task=3&task=4 。
每个任务所花费的时间分别是1秒、2秒、3秒和4秒。最后,一共花费了10.009秒.
两个线程并发地执行多个任务:http://localhost:8080/tasks/concurrent?task=1&task=2&task=3&task=4&threads=2 。
三个线程并发地执行多个任务:http://localhost:8080/tasks/concurrent?task=1&task=2&task=3&task=4&threads=3 。
总结 。
本文使用了 kotlin 的特性跟 spring boot 整合进行后端开发。kotlin 的很多语法糖使得开发变得更加便利,当然 kotlin 也是 java 的必要补充.
本文 demo 的 github 地址:https://github.com/fengzhizi715/kotlin-spring-demo 。
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我的支持.
原文链接:https://juejin.im/post/5bebb4436fb9a04a072feb74 。
最后此篇关于利用Kotlin + Spring Boot实现后端开发的文章就讲到这里了,如果你想了解更多关于利用Kotlin + Spring Boot实现后端开发的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我尝试阅读有关 Spring BOM、Spring Boot 和 Spring IO 的文档。 但是没有说明,我们应该如何一起使用它们? 在我的项目中,我们已经有了自己的 Parent POM ,所以
我正在开发的很酷的企业应用程序正在转向 Spring。这对所有团队来说都是非常酷和令人兴奋的练习,但也是一个巨大的压力源。我们所做的是逐渐将遗留组件移至 Spring 上下文。现在我们有一个 huuu
我正在尝试使用 @Scheduled 运行 Spring 批处理作业注释如下: @Scheduled(cron = "* * * * * ?") public void launchMessageDi
我对这两个概念有点困惑。阅读 Spring 文档,我发现,例如。 bean 工厂是 Spring 容器。我还读到“ApplicationContext 是 BeanFactory 的完整超集”。但两者
我们有一个使用 Spring BlazeDS 集成的应用程序。到目前为止,我们一直在使用 Spring 和 Flex,它运行良好。我们现在还需要添加一些 Spring MVC Controller 。
假设我有一个类(class) Person带属性name和 age ,它可以像这样用 Spring 配置: 我想要一个自定义的 Spring 模式元素,这很容易做到,允许我在我的 Sp
如何在 Java 中以编程方式使用 Spring Data 创建 MongoDB 复合索引? 使用 MongoTemplate 我可以创建一个这样的索引:mongoTemplate.indexOps(
我想使用 spring-complex-task 执行我的应用程序,并且我已经构建了复杂的 spring-batch Flow Jobs,它执行得非常好。 你能解释一下spring批处理流作业与spr
我实现了 spring-boot 应用程序,现在我想将它用作非 spring 应用程序的库。 如何初始化 lib 类,以便 Autowiring 的依赖项按预期工作?显然,如果我使用“new”创建类实
我刚开始学习 spring cloud security,我有一个基本问题。它与 Spring Security 有何不同?我们是否需要在 spring boot 上构建我们的应用程序才能使用 spr
有很多人建议我使用 Spring Boot 而不是 Spring 来开发 REST Web 服务。我想知道这两者到底有什么区别? 最佳答案 总之 Spring Boot 减少了编写大量配置和样板代码的
您能向我解释一下如何使用 Spring 正确构建 Web 应用程序吗?我知道 Spring 框架的最新版本是 4.0.0.RELEASE,但是 Spring Security 的最新版本是 3.2.0
我如何才能知道作为 Spring Boot 应用程序的一部分加载的所有 bean 的名称?我想在 main 方法中有一些代码来打印服务器启动后加载的 bean 的详细信息。 最佳答案 如spring-
我有一个使用 Spring 3.1 构建的 RESTful API,也使用 Spring Security。我有一个 Web 应用程序,也是一个 Spring 3.1 MVC 应用程序。我计划让移动客
升级到 Spring 5 后,我在 Spring Rabbit 和 Spring AMQP 中遇到错误。 两者现在都设置为 1.5.6.RELEASE 有谁知道哪些版本应该与 Spring 5 兼容?
我现在已经使用 Spring Framework 3.0.5 和 Spring Security 3.0.5 多次了。我知道Spring框架使用DI和AOP。我还知道 Spring Security
我收到错误 Unable to Location NamespaceHandler when using context:annotation-config running (java -jar) 由
在 Spring 应用程序中嵌入唯一版本号的策略是什么? 我有一个使用 Spring Boot 和 Spring Web 的应用程序。 它已经足够成熟,我想对其进行版本控制并在运行时看到它显示在屏幕上
我正在使用 spring data jpa 进行持久化。如果存在多个具有相同名称的实体,是否有一种方法可以将一个实体标记为默认值。类似@Primary注解的东西用来解决多个bean的依赖问题 @Ent
我阅读了 Spring 框架的 DAOSupport 类。但是我无法理解这些 DAOSuport 类的优点。在 DAOSupport 类中,我们调用 getXXXTemplate() 方法来获取特定的
我是一名优秀的程序员,十分优秀!