1. 项目概述
最近在整理技术笔记时,翻到了一个去年开发的图书商城项目,这个基于SpringBoot+Vue3+MyBatis的全栈项目让我印象深刻。作为一个完整的电商系统,它涵盖了前后端分离架构下的典型开发场景,今天就来详细拆解这个项目的技术实现。
这个系统采用现代化的技术栈组合:后端使用SpringBoot 2.7提供RESTful API服务,前端采用Vue3+Element Plus构建响应式界面,数据持久层使用MyBatis-Plus简化数据库操作,MySQL 8.0作为主数据库,配合Redis实现缓存和会话管理。系统实现了完整的电商业务流程,包括用户认证、商品展示、购物车管理、订单处理等核心功能模块。
2. 技术架构解析
2.1 前后端分离设计
前后端分离架构是本项目的核心设计理念。与传统单体应用不同,我们将前端和后端完全解耦:
- 后端:纯API服务,不涉及任何视图渲染
- 前端:独立SPA应用,通过HTTP API与后端交互
- 接口规范:遵循RESTful设计原则
这种架构的优势在于:
- 开发效率提升:前后端可以并行开发
- 可维护性强:模块边界清晰
- 扩展性好:可以单独扩展前端或后端服务
2.2 后端技术栈
后端采用SpringBoot作为基础框架,主要技术组件包括:
- Web层:Spring MVC + RESTful API
- 安全认证:Spring Security + JWT
- ORM框架:MyBatis-Plus 3.5
- 数据库:MySQL 8.0
- 缓存:Redis 6.x
- 其他工具:Lombok、Hutool、MapStruct
提示:MyBatis-Plus相比原生MyBatis提供了更多开箱即用的功能,如自动分页、条件构造器等,可以显著减少样板代码。
2.3 前端技术栈
前端采用Vue3组合式API开发,主要技术选型:
- 核心框架:Vue 3.2
- UI组件库:Element Plus
- 状态管理:Pinia
- 路由:Vue Router 4
- HTTP客户端:Axios
- 构建工具:Vite
Vue3的Composition API让代码组织更加灵活,配合Vite的快速构建,开发体验非常流畅。
3. 数据库设计
3.1 核心表结构
系统主要包含以下几张核心表:
用户表(user)
sql复制CREATE TABLE `user` (
`user_id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password_hash` varchar(100) NOT NULL,
`email` varchar(100) DEFAULT NULL,
`phone` varchar(20) DEFAULT NULL,
`register_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_login` datetime DEFAULT NULL,
`is_admin` tinyint(1) DEFAULT '0',
PRIMARY KEY (`user_id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
图书表(book)
sql复制CREATE TABLE `book` (
`book_id` bigint NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL,
`author` varchar(50) NOT NULL,
`publisher` varchar(50) DEFAULT NULL,
`publish_date` date DEFAULT NULL,
`price` decimal(10,2) NOT NULL,
`stock` int NOT NULL DEFAULT '0',
`category_id` bigint DEFAULT NULL,
`cover_url` varchar(200) DEFAULT NULL,
`shelf_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`book_id`),
KEY `idx_category` (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
订单表(order)
sql复制CREATE TABLE `order` (
`order_id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`total_amount` decimal(10,2) NOT NULL,
`status` tinyint(1) NOT NULL DEFAULT '0',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`pay_time` datetime DEFAULT NULL,
`receiver_name` varchar(50) NOT NULL,
`receiver_phone` varchar(20) NOT NULL,
`address` varchar(200) NOT NULL,
PRIMARY KEY (`order_id`),
KEY `idx_user` (`user_id`),
KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 索引设计优化
为提高查询性能,我们在关键字段上建立了索引:
- 用户表的username字段:用于登录和用户查询
- 图书表的category_id字段:用于分类检索
- 订单表的user_id和create_time字段:用于用户订单查询
注意:索引不是越多越好,需要根据实际查询场景合理设计。过多的索引会影响写入性能。
4. 核心功能实现
4.1 用户认证模块
采用JWT(JSON Web Token)实现无状态认证:
-
登录流程:
- 客户端提交用户名密码
- 服务端验证通过后生成JWT
- 返回JWT给客户端存储
- 后续请求携带JWT进行认证
-
安全措施:
- 密码使用BCrypt加密存储
- JWT设置合理过期时间(如2小时)
- 敏感操作需要二次验证
关键代码示例(JWT工具类):
java复制public class JwtUtil {
private static final String SECRET_KEY = "your-secret-key";
private static final long EXPIRATION_TIME = 7200000; // 2小时
public static String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public static boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
// 其他工具方法...
}
4.2 图书展示与搜索
实现功能:
- 分页查询
- 分类筛选
- 关键词搜索
- 排序功能
后端API示例:
java复制@GetMapping("/books")
public PageResult<BookVO> getBooks(
@RequestParam(required = false) String keyword,
@RequestParam(required = false) Long categoryId,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(defaultValue = "shelf_time") String sort) {
QueryWrapper<Book> wrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(keyword)) {
wrapper.like("title", keyword).or().like("author", keyword);
}
if (categoryId != null) {
wrapper.eq("category_id", categoryId);
}
wrapper.orderByDesc(sort);
Page<Book> bookPage = bookService.page(new Page<>(page, size), wrapper);
return PageResult.success(bookPage.convert(this::convertToVO));
}
4.3 购物车与订单系统
购物车设计考虑:
- 未登录用户:使用浏览器本地存储
- 已登录用户:持久化到数据库
订单状态机设计:
java复制public enum OrderStatus {
UNPAID(0, "待支付"),
PAID(1, "已支付"),
SHIPPED(2, "已发货"),
COMPLETED(3, "已完成"),
CANCELLED(4, "已取消");
// 状态转换校验逻辑
public static boolean canChangeTo(OrderStatus from, OrderStatus to) {
switch (from) {
case UNPAID: return to == PAID || to == CANCELLED;
case PAID: return to == SHIPPED || to == CANCELLED;
case SHIPPED: return to == COMPLETED;
default: return false;
}
}
}
5. 性能优化实践
5.1 缓存策略
- 图书详情缓存:使用Redis缓存热门图书信息
- 分类数据缓存:减少重复查询
- 购物车数据:混合使用本地存储和Redis
缓存更新策略:
- 读多写少:缓存失效后更新
- 关键数据:主动更新缓存
5.2 数据库优化
- 合理使用索引
- 查询优化:避免SELECT *,使用分页
- 批量操作:减少数据库往返
5.3 前端性能优化
- 代码分割:按需加载
- 图片懒加载
- API请求合并
- 本地缓存利用
6. 部署方案
6.1 开发环境
- 后端:SpringBoot内嵌Tomcat
- 前端:Vite开发服务器
- 数据库:Docker运行MySQL和Redis
6.2 生产环境
推荐部署架构:
code复制前端静态资源 → Nginx
↓
API请求 → SpringBoot应用集群
↓
MySQL主从
↓
Redis集群
部署步骤:
- 前端构建:
npm run build - 后端打包:
mvn clean package - 配置Nginx反向代理
- 数据库初始化
7. 常见问题与解决方案
7.1 跨域问题
解决方案:
- 后端配置CORS
- Nginx反向代理
- 开发环境配置代理
SpringBoot CORS配置示例:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
}
7.2 接口版本管理
随着业务发展,API可能需要变更。我们采用以下策略:
- URL路径版本化:
/api/v1/books - 请求头版本控制
- 文档及时更新
7.3 数据一致性
分布式环境下保证数据一致性的方法:
- 本地事务:简单场景
- 分布式事务:复杂场景(如Seata)
- 最终一致性:消息队列+重试机制
8. 项目扩展方向
这个基础项目还可以进一步扩展:
- 支付系统集成:对接支付宝/微信支付
- 推荐系统:基于用户行为的图书推荐
- 评论系统:用户评价与互动
- 数据分析:销售统计与报表
- 微服务化:按业务拆分服务
实际开发中发现,良好的项目结构和规范的代码风格对后期维护非常重要。建议从一开始就注重:
- 统一的异常处理
- 规范的API响应格式
- 清晰的包结构划分
- 完善的日志记录
- 自动化测试覆盖