1. 项目概述:在线家具商城的技术架构解析
这个基于SpringBoot+Vue3+MyBatis的在线家具商城项目,采用前后端分离架构,MySQL作为核心数据库,是一个典型的电商类应用开发案例。作为全栈开发者,我在实际开发中发现这种技术组合特别适合中小型电商平台的快速搭建。
项目前端使用Vue3组合式API开发,后端采用SpringBoot框架,通过RESTful API进行数据交互。MyBatis作为ORM框架处理数据库操作,MySQL存储商品、订单等核心业务数据。这种架构既保证了开发效率,又能满足电商系统对性能和数据一致性的要求。
2. 技术栈选型与核心组件分析
2.1 后端技术栈:SpringBoot的优势与应用
SpringBoot作为后端框架的选择主要基于以下几点考虑:
- 自动配置特性大幅减少了XML配置
- 内嵌Tomcat服务器简化了部署流程
- 丰富的Starter依赖可以快速集成各种功能模块
- 完善的生态圈和社区支持
在实际开发中,我们特别使用了:
@SpringBootApplication public class FurnitureStoreApplication { public static void main(String[] args) { SpringApplication.run(FurnitureStoreApplication.class, args); } }这个启动类配置简单但功能强大,通过@SpringBootApplication注解就完成了自动配置、组件扫描等核心功能。
2.2 前端技术栈:Vue3的特性实践
Vue3相比Vue2在性能上有显著提升,特别适合电商类应用:
- Composition API使代码组织更灵活
- 更小的打包体积
- 更好的TypeScript支持
- 更高效的响应式系统
在商品列表组件中,我们这样使用setup语法:
<script setup> import { ref, computed } from 'vue' const products = ref([]) const filteredProducts = computed(() => { return products.value.filter(p => p.stock > 0) }) </script>2.3 数据持久层:MyBatis的灵活运用
MyBatis作为ORM框架,在电商系统中处理复杂查询特别有优势。我们主要使用:
- 动态SQL处理多条件商品查询
- 结果映射将数据库字段转换为对象属性
- 缓存机制提升查询性能
一个典型的商品查询Mapper示例:
<select id="selectProductsByCondition" resultMap="productResultMap"> SELECT * FROM product <where> <if test="categoryId != null"> AND category_id = #{categoryId} </if> <if test="minPrice != null"> AND price >= #{minPrice} </if> </where> ORDER BY ${orderBy} ${orderDirection} </select>2.4 数据库设计:MySQL表结构优化
家具商城的主要表结构设计要点:
- 商品表:考虑多规格、多图片存储
- 用户表:安全存储密码等敏感信息
- 订单表:处理状态流转和事务一致性
- 评价表:关联用户和商品
核心商品表DDL示例:
CREATE TABLE `product` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `description` text, `price` decimal(10,2) NOT NULL, `stock` int NOT NULL DEFAULT '0', `category_id` bigint NOT NULL, `main_image` varchar(255), `status` tinyint NOT NULL DEFAULT '1', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_category` (`category_id`), KEY `idx_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;3. 核心功能模块实现
3.1 用户认证与授权系统
采用JWT实现无状态认证:
- 用户登录成功后生成Token
- Token包含用户基本信息和权限
- 前端存储Token并在每次请求携带
- 后端验证Token有效性
Spring Security配置核心代码:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/api/auth/**").permitAll() .anyRequest().authenticated() .and() .addFilter(new JwtAuthenticationFilter(authenticationManager())) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); return http.build(); } }3.2 商品管理与展示系统
商品系统关键功能点:
- 多条件分页查询
- 商品详情页
- 商品分类管理
- 商品评价展示
前端商品列表分页查询实现:
const fetchProducts = async (page = 1, size = 10) => { const res = await axios.get('/api/products', { params: { page, size } }) products.value = res.data.items total.value = res.data.total }3.3 购物车与订单系统
购物车设计考虑:
- 未登录用户使用本地存储
- 已登录用户同步到服务端
- 合并本地和服务端购物车
订单创建流程:
- 验证商品库存
- 计算总价
- 创建订单主表
- 创建订单明细
- 扣减库存
- 清理购物车
订单服务核心代码:
@Transactional public Order createOrder(Long userId, OrderCreateDTO dto) { // 验证库存 List<CartItem> cartItems = cartService.getCheckedItems(userId); checkStock(cartItems); // 创建订单 Order order = new Order(); order.setUserId(userId); order.setTotalAmount(calculateTotal(cartItems)); orderMapper.insert(order); // 创建订单项 createOrderItems(order.getId(), cartItems); // 扣减库存 reduceStock(cartItems); // 清空购物车 cartService.clearCheckedItems(userId); return order; }4. 前后端分离架构实践
4.1 API接口设计规范
采用RESTful风格设计原则:
- 资源使用名词复数形式
- HTTP方法表示操作类型
- 状态码准确反映结果
- 统一响应格式
通用响应格式示例:
{ "code": 200, "message": "success", "data": { "items": [], "total": 0 }, "timestamp": 1630000000000 }4.2 跨域问题解决方案
前端代理配置(vue.config.js):
module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, pathRewrite: { '^/api': '' } } } } }后端CORS配置:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") .maxAge(3600); } }4.3 前端路由与权限控制
基于Vue Router的权限控制方案:
- 定义路由元信息requireAuth
- 全局前置守卫检查登录状态
- 动态路由加载用户权限
路由配置示例:
const routes = [ { path: '/user', component: UserCenter, meta: { requireAuth: true } }, { path: '/admin', component: AdminPanel, meta: { requireAuth: true, roles: ['ADMIN'] } } ] router.beforeEach((to, from, next) => { if (to.meta.requireAuth && !store.state.user.token) { next('/login') } else { next() } })5. 性能优化与安全实践
5.1 数据库查询优化技巧
MyBatis性能优化手段:
- 合理使用二级缓存
- 批量操作代替循环单条操作
- 延迟加载关联对象
- 使用索引提示
批量插入示例:
<insert id="batchInsert" parameterType="java.util.List"> INSERT INTO product_sku (product_id, sku_code, price, stock) VALUES <foreach collection="list" item="item" separator=","> (#{item.productId}, #{item.skuCode}, #{item.price}, #{item.stock}) </foreach> </insert>5.2 接口性能监控与优化
Spring Boot Actuator集成:
- 添加依赖
- 配置端点暴露
- 使用Prometheus收集指标
- Grafana可视化监控
配置示例:
management: endpoints: web: exposure: include: health,info,metrics,prometheus metrics: tags: application: ${spring.application.name}5.3 系统安全防护措施
关键安全实践:
- SQL注入防护:使用预编译语句
- XSS防护:前端转义+后端过滤
- CSRF防护:虽然RESTful API通常不需要,但表单提交仍需考虑
- 密码安全:BCrypt加密存储
- 敏感数据脱敏
密码加密实现:
@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } public String register(User user) { user.setPassword(passwordEncoder.encode(user.getPassword())); userMapper.insert(user); return generateToken(user); }6. 项目部署与运维
6.1 多环境配置管理
Spring Boot多环境配置:
- application.yml 基础配置
- application-dev.yml 开发环境
- application-prod.yml 生产环境
- 通过spring.profiles.active指定环境
前端环境变量配置:
// .env.development VUE_APP_API_BASE_URL=http://localhost:8080 // .env.production VUE_APP_API_BASE_URL=https://api.furniture-store.com6.2 容器化部署方案
Docker部署关键步骤:
- 构建Spring Boot应用的JAR包
- 编写Dockerfile
- 构建前端静态资源
- 配置Nginx反向代理
后端Dockerfile示例:
FROM openjdk:11-jre WORKDIR /app COPY target/furniture-store.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]前端Dockerfile示例:
FROM nginx:alpine COPY dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 806.3 CI/CD自动化流程
GitHub Actions配置示例:
name: Build and Deploy on: push: branches: [ main ] jobs: build-backend: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up JDK 11 uses: actions/setup-java@v2 with: java-version: '11' distribution: 'adopt' - name: Build with Maven run: mvn clean package -DskipTests - name: Build and push Docker image run: | docker build -t furniture-store-backend . docker tag furniture-store-backend registry.example.com/furniture-store-backend:${{ github.sha }} docker push registry.example.com/furniture-store-backend:${{ github.sha }}7. 常见问题与解决方案
7.1 跨域会话保持问题
前后端分离架构下,解决认证信息保持的方案:
- JWT存储在HttpOnly的Cookie中
- 配置跨域携带Cookie
- 服务端设置正确的CORS头
前端axios配置:
axios.defaults.withCredentials = true后端CORS调整:
.allowedOrigins("http://localhost:8081") .allowCredentials(true)7.2 Vue3响应式数据更新问题
常见问题及解决:
- 数组更新不触发响应:使用push等变异方法或重新赋值
- 对象新增属性不响应:使用Vue.set或重新赋值
- 解构丢失响应性:使用toRefs保持响应性
正确做法示例:
const state = reactive({ items: [] }) // 正确更新数组 state.items.push(newItem) // 或 state.items = [...state.items, newItem] // 正确添加对象属性 state.user = { ...state.user, newProp: value }7.3 MyBatis动态SQL使用技巧
复杂查询场景下的动态SQL实践:
- 使用 标签自动处理AND前缀
- 实现条件分支
- 处理集合参数
- 定义变量
动态排序示例:
<select id="selectProducts" resultMap="productResultMap"> SELECT * FROM product <where> <if test="categoryId != null"> AND category_id = #{categoryId} </if> </where> ORDER BY <choose> <when test="orderBy == 'price'">price</when> <when test="orderBy == 'sales'">sales_count</when> <otherwise>id</otherwise> </choose> <if test="orderDirection != null"> ${orderDirection} </if> </select>8. 项目扩展与进阶方向
8.1 微服务架构改造
单体到微服务的演进路径:
- 按业务功能拆分服务
- 引入Spring Cloud组件
- 实现服务注册发现
- 配置API网关
- 处理分布式事务
商品服务独立示例:
@SpringBootApplication @EnableDiscoveryClient public class ProductServiceApplication { public static void main(String[] args) { SpringApplication.run(ProductServiceApplication.class, args); } }8.2 引入Elasticsearch提升搜索体验
商品搜索优化方案:
- 部署Elasticsearch集群
- 使用Logstash同步MySQL数据
- 实现多条件商品搜索
- 支持拼音/同义词搜索
Spring Data Elasticsearch集成:
@Document(indexName = "products") public class ProductES { @Id private Long id; private String name; private String description; // 其他字段... } public interface ProductESRepository extends ElasticsearchRepository<ProductES, Long> { Page<ProductES> findByNameOrDescription(String name, String description, Pageable pageable); }8.3 支付系统集成
常见支付接入方案:
- 支付宝/微信支付SDK集成
- 处理支付回调通知
- 实现订单状态同步
- 处理退款流程
支付回调处理核心代码:
@PostMapping("/pay/callback") public String paymentCallback(@RequestBody String notifyData) { // 验证签名 boolean verifyResult = paymentService.verifySignature(notifyData); if (!verifyResult) { throw new RuntimeException("签名验证失败"); } // 解析支付结果 PaymentResult result = paymentService.parseNotifyData(notifyData); // 更新订单状态 orderService.updatePaymentStatus(result.getOrderId(), result.isSuccess()); return "success"; }9. 开发经验与最佳实践
9.1 前后端协作流程优化
高效协作的关键点:
- 使用Swagger或YAPI维护API文档
- 定义统一的接口规范
- 前端Mock数据开发
- 定期同步接口变更
Spring Boot集成Swagger:
@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.furniture.store.controller")) .paths(PathSelectors.any()) .build() .apiInfo(apiInfo()); } }9.2 代码质量保障措施
质量保障体系:
- 单元测试覆盖核心逻辑
- 集成测试验证接口功能
- SonarQube静态代码分析
- Git提交规范约束
JUnit测试示例:
@SpringBootTest public class ProductServiceTest { @Autowired private ProductService productService; @Test @Transactional @Rollback public void testCreateProduct() { ProductCreateDTO dto = new ProductCreateDTO(); dto.setName("测试商品"); dto.setPrice(new BigDecimal("99.99")); Product product = productService.createProduct(dto); assertNotNull(product.getId()); assertEquals("测试商品", product.getName()); } }9.3 项目文档编写要点
必备项目文档:
- 接口文档(Swagger)
- 数据库设计文档
- 部署文档
- 开发环境搭建指南
- 项目结构说明
数据库文档示例:
## 商品表(product) | 字段 | 类型 | 必填 | 描述 | |------|------|------|------| | id | bigint | 是 | 主键 | | name | varchar(100) | 是 | 商品名称 | | price | decimal(10,2) | 是 | 商品价格 | | stock | int | 是 | 库存数量 | | status | tinyint | 是 | 状态(1-上架,0-下架) |10. 项目总结与反思
经过这个家具商城项目的完整开发周期,我深刻体会到全栈开发的挑战与乐趣。SpringBoot+Vue3+MyBatis的技术组合确实能够快速构建出功能完善、性能良好的电商系统。但在实际开发中,以下几个方面的经验特别值得分享:
- 接口设计要前后端共同参与,避免后期频繁修改
- 数据库设计要考虑扩展性,特别是商品多规格场景
- 事务处理要格外小心,特别是库存扣减和订单创建
- 前端状态管理要合理规划,避免组件间状态混乱
- 性能优化要从项目初期就考虑,而不是后期补救
一个实用的建议是:在开发商品详情页时,尽早实现静态化或缓存策略,因为这个页面访问频率高且对性能要求严格。我们最初没有做好这点,导致促销活动时数据库压力很大,后来通过Redis缓存商品详情数据解决了这个问题。