docs(core): add KDoc documentation to controllers, services, and entities
Add descriptive KDoc comments to all REST controllers, service interfaces, entity classes, and mappers to improve code readability and maintainability. Include annotations for controller-level API documentation.
This commit is contained in:
@@ -3,6 +3,9 @@ package com.msksbr.bookmgr
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
||||
|
||||
/*
|
||||
* Spring Boot 启动类
|
||||
*/
|
||||
@SpringBootApplication
|
||||
class BookMgrApplication
|
||||
|
||||
|
||||
@@ -3,7 +3,9 @@ package com.msksbr.bookmgr.config
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
//获取真实IP的bean
|
||||
/*
|
||||
* 从请求头中提取真实客户端 IP(处理反向代理)
|
||||
*/
|
||||
@Component
|
||||
class IpExtractor {
|
||||
fun getRealIp(request: HttpServletRequest): String {
|
||||
|
||||
@@ -13,7 +13,8 @@ import java.util.*
|
||||
import javax.crypto.SecretKey
|
||||
|
||||
/*
|
||||
* 注册JWT的失效时间和密钥
|
||||
* JWT 令牌工具:签发、解析
|
||||
* 密钥来源:环境变量 JWT_SECRET,未配置时自动生成(重启失效)
|
||||
*/
|
||||
@Component
|
||||
class JwtUtils(
|
||||
@@ -22,10 +23,9 @@ class JwtUtils(
|
||||
) {
|
||||
private val secretKey: SecretKey
|
||||
|
||||
// 没有配置key时自动生成
|
||||
// 初始化密钥:有配置时用 SHA-256 哈希,无配置时随机生成
|
||||
init {
|
||||
val keyBytes = if (configuredSecret.isNotBlank()) {
|
||||
// 把用户提供的secret,用SHA-256哈希成256字节固定长度
|
||||
val md = MessageDigest.getInstance("SHA-256")
|
||||
md.digest(configuredSecret.toByteArray())
|
||||
} else {
|
||||
@@ -39,7 +39,7 @@ class JwtUtils(
|
||||
secretKey = Keys.hmacShaKeyFor(keyBytes)
|
||||
}
|
||||
|
||||
// 生成token
|
||||
// 签发 token,payload 包含 role
|
||||
fun generateToken(username: String, role: String): String {
|
||||
val claims = Jwts.claims().add("role", role).build()
|
||||
val token = Jwts.builder().claims(claims).subject(username)
|
||||
@@ -52,16 +52,16 @@ class JwtUtils(
|
||||
return token
|
||||
}
|
||||
|
||||
// 解析token
|
||||
// 解析 token,校验失败时记日志并返回 null
|
||||
fun parseToken(token: String): Claims? {
|
||||
try {
|
||||
val claims = Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token)
|
||||
return claims.payload
|
||||
} catch (e: JwtException) {
|
||||
log.error("Token parsing failed", e)
|
||||
log.error("[JWT] parse failed: {}", e.message)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
log.error("Token parsing failed with illegalArguments: $token", e)
|
||||
log.error("[JWT] parse failed: illegal argument")
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,11 @@ import org.aspectj.lang.annotation.Aspect
|
||||
import org.aspectj.lang.annotation.Pointcut
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
/*
|
||||
* AOP 日志切面:自动记录方法入口/出口/耗时
|
||||
* - controller/service/runner/jwt:DEBUG 级别,超 500ms 时 WARN
|
||||
* - mapper:TRACE 级别,日常不输出
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
class LoggingAspect {
|
||||
|
||||
@@ -5,6 +5,9 @@ import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder
|
||||
import org.springframework.security.crypto.password.PasswordEncoder
|
||||
|
||||
/*
|
||||
* Argon2 密码编码器配置
|
||||
*/
|
||||
// 将Argon2的加盐哈希方法注册成Bean
|
||||
@Configuration
|
||||
class PasswordConfig {
|
||||
|
||||
@@ -2,6 +2,9 @@ package com.msksbr.bookmgr.controller
|
||||
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
/*
|
||||
* 管理端图书接口
|
||||
*/
|
||||
@RestController
|
||||
class AdminBookController {
|
||||
}
|
||||
@@ -2,6 +2,9 @@ package com.msksbr.bookmgr.controller
|
||||
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
/*
|
||||
* 管理端借阅接口
|
||||
*/
|
||||
@RestController
|
||||
class AdminBorrowController {
|
||||
}
|
||||
@@ -14,8 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
/*
|
||||
* 登录接口
|
||||
* 接收DTO,返回json
|
||||
* 认证接口:登录 / 登出
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
@@ -31,14 +30,13 @@ class AuthController(
|
||||
loginDTO: UserLoginDTO,
|
||||
request: HttpServletRequest
|
||||
): Result<out Any?> {
|
||||
log.info("Login from ${ipExtractor.getRealIp(request)} username: ${loginDTO.username}")
|
||||
log.info("UA: ${request.getHeader("User-Agent")}")
|
||||
// 调用service验证
|
||||
log.info("[Auth] login attempt: user={}, ip={}", loginDTO.username, ipExtractor.getRealIp(request))
|
||||
log.debug("[Auth] user agent: {}", request.getHeader("User-Agent"))
|
||||
val user = authService.login(loginDTO)
|
||||
return if (user != null) {
|
||||
// 登录成功,返回JWT
|
||||
// 登录成功,签发 JWT
|
||||
val token = jwtUtils.generateToken(user.username, user.role)
|
||||
log.info("Login success")
|
||||
log.info("[Auth] login success: user={}", user.username)
|
||||
Result.success(
|
||||
mapOf(
|
||||
"token" to token,
|
||||
@@ -47,8 +45,8 @@ class AuthController(
|
||||
)
|
||||
)
|
||||
} else {
|
||||
log.info("Login failed")
|
||||
Result.error("username or password not match")
|
||||
log.info("[Auth] login failed: user={}", loginDTO.username)
|
||||
Result.error("Incorrect username or password")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,10 +54,10 @@ class AuthController(
|
||||
fun logout(
|
||||
request: HttpServletRequest
|
||||
): Result<String> {
|
||||
log.info("Logout from ${ipExtractor.getRealIp(request)}")
|
||||
log.info("UA: ${request.getHeader("User-Agent")}")
|
||||
// JWT无状态,只需返回成功让客户端自行删除token即可
|
||||
log.info("Logout success")
|
||||
log.info("[Auth] logout: ip={}", ipExtractor.getRealIp(request))
|
||||
log.debug("[Auth] user agent: {}", request.getHeader("User-Agent"))
|
||||
// JWT 无状态,登出只需客户端删除 token
|
||||
log.info("[Auth] logout success")
|
||||
return Result.success("logout successfully")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@ package com.msksbr.bookmgr.controller
|
||||
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
/*
|
||||
* 图书接口
|
||||
*/
|
||||
@RestController
|
||||
class BookController {
|
||||
}
|
||||
@@ -2,6 +2,9 @@ package com.msksbr.bookmgr.controller
|
||||
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
/*
|
||||
* 借阅接口
|
||||
*/
|
||||
@RestController
|
||||
class BorrowController {
|
||||
}
|
||||
@@ -2,6 +2,9 @@ package com.msksbr.bookmgr.controller
|
||||
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
/*
|
||||
* 仪表盘接口
|
||||
*/
|
||||
@RestController
|
||||
class DashBoardController {
|
||||
}
|
||||
@@ -2,7 +2,9 @@ package com.msksbr.bookmgr.dto
|
||||
|
||||
import jakarta.validation.constraints.NotBlank
|
||||
|
||||
|
||||
/*
|
||||
* 登录请求体
|
||||
*/
|
||||
data class UserLoginDTO(
|
||||
@NotBlank(message = "username is required")
|
||||
val username: String?,
|
||||
|
||||
@@ -4,6 +4,9 @@ import com.baomidou.mybatisplus.annotation.IdType
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
|
||||
/*
|
||||
* 图书实体,映射 book 表
|
||||
*/
|
||||
@TableName("book")
|
||||
data class Book(
|
||||
@TableId(type = IdType.AUTO)
|
||||
|
||||
@@ -5,6 +5,9 @@ import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
import java.util.Date
|
||||
|
||||
/*
|
||||
* 借阅记录实体,映射 book_record 表
|
||||
*/
|
||||
@TableName("book_record")
|
||||
data class BorrowRecord(
|
||||
@TableId(type = IdType.AUTO)
|
||||
|
||||
@@ -4,6 +4,9 @@ import com.baomidou.mybatisplus.annotation.IdType
|
||||
import com.baomidou.mybatisplus.annotation.TableId
|
||||
import com.baomidou.mybatisplus.annotation.TableName
|
||||
|
||||
/*
|
||||
* 用户实体,映射 user 表
|
||||
*/
|
||||
@TableName("user")
|
||||
data class User(
|
||||
@TableId(type = IdType.AUTO) // 设置自增主键
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package com.msksbr.bookmgr.interceptor
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
|
||||
import com.msksbr.bookmgr.config.JwtUtils
|
||||
import com.msksbr.bookmgr.template.Result
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import jakarta.servlet.http.HttpServletResponse
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.web.servlet.HandlerInterceptor
|
||||
import tools.jackson.databind.ObjectMapper
|
||||
|
||||
@Component
|
||||
class JwtAuthInterceptor(
|
||||
|
||||
@@ -4,5 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import com.msksbr.bookmgr.entity.Book
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
/*
|
||||
* 图书 Mapper,继承 MyBatis-Plus BaseMapper 获得通用 CRUD
|
||||
*/
|
||||
@Mapper
|
||||
interface BookMapper: BaseMapper<Book>
|
||||
@@ -4,5 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import com.msksbr.bookmgr.entity.BorrowRecord
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
/*
|
||||
* 借阅记录 Mapper,继承 MyBatis-Plus BaseMapper 获得通用 CRUD
|
||||
*/
|
||||
@Mapper
|
||||
interface BorrowRecordMapper: BaseMapper<BorrowRecord>
|
||||
@@ -4,5 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper
|
||||
import com.msksbr.bookmgr.entity.User
|
||||
import org.apache.ibatis.annotations.Mapper
|
||||
|
||||
/*
|
||||
* 用户 Mapper,继承 MyBatis-Plus BaseMapper 获得通用 CRUD
|
||||
*/
|
||||
@Mapper
|
||||
interface UserMapper: BaseMapper<User>
|
||||
@@ -10,21 +10,24 @@ import org.springframework.security.crypto.password.PasswordEncoder
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
|
||||
/*
|
||||
* 应用启动时初始化默认用户(admin / user01 / user02)
|
||||
* 已存在的用户会跳过,因此可安全重复执行
|
||||
*/
|
||||
@Component
|
||||
class InitUserRunner(
|
||||
val passwordEncoder: PasswordEncoder,
|
||||
val userMapper: UserMapper,
|
||||
) : ApplicationRunner {
|
||||
// 添加注解,失败时可回滚
|
||||
@Transactional
|
||||
override fun run(args: ApplicationArguments) {
|
||||
log.info("Starting default user initialization")
|
||||
log.info("[InitUser] starting")
|
||||
val existsAdmin = userMapper.selectOne(
|
||||
QueryWrapper<User>()
|
||||
.eq("username", "admin")
|
||||
)
|
||||
if (existsAdmin == null) {
|
||||
log.info("Admin user not found, creating...")
|
||||
log.info("[InitUser] admin not found, creating")
|
||||
insertAdmin()
|
||||
}
|
||||
val existsUser01 = userMapper.selectOne(
|
||||
@@ -32,7 +35,7 @@ class InitUserRunner(
|
||||
.eq("username", "user01")
|
||||
)
|
||||
if (existsUser01 == null) {
|
||||
log.info("Common user01 not found, creating...")
|
||||
log.info("[InitUser] user01 not found, creating")
|
||||
insertUser01()
|
||||
}
|
||||
val existsUser02 = userMapper.selectOne(
|
||||
@@ -40,10 +43,10 @@ class InitUserRunner(
|
||||
.eq("username", "user02")
|
||||
)
|
||||
if (existsUser02 == null) {
|
||||
log.info("Common user02 not found, creating...")
|
||||
log.info("[InitUser] user02 not found, creating")
|
||||
insertUser02()
|
||||
}
|
||||
log.info("Default user initialization completed")
|
||||
log.info("[InitUser] completed")
|
||||
}
|
||||
|
||||
fun insertAdmin() {
|
||||
@@ -75,4 +78,4 @@ class InitUserRunner(
|
||||
)
|
||||
userMapper.insert(user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
/*
|
||||
* 手动日志属性
|
||||
* SLF4J 日志扩展属性,通过 T.log 在任意类获取 Logger
|
||||
*/
|
||||
|
||||
val <T: Any> T.log: Logger
|
||||
|
||||
@@ -3,6 +3,9 @@ package com.msksbr.bookmgr.service
|
||||
import com.msksbr.bookmgr.dto.UserLoginDTO
|
||||
import com.msksbr.bookmgr.entity.User
|
||||
|
||||
/*
|
||||
* 认证服务
|
||||
*/
|
||||
interface AuthService {
|
||||
fun login(loginDTO: UserLoginDTO): User?
|
||||
}
|
||||
@@ -8,6 +8,9 @@ import com.msksbr.bookmgr.service.AuthService
|
||||
import org.springframework.security.crypto.password.PasswordEncoder
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
/*
|
||||
* 认证服务实现,含时序攻击防护
|
||||
*/
|
||||
@Service
|
||||
class AuthServiceImpl(private val userMapper: UserMapper, private val passwordEncoder: PasswordEncoder) : AuthService {
|
||||
override fun login(loginDTO: UserLoginDTO): User? {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.msksbr.bookmgr.template
|
||||
|
||||
/*
|
||||
* 统一 API 响应格式
|
||||
*/
|
||||
data class Result<T>(
|
||||
var code: Int,
|
||||
var message: String,
|
||||
|
||||
Reference in New Issue
Block a user