SpringBoot到Kotlin血泪史
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot到Kotlin血泪史相关的知识,希望对你有一定的参考价值。
参考技术A 如果原先有 @Bean(name="xxx") 直接用方法名即可(我原先的 name 和方法名不一样就很尴尬)hashedCredentialsMatcher 中的内容可以直接 new ,所以不需要注入
如果SpringBoot的版本从 1.5.x 变成了 2.0.x , shiroDialect 或者 shiroFilter 可能会报如下错误
把 thymeleaf-extras-shiro 的版本号改成 2.0.0 即可(原先是 1.2.1 )
在 SpringBoot 版本中,在 Realm 中注入 Service 时,为了启用缓存,需要在前面加上 @Lazy 注解,如下
在 Kotlin 版本中我不知道发了啥疯就把它去掉了(可能是看到前面类型是 lateinit var ,自以为是的觉得可以代替 @Lazy ),然后改成了改成如下形式
拷贝完整个项目之后,测试功能的时候,发现缓存没了……然后就开始疯狂DEBUG,从版本问题,到 jar 包冲突问题,经历了很漫长的一段时间后,我定位到了 ShiroConfiguration ,只要把 shiro aop 注解关闭就可以开启缓存了
WHAT??
疯狂谷歌一个小时无果(因为一直以为是 Kotlin 不兼容啥的,或者是 shiro 在 boot2.x 之后需要修改相应的配置)
然后又疯狂DEBUG,把 Kotlin 版和 springboot 版进行对比,最后。定位到了 @Lazy (还好只是改成了注释,没把它给直接删了)
果然。加了 @Lazy ,整个天都亮了
最后顺便提一句 Realm 认证超级管理员的问题,可以直接在 Realm 中加上超级管理员的特别认证,就不用去方法级别上区分这个权限可以超级管理和XX管理员都可用了
springboot+kotlin+gradle+hibernate学习笔记
Hibernate 将 Java 类映射到数据库表中,从 Java 数据类型中映射到 SQL 数据类型中,并把开发人员从 95% 的公共数据持续性编程工作中解放出来。是传统 Java 对象和数据库服务器之间的桥梁,用来处理基于 O/R 映射机制和模式的那些对象。
Hibernate 优势
Hibernate 使用 XML 文件来处理映射 Java 类别到数据库表格中,并且不用编写任何代码。
为在数据库中直接储存和检索 Java 对象提供简单的 APIs。
如果在数据库中或任何其它表格中出现变化,那么仅需要改变 XML 文件属性。
抽象不熟悉的 SQL 类型,并为我们提供工作中所熟悉的 Java 对象。
Hibernate 不需要应用程序服务器来操作。
操控你数据库中对象复杂的关联。
最小化与访问数据库的智能提取策略。
提供简单的数据询问。
build.gradle.kts
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins
id("org.springframework.boot") version "2.3.7.RELEASE"
id("io.spring.dependency-management") version "1.0.10.RELEASE"
kotlin("jvm") version "1.3.72"
kotlin("plugin.spring") version "1.3.72"
group = "com"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_1_8
configurations
compileOnly
extendsFrom(configurations.annotationProcessor.get())
repositories
mavenLocal() //配置先从本地仓库寻找jar包,优先寻找上一个配置,找到不执行下面的配置
mavenCentral() //配置从中央仓库寻找
google() //第三方仓库
dependencies
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
// https://mvnrepository.com/artifact/org.hibernate/hibernate-core
implementation("org.hibernate:hibernate-core:5.6.10.Final")
runtimeOnly("mysql:mysql-connector-java:5.1.6")
compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-test")
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
// https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter
implementation("com.alibaba:druid-spring-boot-starter:1.2.8")
// https://mvnrepository.com/artifact/org.springframework/spring-orm
implementation("org.springframework:spring-orm:5.3.21")
// https://mvnrepository.com/artifact/cn.hutool/hutool-core
implementation("cn.hutool:hutool-core:5.8.4")
tasks.withType<Test>
useJUnitPlatform()
tasks.withType<KotlinCompile>
kotlinOptions
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "1.8"
application.yml
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
name: defaultDataSource
url: jdbc:mysql://localhost:3306/people?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
password: 123456
username: root
配置数据源
package com.spring_hibernate.config
import com.alibaba.druid.pool.DruidDataSource
import org.springframework.beans.factory.annotation.Configurable
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import javax.sql.DataSource
@Configurable
class DataSourceConfig
@Bean
@ConfigurationProperties("spring.datasource")
fun dataSource(): DataSource?
val source = DruidDataSource()
//source.setDriverClassName("com.mysql.cj.jdbc.Driver");
source.isBreakAfterAcquireFailure = true
source.name = "root"
source.initialSize = 1
//最大活动
source.maxActive = 10
source.maxWait = 60000
//配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
source.timeBetweenEvictionRunsMillis = 60000
//配置一个连接在池中最小生存的时间,单位是毫秒
source.minEvictableIdleTimeMillis = 300000
//每分钟打印一次连接状态日志
//source.setTimeBetweenLogStatsMillis(60000);
return source
配置hibernate
package com.spring_hibernate.config
import com.alibaba.druid.pool.DruidDataSource
import org.springframework.context.annotation.Bean
import org.springframework.orm.hibernate5.LocalSessionFactoryBean
import org.springframework.stereotype.Component
import java.util.*
import javax.annotation.Resource
import javax.sql.DataSource
@Component
class HibernateToConfig
@Resource
private val dataSource: DataSource? = null
/**
* 此处bean为根据 hibernate 官网配置文件 hibernate.cfg.xml 改造的
* https://docs.jboss.org/hibernate/orm/5.5/quickstart/html_single/hibernate-tutorials.zip
*
* @return
*/
@Bean
fun sessionFactory(): LocalSessionFactoryBean?
val bean = LocalSessionFactoryBean()
if (dataSource != null)
bean.setDataSource(dataSource)
// 扫描实体类
bean.setPackagesToScan("com.spring_hibernate.entity")
val properties = Properties()
properties.setProperty("current_session_context_class", "thread")
val druidDataSource = dataSource as DruidDataSource?
properties.setProperty("connection.pool_size", druidDataSource!!.maxActive.toString())
// 配置方言 mysql 5.7.34
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL57Dialect")
// <!-- 控制台打印SQL -->
properties.setProperty("hibernate.show_sql", "true")
// 制台打印SQL格式化
//properties.setProperty("hibernate.format_sql", "true");
/**
* create:表示启动的时候先drop,再create
* create-drop: 也表示创建,只不过再系统关闭前执行一下drop
* update: 这个操作启动的时候会去检查schema是否一致,如果不一致会做scheme更新
* validate: 启动时验证现有schema与你配置的hibernate是否一致,如果不一致就抛出异常,并不做更新
*/
// 首次启动使用 create 让bean自动生成表,之后使用 update模式即可
properties.setProperty("hibernate.hbm2ddl.auto", "update")
bean.setHibernateProperties(properties)
return bean
在配置hibernate时,需要配置实体类的包,然后在 properties.setProperty(“hibernate.hbm2ddl.auto”, “create”) 在第一次启动时,就会根据类对象,创建数据表,但是在这之前需要指定数据库,在application.yml中进行指定,本demo使用的是MySQL5.1.6的驱动,所以在application.yml中是com.mysql.jdbc.Driver,要是使用更高版本的驱动,需要使用com.mysql.cj.jdbc.Driver
自定义主键生成
package com.spring_hibernate.util
import cn.hutool.core.lang.Snowflake
import cn.hutool.core.util.IdUtil;
import org.hibernate.HibernateException
import org.hibernate.MappingException
import org.hibernate.engine.spi.SharedSessionContractImplementor
import org.hibernate.id.Configurable
import org.hibernate.id.IdentifierGenerator
import org.hibernate.service.ServiceRegistry
import org.hibernate.type.Type
import java.io.Serializable
import java.util.*
/**
* 采用雪花算法生成主键
* 2021年7月11日22:11:55
*/
class PrimaryGenerator : Configurable, IdentifierGenerator
var snowflake: Snowflake? = IdUtil.getSnowflake(1, 1)
private var pre = ""
@Throws(MappingException::class)
override fun configure(type: Type, params: Properties, serviceRegistry: ServiceRegistry)
val prefix = params.getProperty("prefix")
if (prefix != null) pre = prefix
@Throws(HibernateException::class)
override fun generate(session: SharedSessionContractImplementor, `object`: Any): Serializable
//雪花算法生成ID
return pre + snowflake!!.nextIdStr()
实体类
package com.spring_hibernate.entity
import lombok.Data
import org.hibernate.annotations.GenericGenerator
import java.util.*
import javax.persistence.*
@Data
@Entity
@Table(name = "t_user")
class UserBean
// 主键采用string为了兼容更多数据库
@Id
@Column(length = 20)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "gg") //自定义生成主键
@GenericGenerator(name = "gg", strategy = "com.spring_hibernate.util.PrimaryGenerator")
val id: String? = null
@Column(length = 40)
var username: String? = null
@Column(length = 64)
var password: String? = null
@Column(length = 20)
var nickname: String? = null
@Column(name = "create_time")
var createTime: Date? = null
在第一次运行完之后,就会在指定数据库创建表,该表的字段和上面的实体类一一对应
controller
package com.spring_hibernate.controller
import com.spring_hibernate.entity.UserBean
import com.spring_hibernate.service.UserBeanService
import com.spring_hibernate.util.R
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping("/user")
class UserBeanController
@Autowired
lateinit var userBeanService: UserBeanService
@Transactional
@PostMapping
fun insertOne(@RequestBody userBean: UserBean): R<*>
return userBeanService.insertOne(userBean)
@Transactional
@PutMapping
fun updateOne(@RequestBody userBean: UserBean):R<*>
return userBeanService.updateOne(userBean)
@Transactional
@DeleteMapping
fun deleteOne(@RequestBody userBean: UserBean): R<*>
return userBeanService.deleteOne(userBean)
@Transactional
@GetMapping
fun getOne(id:String):R<*>
return userBeanService.getOne(id)
@Transactional
@GetMapping("/all")
fun getAll():R<*>
return userBeanService.getAll()
这里的R还是自己封装好的返回值类型
dao层
package com.spring_hibernate.service.impl
import com.spring_hibernate.entity.UserBean
import com.spring_hibernate.service.UserBeanService
import com.spring_hibernate.util.R
import org.hibernate.SessionFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Repository
import java.util.*
@Repository
class UserBeanServiceImpl : UserBeanService
@Autowired
lateinit var sessionFactory:SessionFactory
override fun insertOne(userBean: UserBean): R<*>
userBean.createTime = Date()
val line = sessionFactory.currentSession.save(userBean)
println("line::$line")
return R.ok(line,"插入成功")
override fun updateOne(userBean: UserBean): R<*>
val user:UserBean = sessionFactory
.currentSession
.createQuery("from UserBean where id=:id")
.setParameter("id", userBean.id).uniqueResult() as UserBean
user.nickname = userBean.nickname
user.username = userBean.username
user.password = userBean.password
sessionFactory.currentSession.update(user)
return R.ok(null,"修改数据")
override fun deleteOne(userBean: UserBean): R<*>
val res = sessionFactory.currentSession
.createQuery("delete from UserBean where id=:id")
.setParameter("id", userBean.id).executeUpdate()
return R.ok(res,"删除成功")
override fun getOne(id: String): R<*>
val user:UserBean = sessionFactory
.currentSession
.createQuery("from UserBean where id=:id")
.setParameter("id", id).uniqueResult() as UserBean
return R.ok(user,"找到一条记录")
override fun getAll(): R<*>
val list = sessionFactory
.currentSession
.createQuery("from UserBean")
.list()
return R.ok(list,"查询所有")
上述是一些基本的CRUD操作,需要查找更多的模板代码,可以去如下地址
https://www.w3cschool.cn/hibernate/hvqb1ie5.html
以上是关于SpringBoot到Kotlin血泪史的主要内容,如果未能解决你的问题,请参考以下文章
Gradle kotlin Springboot多模块导致无法引用kotlin的类文件(BootJar)
springboot+kotlin+gradle+hibernate学习笔记
springboot+kotlin+gradle+hibernate学习笔记