SpringBoot+Vue前后端分离超市管理系统实战教程
如果你正在学习Java全栈开发想要找一个既能练手又有实际应用价值的项目超市管理系统绝对是一个不错的选择。但市面上的很多教程要么过于简单要么技术栈陈旧很难让你真正掌握企业级开发的核心要点。这篇文章要解决的核心问题是如何从零开始构建一个真正可用的前后端分离超市管理系统而不仅仅是完成一个玩具项目。我们将使用SpringBoot Vue的主流技术栈重点讲解在实际开发中容易踩坑的地方比如权限设计、接口规范、数据一致性等关键问题。通过本文你将学会的不仅仅是代码编写更重要的是理解一个完整项目的架构设计思路和工程化实践。无论你是准备毕业设计、面试项目展示还是想要提升实际开发能力这篇文章都能给你实实在在的帮助。1. 为什么超市管理系统是Java学习的黄金项目超市管理系统看似简单实则包含了企业级应用的核心要素。与图书管理系统、学生管理系统相比它的业务场景更贴近真实商业环境涉及的商品管理、库存控制、销售分析等模块都是电商系统的简化版。技术层面的价值完整的CRUD操作从简单的增删改查到复杂的联表查询权限控制需求不同角色管理员、收银员、采购员的操作权限差异数据一致性要求库存增减与销售记录的原子性操作前后端分离实践RESTful API设计、跨域处理、Token认证学习路径的合理性 对于初学者来说直接从微服务、分布式系统入手往往难度过大。超市管理系统提供了一个恰到好处的复杂度既有足够的技术挑战又不会让人望而却步。完成这个项目后你能够平滑过渡到更复杂的电商系统开发。2. 技术栈选择与架构设计2.1 后端技术栈!-- SpringBoot核心依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-security/artifactId /dependency选择理由SpringBoot简化配置快速启动JPA面向对象的数据操作适合初学者理解Spring Security成熟的权限管理框架2.2 前端技术栈// package.json 核心依赖 { dependencies: { vue: ^3.0.0, vue-router: ^4.0.0, axios: ^1.0.0, element-plus: ^2.0.0 } }架构设计要点 前后端完全分离通过RESTful API进行数据交互。这种架构的优势在于前端可以独立开发和部署后端API可以被多种客户端复用团队分工明确提高开发效率3. 数据库设计与核心表结构数据库设计是项目成功的关键。我们需要考虑数据的完整性、查询效率以及未来的扩展性。3.1 用户表userCREATE TABLE user ( id bigint(20) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL COMMENT 用户名, password varchar(100) NOT NULL COMMENT 密码, real_name varchar(50) DEFAULT NULL COMMENT 真实姓名, role varchar(20) NOT NULL COMMENT 角色ADMIN、CASHIER、PURCHASER, status tinyint(1) NOT NULL DEFAULT 1 COMMENT 状态1启用0禁用, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;3.2 商品表productCREATE TABLE product ( id bigint(20) NOT NULL AUTO_INCREMENT, product_code varchar(50) NOT NULL COMMENT 商品编码, product_name varchar(100) NOT NULL COMMENT 商品名称, category_id bigint(20) NOT NULL COMMENT 分类ID, price decimal(10,2) NOT NULL COMMENT 售价, cost_price decimal(10,2) DEFAULT NULL COMMENT 成本价, stock int(11) NOT NULL DEFAULT 0 COMMENT 库存, min_stock int(11) NOT NULL DEFAULT 0 COMMENT 最低库存预警, status tinyint(1) NOT NULL DEFAULT 1 COMMENT 状态1上架0下架, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_product_code (product_code), KEY idx_category (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品表;3.3 核心业务关系设计商品分类与商品是一对多关系订单与订单项也是一对多关系。这种设计保证了数据的规范化和查询效率。4. 后端核心功能实现4.1 项目结构规划src/main/java/com/supermarket/ ├── config/ # 配置类 ├── controller/ # 控制层 ├── service/ # 业务层 ├── repository/ # 数据访问层 ├── entity/ # 实体类 ├── dto/ # 数据传输对象 ├── security/ # 安全相关 └── exception/ # 异常处理4.2 商品管理核心代码// ProductController.java RestController RequestMapping(/api/products) PreAuthorize(hasAnyRole(ADMIN, PURCHASER)) public class ProductController { Autowired private ProductService productService; GetMapping public ResponseEntityPageResultProductDTO getProducts( RequestParam(defaultValue 1) int page, RequestParam(defaultValue 10) int size, RequestParam(required false) String keyword) { Pageable pageable PageRequest.of(page - 1, size); return ResponseEntity.ok(productService.getProducts(keyword, pageable)); } PostMapping public ResponseEntityProductDTO createProduct(Valid RequestBody ProductDTO productDTO) { return ResponseEntity.ok(productService.createProduct(productDTO)); } PutMapping(/{id}) public ResponseEntityProductDTO updateProduct( PathVariable Long id, Valid RequestBody ProductDTO productDTO) { return ResponseEntity.ok(productService.updateProduct(id, productDTO)); } }4.3 库存管理的并发控制// ProductService.java Service Transactional public class ProductService { public synchronized boolean updateStock(Long productId, int quantity) { Product product productRepository.findById(productId) .orElseThrow(() - new ResourceNotFoundException(商品不存在)); if (product.getStock() quantity 0) { throw new BusinessException(库存不足); } product.setStock(product.getStock() quantity); productRepository.save(product); // 记录库存变更日志 stockLogService.logStockChange(productId, quantity, 销售出库); return true; } }5. 前端Vue3项目搭建与核心组件5.1 项目初始化与配置// main.js import { createApp } from vue import App from ./App.vue import router from ./router import store from ./store import ElementPlus from element-plus import element-plus/dist/index.css const app createApp(App) app.use(store) app.use(router) app.use(ElementPlus) app.mount(#app)5.2 商品管理组件!-- ProductList.vue -- template div classproduct-management el-card template #header div classcard-header span商品管理/span el-button typeprimary clickhandleCreate新增商品/el-button /div /template el-table :dataproductList v-loadingloading el-table-column propproductCode label商品编码 width120 / el-table-column propproductName label商品名称 / el-table-column propcategoryName label分类 width120 / el-table-column propprice label售价 width100 template #defaultscope ¥{{ scope.row.price }} /template /el-table-column el-table-column propstock label库存 width100 / el-table-column label操作 width200 template #defaultscope el-button sizesmall clickhandleEdit(scope.row)编辑/el-button el-button sizesmall typedanger clickhandleDelete(scope.row)删除/el-button /template /el-table-column /el-table el-pagination v-model:current-pagepagination.current v-model:page-sizepagination.size :totalpagination.total current-changehandlePageChange layouttotal, sizes, prev, pager, next, jumper / /el-card /div /template script setup import { ref, onMounted } from vue import { ElMessage, ElMessageBox } from element-plus import { getProducts, deleteProduct } from /api/product const productList ref([]) const loading ref(false) const pagination ref({ current: 1, size: 10, total: 0 }) const loadProducts async () { loading.value true try { const response await getProducts({ page: pagination.value.current, size: pagination.value.size }) productList.value response.data.list pagination.value.total response.data.total } catch (error) { ElMessage.error(加载商品列表失败) } finally { loading.value false } } const handleDelete async (product) { try { await ElMessageBox.confirm(确定要删除这个商品吗, 提示, { type: warning }) await deleteProduct(product.id) ElMessage.success(删除成功) loadProducts() } catch (error) { // 用户取消删除 } } onMounted(() { loadProducts() }) /script6. 权限系统设计与实现6.1 基于角色的访问控制RBAC// SecurityConfig.java Configuration EnableWebSecurity public class SecurityConfig { Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeHttpRequests(authz - authz .requestMatchers(/api/auth/**).permitAll() .requestMatchers(/api/admin/**).hasRole(ADMIN) .requestMatchers(/api/products/**).hasAnyRole(ADMIN, PURCHASER) .requestMatchers(/api/sales/**).hasAnyRole(ADMIN, CASHIER) .anyRequest().authenticated() ) .sessionManagement(session - session .sessionCreationPolicy(SessionCreationPolicy.STATELESS) ) .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } }6.2 JWT令牌实现// JwtUtil.java Component public class JwtUtil { Value(${jwt.secret}) private String secret; Value(${jwt.expiration}) private Long expiration; public String generateToken(UserDetails userDetails) { MapString, Object claims new HashMap(); return Jwts.builder() .setClaims(claims) .setSubject(userDetails.getUsername()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() expiration)) .signWith(SignatureAlgorithm.HS512, secret) .compact(); } public boolean validateToken(String token, UserDetails userDetails) { final String username extractUsername(token); return (username.equals(userDetails.getUsername()) !isTokenExpired(token)); } }7. 销售模块与库存联动7.1 销售业务逻辑// SaleService.java Service Transactional public class SaleService { public SaleDTO createSale(SaleDTO saleDTO) { // 1. 验证商品库存 for (SaleItemDTO item : saleDTO.getItems()) { Product product productRepository.findById(item.getProductId()) .orElseThrow(() - new ResourceNotFoundException(商品不存在)); if (product.getStock() item.getQuantity()) { throw new BusinessException(商品【 product.getProductName() 】库存不足); } } // 2. 创建销售记录 Sale sale new Sale(); sale.setSaleCode(generateSaleCode()); sale.setTotalAmount(calculateTotalAmount(saleDTO.getItems())); sale.setCashierId(saleDTO.getCashierId()); sale saleRepository.save(sale); // 3. 创建销售明细并扣减库存 for (SaleItemDTO item : saleDTO.getItems()) { SaleItem saleItem new SaleItem(); saleItem.setSaleId(sale.getId()); saleItem.setProductId(item.getProductId()); saleItem.setQuantity(item.getQuantity()); saleItem.setUnitPrice(item.getUnitPrice()); saleItemRepository.save(saleItem); // 扣减库存 productService.updateStock(item.getProductId(), -item.getQuantity()); } return convertToDTO(sale); } }8. 项目部署与运行8.1 后端启动配置# application.yml server: port: 8080 servlet: context-path: /api spring: datasource: url: jdbc:mysql://localhost:3306/supermarket?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: update show-sql: true jwt: secret: supermarket-secret-key expiration: 86400000 # 24小时8.2 前端部署脚本// package.json { scripts: { dev: vite, build: vite build, preview: vite preview, deploy: npm run build rsync -av dist/ userserver:/path/to/nginx/html/ } }9. 常见问题与解决方案9.1 跨域问题处理// CorsConfig.java Configuration public class CorsConfig { Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); CorsConfiguration config new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin(http://localhost:3000); config.addAllowedHeader(*); config.addAllowedMethod(*); source.registerCorsConfiguration(/**, config); return new CorsFilter(source); } }9.2 数据一致性保障在销售和库存更新时使用Transactional注解确保事务性Service public class InventoryService { Transactional(rollbackFor Exception.class) public void processSale(Long saleId) { // 业务逻辑如果任何一步失败整个事务回滚 } }9.3 性能优化建议数据库索引优化为经常查询的字段建立索引接口缓存使用Redis缓存热点数据分页查询大数据量时一定要使用分页前端懒加载图片等资源按需加载10. 项目扩展与进阶学习完成基础版本后可以考虑以下扩展功能报表统计销售报表、库存报表、利润分析会员系统积分、折扣、会员等级供应商管理采购订单、供应商评估移动端支持开发微信小程序版本微服务改造将系统拆分为多个微服务这个超市管理系统项目涵盖了JavaWeb开发的核心技术要点从数据库设计到前后端分离从权限管理到业务逻辑实现。建议按照本文的步骤逐步实现遇到问题时重点理解解决方案的设计思路而不仅仅是复制代码。真正的技术成长来自于实践中遇到的问题和解决问题的过程。建议在完成基础功能后尝试自己添加一些扩展功能这样能够更好地掌握系统设计的思维方式。