1. 简介
在本文中,我们将使用 Spring Boot 和 Kotlin 构建一个简单的 CRUD(创建、读取、更新、删除)API。我们将以一个任务管理系统为例,展示如何使用 Kotlin 语言结合 Spring Boot 快速搭建 RESTful 接口。
2. 项目搭建
要完成本项目,需要先搭建一个支持 Kotlin 的 Spring Boot 项目。建议使用 Spring Initializr 创建项目,选择以下依赖:
- Spring Web
- Spring Data JPA
- H2 Database(用于内存数据库)
Kotlin 与 Spring Boot 集成非常方便,只需在 build.gradle.kts
中引入 Kotlin 插件和 Spring Boot 插件即可。
3. 定义实体与仓库
我们首先定义一个 TaskEntity
数据类,用于映射数据库表:
@Entity(name = "task")
data class TaskEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long?,
var name: String,
var description: String,
var done: Boolean
)
⚠️ 注意:
id
被定义为Long?
是为了支持 JPA 的自动生成 ID 机制。
接下来,定义一个 JPA Repository:
@Repository
interface TaskRepository : JpaRepository<TaskEntity, Long>
至此,我们已经完成了数据模型和持久层的搭建。
4. 实现 CRUD 操作
4.1 控制器与服务类
我们创建一个 TaskController
作为 REST API 的入口点:
@RestController
@RequestMapping("/tasks")
class TaskController(var taskService: TaskService)
同时,创建 TaskService
作为业务逻辑层:
@Service
class TaskService(var repository: TaskRepository)
4.2 创建任务
定义用于请求和响应的数据传输对象(DTO):
data class TaskDTORequest(
var name: String,
var description: String,
var done: Boolean
)
data class TaskDTOResponse(
var id: Long,
var name: String,
var description: String,
var done: Boolean
)
创建任务的接口如下:
@PostMapping("/create")
fun createTask(@RequestBody newTask: TaskDTORequest): TaskDTOResponse {
return taskService.createTask(newTask)
}
对应的服务方法:
fun createTask(newTask: TaskDTORequest): TaskDTOResponse {
val saved = repository.save(TaskEntity(id = null, newTask.name, newTask.description, newTask.done))
return TaskDTOResponse(saved.id!!, saved.name, saved.description, saved.done)
}
✅ 提示:这里使用了
!!
操作符,表示我们确信id
不为 null,否则会抛出NullPointerException
。
4.3 查询任务
接口定义:
@GetMapping("/{id}")
fun getTask(@PathVariable id: Long): TaskDTOResponse {
return taskService.getTask(id)
?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Task not found")
}
服务层实现:
fun getTask(id: Long): TaskDTOResponse? {
return repository.findById(id)
.map { TaskDTOResponse(it.id!!, it.name, it.description, it.done) }
.getOrNull()
}
4.4 更新任务
使用 @PutMapping
实现任务更新:
@PutMapping("/{id}")
fun updateTask(@PathVariable id: Long, @RequestBody updatedTask: TaskDTORequest): TaskDTOResponse {
return taskService.updateTask(id, updatedTask)
?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Task not found")
}
服务层:
fun updateTask(id: Long, updatedTask: TaskDTORequest): TaskDTOResponse? {
return repository.findById(id).map {
val updated = repository.save(TaskEntity(it.id, updatedTask.name, updatedTask.description, updatedTask.done))
TaskDTOResponse(updated.id!!, updated.name, updated.description, updated.done)
}.orElseGet { null }
}
4.5 删除任务
接口定义:
@DeleteMapping("/{id}")
fun deleteTask(@PathVariable id: Long) {
taskService.deleteTask(id)
}
服务层:
fun deleteTask(id: Long) {
repository.deleteById(id)
}
5. 接口测试
我们使用 @SpringBootTest
和 TestRestTemplate
进行集成测试:
@SpringBootTest(
classes = [SpringBootCrudApplication::class],
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
class TaskDTOResponseCRUDIntegrationTest(@Autowired var restTemplate: TestRestTemplate) {
// 测试逻辑...
}
测试创建任务:
val taskDTORequest = TaskDTORequest("Task", "description", false)
val result = this.restTemplate.postForEntity("/tasks/create", taskDTORequest, TaskDTOResponse::class.java)
taskId = result.body?.id!!
assertTrue { result.body?.name == "Task" }
测试获取任务:
val result = this.restTemplate.getForEntity("/tasks/{id}", TaskDTOResponse::class.java, taskId)
assertTrue { result.body?.name == "Task" }
测试更新任务:
this.restTemplate.put("/tasks/{id}", taskDTORequest, taskId)
val result = this.restTemplate.getForEntity("/tasks/{id}", TaskDTOResponse::class.java, taskId)
assertTrue { result.body?.done!! }
测试删除任务:
this.restTemplate.delete("/tasks/{id}", taskId)
val result = this.restTemplate.getForEntity("/tasks/{id}", String::class.java, taskId)
assertTrue { result.statusCode == HttpStatus.NOT_FOUND }
6. 总结
本文我们使用 Spring Boot 和 Kotlin 实现了一个完整的 CRUD API。我们通过定义实体、仓库、服务和控制器,展示了如何使用 Kotlin 构建结构清晰、可维护的后端接口。
✅ 建议:始终使用 DTO 而不是实体类暴露给外部接口,避免耦合数据库结构与 API 模型,便于未来扩展。
如果你是 Kotlin 爱好者或正在寻找快速搭建 Spring Boot 项目的方案,本文提供的结构是一个不错的起点。