在当今数字化浪潮下,电子商务已成为商业活动的主流形式。作为一名长期从事企业级应用开发的工程师,我深刻体会到传统零售模式向线上转型的迫切需求。本次分享的SpringBoot+Vue全栈电商系统,正是为解决中小型企业快速搭建在线销售平台而设计的解决方案。
这个系统采用经典的前后端分离架构,后端基于SpringBoot 2.7实现业务逻辑和API接口,前端使用Vue 3组合式API开发管理后台和用户端界面。数据库选用MySQL 8.0,通过MyBatis-Plus实现高效的数据持久化操作。系统完整实现了商品管理、订单处理、支付对接等电商核心功能模块。
提示:系统设计时特别考虑了中小企业的实际需求,避免了过度复杂的设计,确保在保持功能完备的同时具备良好的可维护性。
SpringBoot作为后端核心框架,其自动配置特性大幅减少了XML配置工作量。我们采用多模块化设计:
ecommerce-core 包含实体类和通用工具ecommerce-admin 处理后台管理逻辑ecommerce-api 提供RESTful接口ecommerce-job 负责定时任务关键依赖配置示例:
xml复制<dependencies>
<!-- SpringBoot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 数据库相关 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!-- 安全控制 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
Vue 3的组合式API使代码组织更加灵活。前端项目采用如下结构:
code复制src/
├── api/ # 接口定义
├── assets/ # 静态资源
├── components/ # 公共组件
├── composables/ # 组合式函数
├── router/ # 路由配置
├── stores/ # Pinia状态管理
├── styles/ # 全局样式
├── utils/ # 工具函数
└── views/ # 页面组件
典型商品列表组件实现:
javascript复制<script setup>
import { ref, onMounted } from 'vue'
import { getProductList } from '@/api/product'
const products = ref([])
const loading = ref(false)
const fetchProducts = async () => {
loading.value = true
try {
const res = await getProductList({
page: 1,
size: 10
})
products.value = res.data
} finally {
loading.value = false
}
}
onMounted(() => {
fetchProducts()
})
</script>
用户表设计考虑了安全性和扩展性:
sql复制CREATE TABLE `user` (
`user_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`username` VARCHAR(50) NOT NULL COMMENT '用户名',
`password_hash` VARCHAR(64) NOT NULL COMMENT '加密密码',
`salt` VARCHAR(32) NOT NULL COMMENT '加密盐值',
`email` VARCHAR(100) NOT NULL COMMENT '邮箱',
`phone` VARCHAR(20) DEFAULT NULL COMMENT '手机号',
`avatar` VARCHAR(255) DEFAULT NULL COMMENT '头像URL',
`status` TINYINT NOT NULL DEFAULT '0' COMMENT '状态(0-正常,1-禁用)',
`last_login_time` DATETIME DEFAULT NULL COMMENT '最后登录时间',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`user_id`),
UNIQUE KEY `idx_username` (`username`),
UNIQUE KEY `idx_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
针对高频查询场景,我们设计了复合索引:
(category_id, is_deleted, publish_time) 用于分类页排序(user_id, order_status, create_time) 优化用户订单查询(product_id, is_show, create_time) 加速商品评价展示注意:索引不是越多越好,我们通过EXPLAIN分析执行计划,确保每个索引都被实际查询使用,避免过度索引影响写入性能。
后台商品CRUD接口采用RESTful风格设计:
java复制@RestController
@RequestMapping("/api/products")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping
public PageResult<ProductVO> listProducts(
@RequestParam(required = false) String keyword,
@RequestParam(required = false) Long categoryId,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size) {
QueryWrapper<Product> wrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(keyword)) {
wrapper.like("product_name", keyword);
}
if (categoryId != null) {
wrapper.eq("category_id", categoryId);
}
wrapper.eq("is_deleted", 0);
IPage<Product> pageInfo = productService.page(
new Page<>(page, size),
wrapper
);
return PageResult.success(pageInfo.convert(this::convertToVO));
}
private ProductVO convertToVO(Product product) {
// 转换逻辑...
}
}
购物车实现考虑了并发场景:
java复制@Service
@Transactional
public class CartServiceImpl implements CartService {
@Override
public void addToCart(Long userId, CartItemDTO item) {
// 1. 校验商品是否存在及库存
Product product = productService.getById(item.getProductId());
if (product == null || product.getIsDeleted() == 1) {
throw new BusinessException("商品不存在或已下架");
}
if (product.getStockQuantity() < item.getQuantity()) {
throw new BusinessException("库存不足");
}
// 2. 查询是否已存在购物车记录
Cart cart = cartMapper.selectOne(new QueryWrapper<Cart>()
.eq("user_id", userId)
.eq("product_id", item.getProductId())
);
// 3. 存在则更新数量,否则新增
if (cart != null) {
cart.setQuantity(cart.getQuantity() + item.getQuantity());
cartMapper.updateById(cart);
} else {
cart = new Cart();
cart.setUserId(userId);
cart.setProductId(item.getProductId());
cart.setQuantity(item.getQuantity());
cartMapper.insert(cart);
}
}
}
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated();
http.addFilterBefore(jwtAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class);
}
}
java复制@Service
@CacheConfig(cacheNames = "product")
public class ProductServiceImpl implements ProductService {
@Cacheable(key = "'detail:' + #id")
@Override
public ProductDetailVO getProductDetail(Long id) {
// 数据库查询逻辑
}
@CacheEvict(key = "'detail:' + #id")
@Override
public void updateProduct(ProductUpdateDTO dto) {
// 更新逻辑
}
}
java复制@Async
public void sendOrderEmail(Order order) {
// 发送邮件逻辑
}
Docker Compose编排示例:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: ecommerce
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/ecommerce
frontend:
build: ./frontend
ports:
- "80:80"
volumes:
mysql_data:
在实际开发过程中,有几个关键点值得特别注意:
接口版本控制:从项目开始就建立/api/v1/的版本前缀,避免后期接口变更导致的前端兼容问题。
枚举使用:所有状态字段都应使用枚举而非魔术数字,例如:
java复制public enum OrderStatus {
UNPAID(0, "待支付"),
PAID(1, "已支付"),
CANCELLED(2, "已取消");
// 省略实现...
}
这个项目从技术选型到最终部署,完整展现了现代Java全栈开发的典型工作流程。在实现过程中,特别要注意前后端协作的接口规范定义,我们采用OpenAPI 3.0标准编写API文档,使用Swagger UI提供可视化界面,大幅提高了团队协作效率。