refactor(admin-borrows): simplify returnBook to use recordId instead of bookId and userId
- Change returnBook signature to accept recordId only, reducing coupling - Improve Javadoc comments across controller, service, and implementation - Clean up imports and reformat class structure in impl Closes: #125
This commit is contained in:
@@ -6,10 +6,7 @@ import com.msksbr.bookmgr.script.log
|
|||||||
import com.msksbr.bookmgr.service.AdminBorrowService
|
import com.msksbr.bookmgr.service.AdminBorrowService
|
||||||
import com.msksbr.bookmgr.template.Result
|
import com.msksbr.bookmgr.template.Result
|
||||||
import jakarta.servlet.http.HttpServletRequest
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.*
|
||||||
import org.springframework.web.bind.annotation.RequestAttribute
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping
|
|
||||||
import org.springframework.web.bind.annotation.RestController
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 借阅管理接口(面向管理员)
|
* 借阅管理接口(面向管理员)
|
||||||
@@ -76,4 +73,37 @@ class AdminBorrowController(
|
|||||||
log.info("[AdminBorrow] user agent: {}", request.getHeader("User-Agent"))
|
log.info("[AdminBorrow] user agent: {}", request.getHeader("User-Agent"))
|
||||||
return adminBorrowService.getAllBorrows()
|
return adminBorrowService.getAllBorrows()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* POST /api/admin/borrows/borrowbook?bookId=xxx&userId=xxx
|
||||||
|
* 管理员手动借书
|
||||||
|
*/
|
||||||
|
@RequireRole("admin")
|
||||||
|
@PostMapping("/borrowbook")
|
||||||
|
fun borrowBook(
|
||||||
|
@RequestAttribute(required = false) username: String?,
|
||||||
|
bookId: Long,
|
||||||
|
userId: Long,
|
||||||
|
request: HttpServletRequest
|
||||||
|
): Result<Any?> {
|
||||||
|
log.info("[AdminBorrow] borrowBook: user={}, bookId={}, userId={}", username ?: "guest", bookId, userId)
|
||||||
|
log.info("[AdminBorrow] user agent: {}, ip={}", request.getHeader("User-Agent"), ipExtractor.getRealIp(request))
|
||||||
|
return adminBorrowService.borrowBook(bookId, userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* POST /api/admin/borrows/returnbook?recordId=xxx
|
||||||
|
* 管理员手动还书
|
||||||
|
*/
|
||||||
|
@RequireRole("admin")
|
||||||
|
@PostMapping("/returnbook")
|
||||||
|
fun returnBook(
|
||||||
|
@RequestAttribute(required = false) username: String?,
|
||||||
|
recordId: Long,
|
||||||
|
request: HttpServletRequest
|
||||||
|
): Result<Any?> {
|
||||||
|
log.info("[AdminBorrow] returnBook: user={}, recordId={}", username ?: "guest", recordId)
|
||||||
|
log.info("[AdminBorrow] user agent: {}, ip={}", request.getHeader("User-Agent"), ipExtractor.getRealIp(request))
|
||||||
|
return adminBorrowService.returnBook(recordId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,9 +37,8 @@ interface AdminBorrowService {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 管理员手动还书
|
* 管理员手动还书
|
||||||
* @param bookId 要还的图书 ID
|
* @param recordId 借阅记录 ID
|
||||||
* @param userId 还书的用户 ID
|
|
||||||
* @return 归还结果
|
* @return 归还结果
|
||||||
*/
|
*/
|
||||||
fun returnBook(bookId: Long, userId: Long): Result<Any?>
|
fun returnBook(recordId: Long): Result<Any?>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import kotlinx.coroutines.async
|
|||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 借阅管理服务实现
|
* 借阅管理服务实现
|
||||||
@@ -131,14 +132,83 @@ class AdminBorrowServiceImpl(
|
|||||||
* 管理员手动借书
|
* 管理员手动借书
|
||||||
*/
|
*/
|
||||||
override fun borrowBook(bookId: Long, userId: Long): Result<Any?> {
|
override fun borrowBook(bookId: Long, userId: Long): Result<Any?> {
|
||||||
TODO("Not yet implemented")
|
val (matchedUser, matchedBook) = runBlocking {
|
||||||
|
val userDeferred = async(Dispatchers.IO) {
|
||||||
|
userMapper.selectById(userId)
|
||||||
|
}
|
||||||
|
val bookDeferred = async(Dispatchers.IO) {
|
||||||
|
bookMapper.selectById(bookId)
|
||||||
|
}
|
||||||
|
userDeferred.await() to bookDeferred.await()
|
||||||
|
}
|
||||||
|
if (matchedUser == null) {
|
||||||
|
log.warn("[AdminBorrow] borrowBook: user not found, userId={}", userId)
|
||||||
|
return Result.error("User does not exist")
|
||||||
|
}
|
||||||
|
if (matchedBook == null) {
|
||||||
|
log.warn("[AdminBorrow] borrowBook: book not found, bookId={}", bookId)
|
||||||
|
return Result.error("Book does not exist")
|
||||||
|
}
|
||||||
|
if (matchedBook.stock < 1) {
|
||||||
|
log.warn("[AdminBorrow] borrowBook: book out of stock, bookId={}, stock={}", bookId, matchedBook.stock)
|
||||||
|
return Result.conflict("Book is out of stock")
|
||||||
|
}
|
||||||
|
val book = Book(
|
||||||
|
id = matchedBook.id,
|
||||||
|
name = matchedBook.name,
|
||||||
|
author = matchedBook.author,
|
||||||
|
stock = matchedBook.stock - 1,
|
||||||
|
)
|
||||||
|
val borrow = BorrowRecord(
|
||||||
|
id = null,
|
||||||
|
userId = userId,
|
||||||
|
bookId = bookId,
|
||||||
|
borrowTime = Date(),
|
||||||
|
returnTime = null,
|
||||||
|
status = "BORROWED"
|
||||||
|
)
|
||||||
|
bookMapper.updateById(book)
|
||||||
|
borrowRecordMapper.insert(borrow)
|
||||||
|
log.info("[AdminBorrow] borrowBook: success, userId={}, bookId={}, book={}", userId, bookId, matchedBook.name)
|
||||||
|
return Result.success("Book borrowed successfully")
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 管理员手动还书
|
* 管理员手动还书
|
||||||
*/
|
*/
|
||||||
override fun returnBook(bookId: Long, userId: Long): Result<Any?> {
|
override fun returnBook(recordId: Long): Result<Any?> {
|
||||||
TODO("Not yet implemented")
|
val matchedBorrow = borrowRecordMapper.selectById(recordId)
|
||||||
|
if (matchedBorrow == null) {
|
||||||
|
log.warn("[AdminBorrow] returnBook: record not found, recordId={}", recordId)
|
||||||
|
return Result.error("Borrow record does not exist")
|
||||||
|
}
|
||||||
|
if (matchedBorrow.status == "RETURNED") {
|
||||||
|
log.warn("[AdminBorrow] returnBook: already returned, recordId={}", recordId)
|
||||||
|
return Result.conflict("Book has already been returned")
|
||||||
|
}
|
||||||
|
val borrow = BorrowRecord(
|
||||||
|
id = matchedBorrow.id,
|
||||||
|
bookId = matchedBorrow.bookId,
|
||||||
|
userId = matchedBorrow.userId,
|
||||||
|
borrowTime = matchedBorrow.borrowTime,
|
||||||
|
returnTime = Date(),
|
||||||
|
status = "RETURNED"
|
||||||
|
)
|
||||||
|
val matchedBook = bookMapper.selectById(matchedBorrow.bookId)
|
||||||
|
if (matchedBook == null) {
|
||||||
|
log.warn("[AdminBorrow] returnBook: book not found, bookId={}", matchedBorrow.bookId)
|
||||||
|
return Result.error("Book does not exist")
|
||||||
|
}
|
||||||
|
val book = Book(
|
||||||
|
id = matchedBook.id,
|
||||||
|
name = matchedBook.name,
|
||||||
|
author = matchedBook.author,
|
||||||
|
stock = matchedBook.stock + 1,
|
||||||
|
)
|
||||||
|
bookMapper.updateById(book)
|
||||||
|
borrowRecordMapper.updateById(borrow)
|
||||||
|
log.info("[AdminBorrow] returnBook: success, recordId={}, userId={}, book={}", recordId, borrow.userId, matchedBook.name)
|
||||||
|
return Result.success("Book returned successfully")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 并发查询用户和图书信息,组装为 BorrowInfoVo 列表
|
// 并发查询用户和图书信息,组装为 BorrowInfoVo 列表
|
||||||
|
|||||||
Reference in New Issue
Block a user