SprongBoot + Koltin + MongoDB
项目搭建
- 打开IDEA,选择File =>New ==> Project
- 选择Spring Initializr,点击 Next
- 勾选Gradle环境,选择Kotlin语言,输入自己的包名,点击Next
- 点击web,勾选Spring Web, 到门口NoSQL ,勾选SpringDataMongoDB ,点击Next ==> Finish,等待构建完成,一个Springboot项目就搭建好了
-
在包目录下新建几个文件夹,分别存放实体类,请求接口,数据仓库等
- 在application.properties中配置数据库连接地址
例:获取心灵鸡汤
实体类
-
在pojo下新建一个实体类,承载数据
package com.sss.notes.pojo import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.mapping.Document /** * Document 表示MongoDB的一个文档 * collation代表实体类对应数据库中collection的名称 * @Id则代表了MongoDB中的ObjectId,用String承载改类型 */ @Document(collection = "soups") data class Soup( @Id val id: String?, val name: String? ){ /** * 建议实体类添加默认的空参构造函数 因为MongoDB是非关系型数据库数据字段有多有少 * 在查询数据中,SpringBoot由于找不到默认的构造函数而报错 * 如 Failed to instantiate void using constructor NO_CONSTRUCTOR with arguments */ constructor():this("","") }
该实体类承载的collection:
数据仓库
- 在repository下新建SoupRepository
package com.sss.notes.repository
import com.sss.notes.pojo.Soup
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.query.Query
import org.springframework.stereotype.Repository
/**
* @Repository 注解可以标记在任何的类上
* 用来表明该类是用来执行与数据库相关的操作(即dao对象)
* 并支持自动处理数据库操作产生的异常
*/
@Repository
class SoupRepository(private val mongoTemplate: MongoTemplate) {
/**
* 将mongoTemplate写入构造方法, 会自动注入到SoupRepository中
* 或者可以将mongoTemplate从构造方法中移到成员变量中
* 并且使用@Autowired 标记
* mongoTemplate 也会自动被写入
*/
// @Autowired
// private lateinit var mongoTemplate: MongoTemplate
/**
* 使用mongoTemplate 查询以startStr开头的心灵鸡汤
*/
fun findByNameStartWith(startStr: String): List<Soup> {
//正则表达式左匹配
val pattern: Pattern = Pattern.compile("^$startStr.*$")
val query = Query.query(Criteria.where("name").regex(pattern))
return mongoTemplate.find(query, Soup::class.java)
}
}
控制层
-
在controller包下新建一个SoupController,提供给客户端调用
package com.sss.notes.controller import com.sss.notes.pojo.Soup import com.sss.notes.repository.SoupRepository import org.springframework.http.HttpStatus import org.springframework.web.bind.annotation.* /** * 使用@RestController 标记 SoupController * 让Springboot 知道这是一个处理http请求的类 * @RequestMapping:配置url映射 */ @RequestMapping("v1/test/") @RestController class SoupController(private val soupRepository: SoupRepository) { @ResponseStatus(HttpStatus.OK) @GetMapping("/soup") fun getSoup(@RequestParam("start") startStr: String): List<Soup> { return soupRepository.findByNameStartWith(startStr) } }
启动服务,进行测试
多种查询实现的方式
回头看SoupRepository,还可以借助springboot自带的MongoRepository来完成,在repository新建一个接口SoupMongoRepository
package com.sss.notes.repository
import com.sss.notes.pojo.Soup
import org.springframework.data.mongodb.repository.MongoRepository
interface SoupMongoRepository : MongoRepository<Soup, String> {
/**
* 接口不用写实现类
* 根据自己的需求和MongoRepository下输入方法时的提示
* SpringBoot在初始化的时候会自动实现该查找
*/
fun findAllByNameStartingWith(startStr: String)
}
-
将SoupController中的SoupRepository替换为SoupMongoRepository
package com.sss.notes.controller import com.sss.notes.pojo.Soup import com.sss.notes.repository.SoupMongoRepository import org.springframework.http.HttpStatus import org.springframework.web.bind.annotation.* /** * 使用@RestController 标记 SoupController * 让Springboot 知道这是一个处理http请求的类 * @RequestMapping:配置url映射 */ @RequestMapping("v1/test/") @RestController class SoupController(private val soupRepository: SoupMongoRepository) { @ResponseStatus(HttpStatus.OK) @GetMapping("/soup") fun getSoup(@RequestParam("start") startStr: String): List<Soup>? { return soupRepository.findAllByNameStartingWith(startStr) } }
-
运行后实现了同样的效果,但是在通常的情况下,数据库中的id我们是不返回给前端的,可以借助Query注解来屏蔽某个字段。
package com.sss.notes.repository import com.sss.notes.pojo.Soup import org.springframework.data.mongodb.repository.MongoRepository import org.springframework.data.mongodb.repository.Query interface SoupMongoRepository : MongoRepository<Soup, String> { /** * 如果这样写的话,方法随意命名 * @Query注解标记之后,Springboot会根据 @Query中的内容自动生成查询实现方法 * value 代表查询条件 ,此处使用了正则表达式,查找以startStr开头的鸡汤,?0表示方法中的第一个参数startStr,依次类推 * fields 代表查询返回的字段,0为不返回,反之1为返回 * */ @Query(value = "{ 'name':{\$regex:/^?0/}}", fields = "{ 'id' : 0 }") fun findAllByNameStartStr(startStr: String):List<Soup>? }
重新运行项目,测试后,id字段就没有值了
-
还可以使用MongoRepository中自带的方法来实现该查询,使用ExampleMatcher,修改SoupController,重新运行项目
package com.sss.notes.controller import com.sss.notes.pojo.Soup import com.sss.notes.repository.SoupMongoRepository import org.springframework.data.domain.Example import org.springframework.data.domain.ExampleMatcher import org.springframework.http.HttpStatus import org.springframework.web.bind.annotation.* /** * 使用@RestController 标记 SoupController * 让Springboot 知道这是一个处理http请求的类 * @RequestMapping:配置url映射 */ @RequestMapping("v1/test/") @RestController class SoupController(private val soupRepository: SoupMongoRepository) { // @ResponseStatus(HttpStatus.OK) // @GetMapping("/soup") // fun getSoup(@RequestParam("start") startStr: String): List<Soup>? { // return soupRepository.findAllByNameStartingWith(startStr) // } @ResponseStatus(HttpStatus.OK) @GetMapping("/soup") fun getSoup(@RequestParam("start") startStr: String): List<Soup>? { val soup = Soup(name = startStr) //使用ExampleMatcher 必须添加忽略路径_class,否则将会搜索不到结果 //_class是springboot 保存MongoDB数据时,自动增加的一个字段,其内容为实体类的包路径, //其目的主要是为了适配多态的场景下能够准确的找到初始化的类 //当然在实体类包路径移动后也可以正常工作,最终以查询时实际传入的泛型为实例化参照 val exampleMatcher = ExampleMatcher.matching() .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.startsWith()) .withIgnorePaths("_class") val example = Example.of(soup,exampleMatcher) return soupRepository.findAll(example) } }
实现了相同的效果
注意事项
在使用Koltin+SpringBoot时,要保证包中的类全部是.kt的kotlin文件,否则会出现ClassNotFonud,加了注解类缺扫不到等异常,可以借助IDEA在如下所示的方法查看项目中已生成的Bean