美文网首页Kotlin编程
20180713_KotlinWithSpringBoot

20180713_KotlinWithSpringBoot

作者: mingmingz | 来源:发表于2018-07-13 16:31 被阅读7次

    前段时间用Kotlin完成一个SpringBoot小项目时遇到了些问题,写一篇以记录.
    代码地址:https://github.com/clockknock/lottery

    1.data class empty constructor

    Kotlin里面,如果使用了data class后,我们在Controller想要接收一个对象参数的时候,应用程序会报错,会说找不到空参构造,但如果我又还是想用data class那该怎么办呢?

        @PostMapping("/")
        fun save(user: User): String {//这行会提示没有可用的构造函数,因为我们知道Spring是通过该对象字节码获取空参构造来创建对象并调用setter来给field赋值的
            user.uid = UUIDUtil.getId()
            user.password = MD5Util.encodeSalt(user.password!!, salt)
    
            userService.save(user)
            return "redirect:loginUI"
        }
    

    我们如果是通过IDEA的SpringInitializr创建的基于gradle的kotlin项目,那build.gradle中一般是如下所示:

    buildscript {
    ...
        
        dependencies {
            classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
            classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
            classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
        }
    }
    
    apply plugin: 'kotlin'
    apply plugin: 'kotlin-spring'
    
    ...
    

    我们只需要添加两行代码就能让Kotlin的data class拥有空参构造

    buildscript {
    ...
        
        dependencies {
            classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
            classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
            classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
            //===================这一行===================
            classpath("org.jetbrains.kotlin:kotlin-noarg:${kotlinVersion}")
        }
    }
    
    apply plugin: 'kotlin'
    //===================以及这一行===================
    apply plugin: "kotlin-jpa"
    apply plugin: 'kotlin-spring'
    
    ...
    

    这时我们再回到我们的程序调用相应的方法想Spring自己给我们提供data class对象,就不会再有问题了

    2.Runtime Annotation With Delegate

    写的小项目中有这么一个问题,数据库中有一个表中的字段是以字符串形式存储的例如:"01,05,13,17,26,32",而在前端页面展示时需要将其以逗号为分隔符一个一个展示出来,我们得取出来后每次都split一下,很是麻烦,而且也不好直接去修改数据库的数据存储形式,只好在别的地方动手脚了

    runtime01.png

    在Kotlin中我们的field可以委托出去,我在BallHistory中声明了一个reds字段委托给了String2List这个类以处理原始字段red

    @Entity
    @Table(name = "ballhistory")
    class BallHistory {
        ...
    //原始数据库字段
    var red: String? = null
    //想要的可以遍历的处理后字段,写了by String2List后,会自动生成相应的委托方法
    var reds: List<String>? by String2List
        ...
    }
    

    String2List:

    object String2List {
        //有了这个委托方法后,我们的BallHistory.reds拿到的就已经是List<String>?类型的对象了
        operator fun getValue(ballHistory: BallHistory, property: KProperty<*>): List<String>? {
            //将ballHistory对象的red以","分隔返回一个list
            return ballHistory.red?.split(",")
        }
    
        //set方法并不需要如何做,如果有需要的话,可以把list转回String赋值给ballHistory的red
        operator fun setValue(ballHistory: BallHistory, property: KProperty<*>, list: List<String>?) {
    
        }
    }
    

    在做了以上处理后,reds这个field会被JPA识别成一个需要持久化到数据库的字段,这不是我想要的结果,我只想要reds这个list为我的业务提供一些帮助,JPA有提供一个注解@Transient,可以让这个字段不被持久化,但我们这个是委托属性,@Transient注解是运行时注解,无法帮我们做事情

    runtime02.png

    在文章底部的参考中有看到一个kotlin的注解可以帮我们将委托字段也可被运行时注解(Runtime Annotation)适用

        @delegate:Transient
        var reds: List<String>? by String2List
    

    用了@delegate注释后,就可以让@Transient这个运行时注解生效了

    参考:

    https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targets

    https://kotlinlang.org/docs/reference/compiler-plugins.html

    相关文章

      网友评论

        本文标题:20180713_KotlinWithSpringBoot

        本文链接:https://www.haomeiwen.com/subject/okhspftx.html