作为一名有10年Java全栈开发经验的工程师,我经常被问到如何设计一个完整的毕业项目。今天要分享的是一个基于SpringBoot的生日蛋糕订购商城系统,这个项目不仅技术栈主流,业务场景贴近生活,更重要的是它涵盖了电商系统90%的核心功能模块。
这个蛋糕商城系统采用前后端分离架构,后端使用SpringBoot+MyBatisPlus,前端采用Vue.js,数据库选用MySQL。系统实现了用户注册登录、商品管理、订单处理、支付对接等完整电商流程,特别适合作为计算机相关专业的毕业设计选题。
为什么我特别推荐这个项目?
- 技术栈组合市场认可度高,SpringBoot+Vue是当前企业主流技术
- 业务逻辑完整但不复杂,2-3周即可完成核心开发
- 模块划分清晰,便于展示MVC设计模式的理解
- 可扩展性强,后续可轻松加入优惠券、秒杀等高级功能
后端技术栈:
前端技术栈:

这个架构采用了经典的三层设计:
数据库设计遵循三范式,主要包含以下核心表:
用户相关表:
sql复制CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(100) NOT NULL COMMENT '密码',
`phone` varchar(20) COMMENT '手机号',
`email` varchar(100) COMMENT '邮箱',
`avatar` varchar(255) COMMENT '头像',
`status` tinyint DEFAULT 1 COMMENT '状态 0-禁用 1-正常',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
商品相关表:
sql复制CREATE TABLE `product` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '商品名称',
`price` decimal(10,2) NOT NULL COMMENT '价格',
`stock` int NOT NULL COMMENT '库存',
`description` text COMMENT '商品描述',
`image_url` varchar(255) COMMENT '主图URL',
`category_id` bigint COMMENT '分类ID',
`status` tinyint DEFAULT 1 COMMENT '状态 0-下架 1-上架',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
数据库设计心得:
- 所有表都添加了create_time和update_time字段,便于后期排查问题
- 金额字段使用decimal类型,避免浮点数精度问题
- 建立适当的索引提升查询性能,但不宜过多影响写入速度
采用Shiro实现安全的认证授权流程:
java复制@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private UserService userService;
@PostMapping("/login")
public Result login(@RequestBody LoginDTO dto) {
// 1. 验证验证码
if(!CaptchaUtil.verify(dto.getCaptchaKey(), dto.getCaptcha())){
return Result.fail("验证码错误");
}
// 2. Shiro认证
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(
dto.getUsername(),
dto.getPassword()
);
try {
subject.login(token);
User user = (User) subject.getPrincipal();
String jwtToken = JwtUtil.generateToken(user.getId());
return Result.success(jwtToken);
} catch (AuthenticationException e) {
return Result.fail("用户名或密码错误");
}
}
@RequiresRoles("admin")
@GetMapping("/admin/test")
public Result adminTest() {
return Result.success("管理员权限测试通过");
}
}
实现商品的CRUD操作,特别注意图片上传的处理:
java复制@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product>
implements ProductService {
@Value("${file.upload-path}")
private String uploadPath;
@Override
@Transactional
public boolean saveProduct(ProductDTO dto) {
Product product = new Product();
BeanUtils.copyProperties(dto, product);
// 处理图片上传
if(!dto.getImageFile().isEmpty()) {
String filename = FileUtil.upload(
dto.getImageFile(),
uploadPath + "/product"
);
product.setImageUrl("/upload/product/" + filename);
}
return this.save(product);
}
@Override
public Page<ProductVO> queryPage(ProductQuery query, Pageable pageable) {
return this.lambdaQuery()
.like(StringUtils.hasText(query.getName()), Product::getName, query.getName())
.eq(query.getCategoryId() != null, Product::getCategoryId, query.getCategoryId())
.eq(query.getStatus() != null, Product::getStatus, query.getStatus())
.page(pageable)
.convert(product -> {
ProductVO vo = new ProductVO();
BeanUtils.copyProperties(product, vo);
return vo;
});
}
}
订单状态机设计是电商系统的核心:
java复制@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private ProductMapper productMapper;
@Override
@Transactional
public Order createOrder(OrderCreateDTO dto, Long userId) {
// 1. 校验库存
Product product = productMapper.selectById(dto.getProductId());
if(product == null || product.getStatus() == 0) {
throw new BusinessException("商品不存在或已下架");
}
if(product.getStock() < dto.getQuantity()) {
throw new BusinessException("库存不足");
}
// 2. 扣减库存
int update = productMapper.deductStock(
dto.getProductId(),
dto.getQuantity()
);
if(update == 0) {
throw new BusinessException("库存不足");
}
// 3. 生成订单
Order order = new Order();
order.setUserId(userId);
order.setOrderNo(OrderNoGenerator.generate());
order.setProductId(dto.getProductId());
order.setQuantity(dto.getQuantity());
order.setTotalAmount(product.getPrice().multiply(
new BigDecimal(dto.getQuantity())
));
order.setStatus(OrderStatus.UNPAID.getCode());
orderMapper.insert(order);
return order;
}
@Override
@Transactional
public void paySuccess(String orderNo) {
Order order = orderMapper.selectByOrderNo(orderNo);
if(order == null) {
throw new BusinessException("订单不存在");
}
if(order.getStatus() != OrderStatus.UNPAID.getCode()) {
throw new BusinessException("订单状态异常");
}
order.setStatus(OrderStatus.PAID.getCode());
order.setPayTime(LocalDateTime.now());
orderMapper.updateById(order);
// 发送订单支付成功事件
eventPublisher.publishEvent(new OrderPaidEvent(this, order));
}
}
java复制public class OrderNoGenerator {
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
public static String generate() {
return "ORD" + LocalDateTime.now().format(FORMATTER)
+ RandomUtil.randomNumbers(4);
}
}
java复制@Component
public class OrderPaidListener {
@EventListener
public void handleOrderPaid(OrderPaidEvent event) {
Order order = event.getOrder();
// 1. 发送短信通知
SmsUtil.sendOrderPaidSms(order.getUserId());
// 2. 记录订单日志
logOrderService.recordPaidLog(order);
// 3. 更新销量统计
productSalesService.updateSales(order.getProductId(), order.getQuantity());
}
}
java复制@Service
@CacheConfig(cacheNames = "product")
public class ProductServiceImpl implements ProductService {
@Cacheable(key = "#id")
@Override
public Product getById(Long id) {
return baseMapper.selectById(id);
}
@CacheEvict(key = "#product.id")
@Override
public boolean updateProduct(Product product) {
return updateById(product);
}
}
java复制@Async
public void asyncProcessOrder(Order order) {
// 耗时操作如生成PDF发票等
Invoice invoice = invoiceService.generate(order);
emailService.sendInvoice(order.getEmail(), invoice);
}
bash复制# 安装JDK 1.8+
brew install openjdk@11
# 安装Maven
brew install maven
# 安装MySQL
brew install mysql
mysql.server start
bash复制# 安装Node.js
brew install node
# 安装Vue CLI
npm install -g @vue/cli
使用Docker Compose一键部署:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: cake_shop
ports:
- "3306:3306"
volumes:
- ./mysql/data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
如果想提升项目难度和含金量,可以考虑以下扩展方向:
项目开发心得:
- 先完成核心业务流程,再考虑扩展功能
- 数据库设计阶段多花时间,后期修改成本高
- 合理使用设计模式,但不要过度设计
- 重视异常处理和日志记录,方便排查问题
这个蛋糕商城项目涵盖了企业级应用的大部分核心技术点,从认证授权到事务管理,从缓存优化到前后端分离,非常适合作为毕业设计选题。如果需要完整源码或技术指导,可以通过文末方式联系我获取项目全套资料,包括数据库脚本、部署文档和论文模板等。