feat: 新增了笔记相关的接口
- getNoteDetailed - uploadNote - updateNote - deleteNote - starNote - likeNotemaster
parent
d50715f58c
commit
e9b6521c89
|
@ -39,6 +39,7 @@ repositories {
|
|||
dependencies {
|
||||
implementation("org.springframework.boot:spring-boot-starter-validation")
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||
// 日志
|
||||
implementation("org.springframework.boot:spring-boot-starter-log4j2")
|
||||
|
|
|
@ -10,5 +10,5 @@ echo 'saving...'
|
|||
docker save -o ..\docker\aics_main.tar auto/aics_main:latest
|
||||
|
||||
echo 'compressing...'
|
||||
Compress-Archive -Path ..\docker\aics_main.tar -DestinationPath ..\docker\aics_main.zip
|
||||
Compress-Archive -Path ..\docker\aics_main.tar -DestinationPath ..\docker\aics_main.zip -Update
|
||||
pause
|
|
@ -1,5 +1,11 @@
|
|||
package cn.edu.hfut.auto.knowledge.config
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer
|
||||
import com.fasterxml.jackson.databind.Module
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.core.convert.converter.Converter
|
||||
import org.springframework.stereotype.Component
|
||||
|
@ -16,4 +22,18 @@ class SerializeConfig {
|
|||
return UUID.fromString(source)
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun nullableUUIDModule(): Module {
|
||||
return SimpleModule().apply {
|
||||
addDeserializer(UUID::class.java, NullableUUIDJsonDeserializer())
|
||||
}
|
||||
}
|
||||
|
||||
class NullableUUIDJsonDeserializer : JsonDeserializer<UUID?>() {
|
||||
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): UUID? {
|
||||
return p.valueAsString?.takeIf { it != "null" }?.let { UUID.fromString(it) }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package cn.edu.hfut.auto.knowledge.config
|
||||
|
||||
import cn.edu.hfut.auto.knowledge.service.QueryService
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.web.reactive.function.client.WebClient
|
||||
import org.springframework.web.reactive.function.client.support.WebClientAdapter
|
||||
import org.springframework.web.service.invoker.HttpServiceProxyFactory
|
||||
import org.springframework.web.service.invoker.createClient
|
||||
|
||||
|
||||
@Configuration
|
||||
class WebClientConfig {
|
||||
@Bean
|
||||
fun webClient(objectMapper: ObjectMapper): WebClient {
|
||||
return WebClient.builder()
|
||||
.build()
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun queryService(webClient: WebClient, configurableBeanFactory: ConfigurableBeanFactory): QueryService {
|
||||
val httpServiceProxyFactory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(webClient))
|
||||
.embeddedValueResolver(configurableBeanFactory::resolveEmbeddedValue)
|
||||
.build()
|
||||
return httpServiceProxyFactory.createClient<QueryService>()
|
||||
}
|
||||
}
|
|
@ -157,6 +157,7 @@ class KnowledgeController(
|
|||
?.knowledgeFileAttribute
|
||||
?.let { attr ->
|
||||
knowledgeFileAttributeRepository.update(new(KnowledgeFileAttribute::class).by {
|
||||
id = knowledgeId
|
||||
starers = attr.starers.filterNot { it.id == loginUserId }
|
||||
if (active) {
|
||||
starers().addBy { id = loginUserId }
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
package cn.edu.hfut.auto.knowledge.controller
|
||||
|
||||
import cn.edu.hfut.auto.knowledge.entity.*
|
||||
import cn.edu.hfut.auto.knowledge.entity.vo.NotePutQueryVO
|
||||
import cn.edu.hfut.auto.knowledge.entity.vo.NoteVO
|
||||
import cn.edu.hfut.auto.knowledge.exception.BusinessError
|
||||
import cn.edu.hfut.auto.knowledge.exception.ErrorCode
|
||||
import cn.edu.hfut.auto.knowledge.repository.NoteRepository
|
||||
import cn.edu.hfut.auto.knowledge.service.QueryService
|
||||
import cn.edu.hfut.auto.knowledge.util.getLoginUser
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import org.babyfish.jimmer.kt.new
|
||||
import org.babyfish.jimmer.sql.kt.fetcher.newFetcher
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import java.time.LocalDateTime
|
||||
import java.util.*
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/note")
|
||||
class NoteController(
|
||||
private val noteRepository: NoteRepository,
|
||||
private val queryService: QueryService,
|
||||
private val objectMapper: ObjectMapper
|
||||
) {
|
||||
@GetMapping("/{noteId}")
|
||||
suspend fun getNoteDetailed(@PathVariable noteId: UUID): Note =
|
||||
noteRepository.findNullable(noteId, Note.DETAILED_FETCHER) ?: throw BusinessError(ErrorCode.RESOURCE_NOT_FOUND)
|
||||
|
||||
@PostMapping
|
||||
@Transactional(rollbackFor = [Exception::class])
|
||||
suspend fun uploadNote(@RequestBody vo: NoteVO): Note {
|
||||
val result = noteRepository.insert(new(Note::class).by {
|
||||
author().id = getLoginUser(objectMapper).id
|
||||
title = vo.title
|
||||
createTime = LocalDateTime.now()
|
||||
updateTime = createTime
|
||||
pageView = 0
|
||||
vo.tags.forEach {
|
||||
tags().addBy { id = it }
|
||||
}
|
||||
vo.linkingKnowledgeFiles.forEach {
|
||||
knowledgeFiles().addBy { id = it }
|
||||
}
|
||||
})
|
||||
queryService.putNote(result.id, NotePutQueryVO(result.title, vo.content, vo.tags))
|
||||
return result
|
||||
}
|
||||
|
||||
@PutMapping("/{noteId}")
|
||||
@Transactional(rollbackFor = [Exception::class])
|
||||
suspend fun updateNote(@PathVariable noteId: UUID, @RequestBody vo: NoteVO) {
|
||||
val result = noteRepository.update(new(Note::class).by {
|
||||
id = noteId
|
||||
title = vo.title
|
||||
createTime = LocalDateTime.now()
|
||||
pageView = 0
|
||||
tags()
|
||||
vo.tags.forEach {
|
||||
tags().addBy { id = it }
|
||||
}
|
||||
knowledgeFiles()
|
||||
vo.linkingKnowledgeFiles.forEach {
|
||||
knowledgeFiles().addBy { id = it }
|
||||
}
|
||||
})
|
||||
queryService.putNote(result.id, NotePutQueryVO(result.title, vo.content, vo.tags))
|
||||
}
|
||||
|
||||
@DeleteMapping("/{noteId}")
|
||||
suspend fun deleteNote(@PathVariable noteId: UUID) {
|
||||
noteRepository.deleteById(noteId)
|
||||
}
|
||||
|
||||
@PutMapping("/{noteId}/star")
|
||||
suspend fun starNote(@PathVariable noteId: UUID, active: Boolean) {
|
||||
val loginUserId = getLoginUser(objectMapper).id
|
||||
noteRepository.findNullable(noteId, newFetcher(Note::class).by {
|
||||
starers()
|
||||
})?.let { attr ->
|
||||
noteRepository.update(new(Note::class).by {
|
||||
id = noteId
|
||||
starers = attr.starers.filterNot { it.id == loginUserId }
|
||||
if (active) {
|
||||
starers().addBy { id = loginUserId }
|
||||
}
|
||||
})
|
||||
} ?: throw BusinessError(ErrorCode.RESOURCE_NOT_FOUND)
|
||||
}
|
||||
|
||||
@PutMapping("/{noteId}/like")
|
||||
suspend fun likeNote(@PathVariable noteId: UUID, active: Boolean) {
|
||||
val loginUserId = getLoginUser(objectMapper).id
|
||||
noteRepository.findNullable(noteId, newFetcher(Note::class).by {
|
||||
likers()
|
||||
})?.let { attr ->
|
||||
noteRepository.update(new(Note::class).by {
|
||||
id = noteId
|
||||
likers = attr.likers.filterNot { it.id == loginUserId }
|
||||
if (active) {
|
||||
likers().addBy { id = loginUserId }
|
||||
}
|
||||
})
|
||||
} ?: throw BusinessError(ErrorCode.RESOURCE_NOT_FOUND)
|
||||
}
|
||||
}
|
|
@ -26,20 +26,24 @@ interface Knowledge {
|
|||
val knowledgeFileAttribute: KnowledgeFileAttribute?
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val BRIEF_FETCHER = newFetcher(Knowledge::class).by {
|
||||
allScalarFields()
|
||||
knowledgeFileAttribute(KnowledgeFileAttribute.BRIEF_FETCHER)
|
||||
}
|
||||
@JvmField
|
||||
val DETAILED_FILE_FETCHER = newFetcher(Knowledge::class).by {
|
||||
allScalarFields()
|
||||
knowledgeFileAttribute(KnowledgeFileAttribute.DETAILED_FETCHER)
|
||||
}
|
||||
@JvmField
|
||||
val AS_PARENT_FETCHER = newFetcher(Knowledge::class).by {
|
||||
allScalarFields()
|
||||
parent()
|
||||
children(BRIEF_FETCHER)
|
||||
knowledgeFileAttribute(KnowledgeFileAttribute.BRIEF_FETCHER)
|
||||
}
|
||||
@JvmField
|
||||
val AS_CHILD_FETCHER = newFetcher(Knowledge::class).by {
|
||||
allScalarFields()
|
||||
parent(BRIEF_FETCHER)
|
||||
|
|
|
@ -31,11 +31,14 @@ interface KnowledgeFileAttribute {
|
|||
val notes: List<Note>
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val EXTERNAL_PREVIEWABLE_SUFFIXES = listOf("pdf", "ppt", "pptx", "doc", "docx", "xls", "xlsx")
|
||||
@JvmField
|
||||
val BRIEF_FETCHER = newFetcher(KnowledgeFileAttribute::class).by {
|
||||
allScalarFields()
|
||||
tags(Tag.ALL_FETCHER)
|
||||
}
|
||||
@JvmField
|
||||
val DETAILED_FETCHER = newFetcher(KnowledgeFileAttribute::class).by {
|
||||
allScalarFields()
|
||||
starers()
|
||||
|
|
|
@ -11,9 +11,11 @@ interface Note {
|
|||
@Id
|
||||
@GeneratedValue(generatorType = UUIDIdGenerator::class)
|
||||
val id: UUID
|
||||
@Key
|
||||
val title: String
|
||||
|
||||
@ManyToOne
|
||||
@Key
|
||||
val author: User
|
||||
val createTime: LocalDateTime
|
||||
val updateTime: LocalDateTime
|
||||
|
@ -39,6 +41,7 @@ interface Note {
|
|||
val likers: List<User>
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val BRIEF_FETCHER = newFetcher(Note::class).by {
|
||||
allScalarFields()
|
||||
author(User.BRIEF_FETCHER)
|
||||
|
@ -46,5 +49,19 @@ interface Note {
|
|||
starers()
|
||||
likers()
|
||||
}
|
||||
@JvmField
|
||||
val DETAILED_FETCHER = newFetcher(Note::class).by {
|
||||
allScalarFields()
|
||||
author(User.BRIEF_FETCHER)
|
||||
tags(Tag.ALL_FETCHER)
|
||||
knowledgeFiles {
|
||||
allScalarFields()
|
||||
starers()
|
||||
tags(Tag.ALL_FETCHER)
|
||||
knowledge { allScalarFields() }
|
||||
}
|
||||
starers()
|
||||
likers()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ interface Notice {
|
|||
val targetUser: User
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val BRIEF_FETCHER = newFetcher(Notice::class).by {
|
||||
allScalarFields()
|
||||
note { allScalarFields() }
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.babyfish.jimmer.sql.Entity
|
|||
import org.babyfish.jimmer.sql.GeneratedValue
|
||||
import org.babyfish.jimmer.sql.GenerationType
|
||||
import org.babyfish.jimmer.sql.Id
|
||||
import org.babyfish.jimmer.sql.Key
|
||||
import org.babyfish.jimmer.sql.kt.fetcher.newFetcher
|
||||
|
||||
@Entity
|
||||
|
@ -11,9 +12,11 @@ interface Tag {
|
|||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
val id: Long
|
||||
@Key
|
||||
val name: String
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val ALL_FETCHER = newFetcher(Tag::class).by {
|
||||
allScalarFields()
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ interface User {
|
|||
val starredNotes: List<Note>
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val BRIEF_FETCHER = newFetcher(User::class).by {
|
||||
allScalarFields()
|
||||
password(false)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package cn.edu.hfut.auto.knowledge.entity.vo
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
data class NotePutQueryVO(
|
||||
val title: String,
|
||||
val content: String,
|
||||
val tags: List<Long>
|
||||
)
|
||||
|
||||
data class NoteVO(
|
||||
val title: String,
|
||||
val content: String,
|
||||
val tags: List<Long>,
|
||||
val linkingKnowledgeFiles: List<UUID>
|
||||
)
|
|
@ -0,0 +1,7 @@
|
|||
package cn.edu.hfut.auto.knowledge.repository
|
||||
|
||||
import cn.edu.hfut.auto.knowledge.entity.Note
|
||||
import org.babyfish.jimmer.spring.repository.KRepository
|
||||
import java.util.UUID
|
||||
|
||||
interface NoteRepository : KRepository<Note, UUID>
|
|
@ -0,0 +1,15 @@
|
|||
package cn.edu.hfut.auto.knowledge.service
|
||||
|
||||
import cn.edu.hfut.auto.knowledge.entity.vo.NotePutQueryVO
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.service.annotation.HttpExchange
|
||||
import org.springframework.web.service.annotation.PutExchange
|
||||
import java.util.UUID
|
||||
|
||||
@HttpExchange(url = "\${aics.services-url.query}/search", contentType = MediaType.APPLICATION_JSON_VALUE)
|
||||
interface QueryService {
|
||||
@PutExchange("/note/{noteId}")
|
||||
suspend fun putNote(@PathVariable noteId: UUID, @RequestBody vo: NotePutQueryVO)
|
||||
}
|
|
@ -31,6 +31,8 @@ logging:
|
|||
|
||||
aics:
|
||||
max-permission-level: 3
|
||||
services-url:
|
||||
query: http://localhost:8082
|
||||
|
||||
tencent:
|
||||
secret-id: AKIDSlvvhEYfYBetvYzCBvhJrDLGwNbcR2B7
|
||||
|
|
|
@ -30,6 +30,8 @@ logging:
|
|||
|
||||
aics:
|
||||
max-permission-level: 3
|
||||
services-url:
|
||||
query: http://aics_query:8082
|
||||
|
||||
tencent:
|
||||
secret-id: AKIDSlvvhEYfYBetvYzCBvhJrDLGwNbcR2B7
|
||||
|
|
Loading…
Reference in New Issue