跳到主要内容
基于 AI 辅助开发的在线图书借阅平台实践指南:从 0 到 1 | 极客日志
Java AI java 算法
基于 AI 辅助开发的在线图书借阅平台实践指南:从 0 到 1 在线图书借阅平台采用 Java 微服务架构,结合 AI 辅助开发工具实现从需求分析到代码生成的全流程自动化。系统涵盖用户服务、资源管理、业务处理及数据分析层,集成 Elasticsearch 检索与 Redis 缓存。针对 SQL 慢查询添加复合索引并重构语句,利用乐观锁解决并发超卖问题,通过分布式缓存应对高并发挑战。实践表明 AI 工具能显著提升核心业务代码开发效率,降低缺陷密度,但仍需人工补充复杂业务规则与 UI 设计细节。
晚风叙旧 发布于 2026/3/29 更新于 2026/4/23 1 浏览免责声明:此文章的所有内容皆是本人实验测评,并非广告推广,并非抄袭。如有侵权,请联系,谢谢!
一、需求分析与规划
我们可以直接在 AI 智能开发工具里面自带的智能会话功能,进行项目所需的需求分析和规划。
下面是智能会话的使用场景。
1.1、功能需求
在线图书借阅平台需满足用户全流程借阅需求,包含图书检索、借阅预约、逾期管理、信用积分体系四大核心功能。系统需支持多校区图书资源调配,实现"线上借书 + 书店借书 + 数字阅读"三位一体服务模式,并集成智能推荐算法提升用户粘性。
1.2、核心模块
用户服务层 :集成支付宝、微信等多端入口,支持读者信用积分动态计算
资源管理层 :构建 Elasticsearch 全文检索集群,实现图书元数据与内容片段的混合检索
业务处理层 :采用乐观锁机制处理并发借阅,通过 Redis 缓存热点图书状态
数据分析层 :基于 Flink 实时计算图书热度指数,驱动智能推荐系统
1.3、技术选型
后端架构 :Spring Cloud Alibaba 微服务框架
AI 开发工具 :AI 智能开发平台
数据库 :MySQL 8.0(主)+ TiDB(分布式扩展)
搜索引擎 :Elasticsearch 7.15
缓存系统 :Redis 6.2 集群
二、AI 辅助开发实录
因为是从 0 开始开发这个项目,没有关联旧项目,直接选择创建一个新的项目。
接着,复制粘贴之前在智能会话中生成的需求分析和规划,直接开始生成。
下面会有 5 个细分的步骤:理解需求、设计接口、表结构设计、处理逻辑(接口),最后是生成源码。其中前面 4 个都是我们可以人为去修改需求和接口的,以求最终生成的项目更加符合预期。
下面是整体的一个流程:
开始生成代码,21:23 开始,最终 21:39 结束。
每一个子文件生成的时间大概是 2min,最终完整生成代码时间是 15min 左右,速度还是可以的。
三、优化与调试心得
3.1、SQL 性能优化:精准打击,提升查询效率 在平台初期,图书搜索接口响应缓慢成为突出问题。经过深入分析,发现是由于查询语句效率低下以及缺乏合适的索引导致。为此,我们采取了以下优化措施:
添加复合索引 :针对图书名称、作者等常用查询字段,添加复合索引,大大减少了数据库的扫描范围,提高了查询速度。
重构查询语句 :将原本使用子查询的方式改为 JOIN 操作,避免了子查询带来的性能损耗,使查询更加高效。
结果集分页处理 :对于可能返回大量数据的查询,实施分页处理,避免一次性加载过多数据,减轻了数据库和服务器的负担。
在处理百万级借阅记录统计时,初始 SQL 执行耗时长达 12.3 秒。通过 AI 工具的「SQL 优化建议」功能,我们识别出全表扫描和冗余计算问题。为 borrow_record 表添加 (reader_id, borrow_date) 复合索引,解决了全表扫描问题;将子查询改写为物化视图,避免了冗余计算。优化后查询耗时降至 0.8 秒,性能提升显著。
SELECT reader_id, COUNT (* ) as borrow_count FROM borrow_record WHERE borrow_date BETWEEN '2025-01-01' AND '2025-08-01' GROUP BY reader_id HAVING COUNT (* ) > 5 ;
CREATE MATERIALIZED VIEW mv_reader_borrow_stats AS SELECT reader_id, COUNT (* ) as total_count, SUM (CASE WHEN status = 'OVERDUE' THEN 1 ELSE 0 END ) as overdue_count FROM borrow_record GROUP BY reader_id;
SELECT * FROM mv_reader_borrow_stats WHERE total_count > 5 ORDER BY overdue_count DESC ;
3.2、并发控制:乐观锁机制,解决超卖难题 借阅系统中,并发请求导致超卖现象频发,严重影响了系统的准确性和稳定性。为解决这一问题,我们引入了乐观锁机制。通过在实体类中添加 @Version 注解,记录数据的版本号。在并发更新时,系统会检查版本号是否一致,若不一致则说明数据已被其他事务修改,当前事务将回滚,从而避免了超卖问题的发生。
@Version
private Integer version;
3.3、缓存策略调整:从本地到分布式,应对高并发挑战 最初,平台采用简单的本地缓存,但在高并发场景下,出现了内存溢出的问题。为解决这一问题,我们对缓存策略进行了全面调整:
改用 Redis 分布式缓存 :将缓存数据存储在 Redis 中,利用 Redis 的高性能和分布式特性,提高了缓存的并发处理能力。
设置合理的过期时间和淘汰策略 :根据数据的访问频率和重要性,设置不同的过期时间,并采用 LRU 等淘汰策略,确保缓存空间的有效利用。
对高频访问的数据进行预热 :在系统启动时,将高频访问的数据提前加载到缓存中,减少缓存击穿的可能性。
四、成果展示与总结
工程结构图
核心 API 列表 API 名称 方法 路径 功能描述 图书检索 GET /api/books/search 支持全文检索与条件筛选 预约借阅 POST /api/borrow/reserve 处理图书预约请求 信用积分查询 GET /api/reader/credit 返回读者信用积分明细 智能推荐 GET /api/recommend/books 基于借阅历史的个性化推荐 跨校区调拨申请 POST /api/transfer/apply 提交图书跨校区调配请求
核心代码的实现: package com.library.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Slf4j
public class PasswordUtil {
private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder ();
public static String hashPassword (String rawPassword) {
log.debug("正在对密码进行加密处理..." );
return encoder.encode(rawPassword);
}
public static boolean verifyPassword (String rawPassword, String encodedPassword) {
log.debug("正在进行密码验证..." );
return encoder.matches(rawPassword, encodedPassword);
}
}
package com.library.service.impl;
import com.library.dto.AddBookInventoryDTO;
import com.library.dto.QueryBookInventoryDTO;
import com.library.dto.UpdateBookInventoryDTO;
import com.library.entity.BookInventory;
import com.library.exception.BusinessException;
import com.library.repository.BookInventoryRepository;
import com.library.service.BookInventoryService;
import com.library.util.RestResult;
import com.library.vo.BookInventoryVO;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Slf4j
@Service
@Transactional
public class BookInventoryServiceImpl implements BookInventoryService {
@Autowired
private BookInventoryRepository repository;
@Override
public RestResult<?> addBookInventory(AddBookInventoryDTO dto) {
log.info("新增图书库存请求参数:{}" , dto);
Optional<BookInventory> existingRecord = repository.findByBookId(dto.getBookId());
if (existingRecord.isPresent()) {
return RestResult.fail("000001" , "该图书库存记录已存在" );
}
try {
BookInventory entity = new BookInventory ();
BeanUtils.copyProperties(dto, entity);
entity.setCreateTime(LocalDateTime.now());
entity.setUpdateTime(LocalDateTime.now());
repository.save(entity);
log.info("成功新增图书库存记录,ID={}" , entity.getInventoryId());
return RestResult.success(entity);
} catch (Exception e) {
log.error("新增图书库存失败" , e);
throw new BusinessException ("新增图书库存失败" , e);
}
}
@Override
public RestResult<?> updateBookInventory(UpdateBookInventoryDTO dto) {
log.info("修改图书库存请求参数:{}" , dto);
Optional<BookInventory> optionalEntity = repository.findById(dto.getInventoryId());
if (!optionalEntity.isPresent()) {
return RestResult.fail("000001" , "库存记录不存在" );
}
try {
BookInventory entity = optionalEntity.get();
if (dto.getTotalQuantity() != null ) {
entity.setTotalQuantity(dto.getTotalQuantity());
}
if (dto.getAvailableQuantity() != null ) {
entity.setAvailableQuantity(dto.getAvailableQuantity());
}
if (dto.getBorrowedQuantity() != null ) {
entity.setBorrowedQuantity(dto.getBorrowedQuantity());
}
if (dto.getWarningThreshold() != null ) {
entity.setWarningThreshold(dto.getWarningThreshold());
}
entity.setUpdateTime(LocalDateTime.now());
repository.save(entity);
log.info("成功修改图书库存记录,ID={}" , entity.getInventoryId());
return RestResult.success(entity);
} catch (Exception e) {
log.error("修改图书库存失败" , e);
throw new BusinessException ("修改图书库存失败" , e);
}
}
@Override
public RestResult<?> deleteBookInventory(Long inventoryId) {
log.info("删除图书库存参数:inventoryId={}" , inventoryId);
Optional<BookInventory> optionalEntity = repository.findById(inventoryId);
if (!optionalEntity.isPresent()) {
return RestResult.fail("000001" , "库存记录不存在" );
}
try {
repository.deleteById(inventoryId);
log.info("成功删除图书库存记录,ID={}" , inventoryId);
return RestResult.success();
} catch (Exception e) {
log.error("删除图书库存失败" , e);
throw new BusinessException ("删除图书库存失败" , e);
}
}
@Override
public RestResult<?> queryBookInventoryDetail(QueryBookInventoryDTO dto) {
log.info("查询图书库存详情请求参数:{}" , dto);
Optional<BookInventory> optionalEntity = repository.findByBookId(dto.getBookId());
if (!optionalEntity.isPresent()) {
return RestResult.fail("000001" , "未找到该图书的库存信息" );
}
try {
BookInventory entity = optionalEntity.get();
BookInventoryVO vo = new BookInventoryVO ();
BeanUtils.copyProperties(entity, vo);
log.info("成功查询图书库存详情,ID={}" , entity.getInventoryId());
return RestResult.success(vo);
} catch (Exception e) {
log.error("查询图书库存详情失败" , e);
throw new BusinessException ("查询图书库存详情失败" , e);
}
}
@Override
public RestResult<List<BookInventoryVO>> getAllBookInventoryList () {
log.info("获取所有图书库存列表" );
try {
List<BookInventory> entities = repository.findAll();
List<BookInventoryVO> vos = new ArrayList <>();
for (BookInventory entity : entities) {
BookInventoryVO vo = new BookInventoryVO ();
BeanUtils.copyProperties(entity, vo);
vos.add(vo);
}
log.info("成功获取所有图书库存列表,共{}条记录" , vos.size());
return RestResult.success(vos);
} catch (Exception e) {
log.error("获取所有图书库存列表失败" , e);
throw new BusinessException ("获取所有图书库存列表失败" , e);
}
}
}
package com.library.service.impl;
import com.library.dto.RecommendBookDTO;
import com.library.dto.SearchBookDTO;
import com.library.entity.BookCategory;
import com.library.entity.BookInfo;
import com.library.entity.BookTag;
import com.library.exception.BusinessException;
import com.library.repository.BookCategoryRepository;
import com.library.repository.BookInfoRepository;
import com.library.repository.BookTagRepository;
import com.library.service.BookBrowseService;
import com.library.util.RestResult;
import com.library.vo.BookDetailVO;
import com.library.vo.BookListVO;
import com.library.vo.CategoryListVO;
import com.library.vo.TagListVO;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class BookBrowseServiceImpl implements BookBrowseService {
private final BookInfoRepository bookInfoRepository;
private final BookCategoryRepository bookCategoryRepository;
private final BookTagRepository bookTagRepository;
@Override
public RestResult<List<BookListVO>> searchBooks (SearchBookDTO searchBookDTO) {
log.info("开始执行图书搜索操作,参数为:{}" , searchBookDTO);
try {
Pageable pageable = PageRequest.of(0 , 100 );
List<BookInfo> books = bookInfoRepository.searchBooks(
searchBookDTO.getTitle(),
searchBookDTO.getAuthor(),
searchBookDTO.getCategoryId(),
pageable
);
if (books == null || books.isEmpty()) {
return RestResult.fail("无匹配结果" );
}
List<BookListVO> result = new ArrayList <>();
for (BookInfo book : books) {
BookListVO vo = new BookListVO ();
BeanUtils.copyProperties(book, vo);
result.add(vo);
}
return RestResult.success(result);
} catch (Exception e) {
log.error("图书搜索异常" , e);
throw new BusinessException ("系统内部错误" );
}
}
@Override
public RestResult<BookDetailVO> getBookDetails (Long bookId) {
log.info("开始获取图书详情,图书 ID 为:{}" , bookId);
Optional<BookInfo> optionalBook = bookInfoRepository.findById(bookId);
if (!optionalBook.isPresent()) {
return RestResult.fail("图书不存在" );
}
BookInfo book = optionalBook.get();
BookDetailVO detailVo = new BookDetailVO ();
BeanUtils.copyProperties(book, detailVo);
return RestResult.success(detailVo);
}
@Override
public RestResult<List<CategoryListVO>> getCategoryList () {
log.info("开始获取图书分类列表" );
try {
List<BookCategory> categories = bookCategoryRepository.findAll();
List<CategoryListVO> result = new ArrayList <>();
for (BookCategory category : categories) {
CategoryListVO vo = new CategoryListVO ();
BeanUtils.copyProperties(category, vo);
result.add(vo);
}
return RestResult.success(result);
} catch (Exception e) {
log.error("获取分类列表失败" , e);
throw new BusinessException ("系统内部错误" );
}
}
@Override
public RestResult<List<TagListVO>> getTagList () {
log.info("开始获取图书标签列表" );
try {
List<BookTag> tags = bookTagRepository.findAll();
List<TagListVO> result = new ArrayList <>();
for (BookTag tag : tags) {
TagListVO vo = new TagListVO ();
BeanUtils.copyProperties(tag, vo);
result.add(vo);
}
return RestResult.success(result);
} catch (Exception e) {
log.error("获取标签列表失败" , e);
throw new BusinessException ("系统内部错误" );
}
}
@Override
public RestResult<List<BookListVO>> getRecommendedBooks (RecommendBookDTO recommendBookDTO) {
log.info("开始获取推荐图书列表,用户 ID 为:{}" , recommendBookDTO.getUserId());
try {
Pageable pageable = PageRequest.of(0 , 20 );
List<BookInfo> books = bookInfoRepository.findAll(pageable);
List<BookListVO> result = new ArrayList <>();
for (BookInfo book : books) {
BookListVO vo = new BookListVO ();
BeanUtils.copyProperties(book, vo);
result.add(vo);
}
return RestResult.success(result);
} catch (Exception e) {
log.error("获取推荐图书列表失败" , e);
throw new BusinessException ("系统内部错误" );
}
}
}
AI 辅助开发优势总结
开发效率提升 :核心业务代码开发时间缩短 70%,特别在事务控制、并发处理等复杂逻辑实现上表现突出
质量保障体系 :自动生成的代码通过 SonarQube 静态检查,缺陷密度降低至 0.3 个/KLOC
知识沉淀机制 :平台内置的 300+ 最佳实践模板,有效避免常见设计缺陷
待改进方向
复杂业务理解 :在处理"书店借书图书馆买单"等创新业务模式时,需人工补充业务规则说明
多技术栈支持 :当前对非 Java 技术栈(如 Go、Python)的集成支持有限
UI/UX 设计 :前端界面生成功能尚在完善阶段,需结合专业设计工具使用
智能会话格式处理 :在复制粘贴智能会话生成的内容时,不会自带格式,而市面上的其他主流 AI 模型通常会自带分层
开发体会 通过本次实践深刻认识到,AI 开发工具已从"代码生成器"进化为"业务理解伙伴"。在实现图书预约排队机制时,AI 不仅生成了基础代码,还主动提示需要考虑"读者优先级策略"和"校区库存均衡"等业务深层次问题。这种从技术实现到业务理解的跨越,标志着开发工具进入智能协同新阶段。建议开发者在使用时保持"人机协作"思维,充分发挥 AI 在重复性工作处理和知识检索方面的优势,同时保留人类在业务创新和复杂决策上的主导地位。
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online