# 尝试 Kotlin Springboot > 总体上来讲,Kotlin 与 Java 相比是有好有坏的,优点是写起来更简洁,缺点是写起来更简洁。 Springboot(Spring) 是目前 JVM 平台功能最强大、扩展性最好、健壮性最好的后端框架。 ## 创建一个 Springboot 项目 这很简单,在 IDEA 中就可以创建,记得选 Kotlin 和 Gradle kts。 自带插件的话根据你的需要来选就好,如果你只是想利用 Springboot 来做一个命令行小程序也是可以的。 ## 插件与依赖 ### `build.gradle.kts` 插件配置 新建项目后,你的 `plugins` 里面应该有这几项: ```kotlin plugins { // 可以不用定义变量,但要保证版本一致 val kotlinVersion = "2.0.0" kotlin("jvm") version kotlinVersion // Spring 专用的 Kotlin 编译器插件 kotlin("plugin.spring") version kotlinVersion id("org.springframework.boot") version "3.3.0" id("io.spring.dependency-management") version "1.1.5" // 如果你用 JPA,建议加上这个,自动给数据实体类生成无参构造函数 // kotlin("plugin.jpa") version kotlinVersion } ``` ### 依赖配置 在 `dependencies` 里,除了常规的 `spring-boot-starter-web`,还需要带上 Kotlin 的反射库: ```kotlin dependencies { implementation("org.springframework.boot:spring-boot-starter-web") // Kotlin 反射库,Spring 容器扫描注入时需要用到 implementation("org.jetbrains.kotlin:kotlin-reflect") testImplementation("org.springframework.boot:spring-boot-starter-test") } ``` 在 Java 下通常默认用 Jackson 来处理 JSON;而在 Kotlin 下,通常更推荐配合 Kotlin 原生的序列化方案。 ## 项目文件的文件夹分类 在 Springboot 里面,基本就是大家非常熟悉的经典 MVC 分层结构。在 Kotlin 里面一般也是这么分: - `src/main/kotlin/com/example/demo/` - `DemoApplication.kt`:启动类,里面有 `@SpringBootApplication` 和 `main` 函数 - `controller/`:接收前端请求的 Controller,写路由接口的地方(例如 `UserController.kt`) - `service/`:业务接口与实现类(例如 `UserService.kt`) - `repository/` 或 `dao/`:数据库访问层(比如 Spring Data JPA 的接口或 MyBatis 的 Mapper),如果是 Mapper 的话有时会直接写作 `Mapper`。 - `entity/`:数据库表对应的实体类 - `dto/`:数据传输对象(前端传进来的 Request,或者返回给前端的 Response),有时会选择放在 entity 里面 - `config/`:全局配置类(跨域配置、Spring Security 配置等) - `exception/`:全局异常拦截类(`@RestControllerAdvice`) - `src/main/resources/` - `application.yml`:全局配置文件(推荐用 yml,结构比 properties 清晰很多) ## 基本的编写思路 Kotlin 写 Springboot 和 Java 最大的区别,就是 Kotlin 本身的特性减少了大量代码。 ### 构造器注入 在 Java 常使用 `@Autowired`,但在 Kotlin 里面,直接用主构造函数用写变量定义即可: ```kotlin @Service class UserService( private val userRepository: UserRepository // 类对象被创建时自动注入对象 ) { fun findUser(id: Long): UserDto { val user = userRepository.findById(id).orElseThrow() return UserDto(user.id, user.name) } } ``` ### 用 `data class` 写 DTO 和数据载体 Java 会使用 Lombok 生成标准 Java Bean 类,Kotlin 的 `data class` 会自动生成 `getter/setter`、`equals`、`hashCode`、`copy`: ```kotlin data class CreateUserRequest( val username: String, val email: String? = null // 问号表示可以为 null,对应选填字段 ) data class UserDto( val id: Long, val username: String ) ``` ### Controller Controller 写法和常规 Springboot 一模一样,但由于 Kotlin 支持单行表达式,写起来格外干净: ```kotlin @RestController @RequestMapping("/api/users") class UserController( private val userService: UserService ) { @GetMapping("/{id}") fun getUser( @PathVariable id: Long ): UserDto { return userService.findUser(id) } @PostMapping fun createUser( @RequestBody request: CreateUserRequest ): UserDto { return userService.createUser(request) } } ``` ### 全局异常处理 用 `@RestControllerAdvice` 兜底,不用在 Controller 里写 `try-catch`: ```kotlin @RestControllerAdvice class GlobalExceptionHandler { @ExceptionHandler(NoSuchElementException::class) fun handleNotFound(e: NoSuchElementException): ResponseEntity { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.message) } } ``` ## 配置文件的写法 Springboot 支持 `.properties` 和 `.yml`,强烈推荐使用 `application.yml`。 在 `src/main/resources/application.yml` 里一般写: ```yaml server: port: 8080 # 端口 spring: application: name: my-kotlin-app datasource: url: jdbc:mysql://localhost:3306/mydb username: root password: rootpassword # 自定义配置 my-config: token-secret: "abcdefg123456" ``` ### 在 Kotlin 代码中读取配置 有两种常见方式: #### @Value 适合只读取一两个简单变量: ```kotlin @Component class MyComponent( @Value("$${my-config.token-secret}") private val tokenSecret: String ) ``` #### @ConfigurationProperties 与 data class 把整块配置映射成一个不可变的数据类,方便快捷: ```kotlin @ConfigurationProperties(prefix = "my-config") data class MyConfigProperties( val tokenSecret: String ) ``` 只要在启动类上加上 `@ConfigurationPropertiesScan`,就可以直接把它像普通 Service 一样注入到任何地方使用了。 ## 接下来可以看 [目录](../README.md) [下一篇:Kotlin Ktor](./Kotlin-Ktor.md) [更进一步:成为 Kotlin 超人](./成为Kotlin超人.md) [进入 KMP](./进入KMP.md)