# fruitmarket **Repository Path**: saiomeil/fruitmarket ## Basic Information - **Project Name**: fruitmarket - **Description**: 水果超市促销系统 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-08 - **Last Updated**: 2026-04-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 水果超市管理系统 基于Spring Boot 3 + JPA的水果超市价格计算系统,采用策略模式实现多种促销方式。 ## 需求内容 1、有一家超市,出售苹果和草莓。其中苹果 8 元/斤,草莓 13 元/斤。 现在顾客 A 在超市购买了若干斤苹果和草莓,需要计算一共多少钱? 请编写函数,对于 A 购买的水果斤数 (水果斤数为大于等于 0 的整数),计算并返回所购买商品的总价。 2、超市增加了一种水果芒果,其定价为 20 元/斤。 现在顾客 B 在超市购买了若干斤苹果、 草莓和芒果,需计算一共需要多少钱? 请编写函数,对于 B 购买的水果斤数 (水果斤数为大于等于 0 的整数),计算并返回所购买商品的总价。 3、超市做促销活动,草莓限时打 8 折。 现在顾客 C 在超市购买了若干斤苹果、 草莓和芒果,需计算一共需要多少钱? 请编写函数,对于 C 购买的水果斤数 (水果斤数为大于等于 0 的整数),计算并返回所购买商品的总价。 4、促销活动效果明显,超市继续加大促销力度,购物满 100 减 10 块。 现在顾客 D 在超市购买了若干斤苹果、 草莓和芒果,需计算一共需要多少钱? 请编写函数,对于 D 购买的水果斤数 (水果斤数为大于等于 0 的整数),计算并返回所购买商品的总价。 ## 技术栈 - **Spring Boot 3.2.0** - 核心框架 - **Spring Data JPA** - ORM映射 - **Redis** - 查询缓存优化 - **Knife4j** - API接口文档 - **MySQL** - 数据存储 ## 前端项目,可以远程访问 https://www.saiomeil.com 用自己的测试服务器已经部署前端操作界面 ### 测试服务器:DNS域名解析不是很稳定,有时候会出现网络异常,多访问几次 https://www.saiomeil.com 就好 #### 请一定点击查看一下我设计的计算界面。 #### 前端代码:frontend #### 前端技术栈:Vue3 ElementPlus Axios #### 可以在request.js 配置后端接口路径 参考代码:https://gitee.com/saiomeil/fruitmarket/blob/master/frontend/src/api/request.js#L4-L10 ![img.png](img.png) ## 项目结构 ``` fruit-market/ ├── src/main/java/com/fruitmarket/ │ ├── FruitShopApplication.java # 应用入口 │ ├── config/ # 配置类 │ │ ├── RedisConfig.java # Redis配置 │ │ ├── Knife4jConfig.java # API文档配置 │ │ └── WebConfig.java # Web配置 │ ├── entity/ # 实体类 │ │ ├── Fruit.java # 水果实体 │ │ ├── Promotion.java # 促销实体 │ │ ├── PromotionType.java # 促销类型枚举 │ │ ├── CartItem.java # 购物车项 │ │ ├── OrderCalculateRequest.java # 订单请求 │ │ └── OrderCalculateResponse.java # 订单响应 │ ├── repository/ # 数据访问层 │ │ ├── FruitRepository.java │ │ └── PromotionRepository.java │ ├── strategy/ # 促销策略(核心设计) │ │ ├── PromotionStrategy.java # 策略接口 │ │ ├── PromotionStrategyFactory.java # 策略工厂 │ │ └── impl/ # 策略实现 │ │ ├── FullReductionStrategy.java # 满减策略 │ │ ├── DiscountStrategy.java # 打折策略 │ │ └── FixedPriceStrategy.java # 固定价策略 │ ├── service/ # 业务逻辑层 │ │ ├── FruitService.java │ │ ├── PromotionService.java │ │ └── PriceCalculateService.java # 价格计算服务 │ ├── controller/ # 接口层 │ │ ├── FruitController.java │ │ ├── PromotionController.java │ │ ├── PriceCalculateController.java │ │ └── SystemController.java │ ├── common/ # 公共类 │ │ ├── ApiResponse.java │ │ └── GlobalExceptionHandler.java │ └── init/ # 数据初始化 │ └── DataInitializer.java └── src/main/resources/ └── application.yml # 应用配置 ``` ## 计算价格核心代码 1:方法入口:https://gitee.com/saiomeil/fruitmarket/blob/master/src/main/java/com/fruitmarket/service/PriceCalculateService.java#L40-L73 2:核心计算入口:https://gitee.com/saiomeil/fruitmarket/blob/master/src/main/java/com/fruitmarket/service/PriceCalculateService.java#L134-L157 ## 核心设计:策略模式 ### 为什么使用策略模式? 1. **符合开闭原则**:添加新促销类型只需添加新的策略类,无需修改现有代码 2. **消除条件语句**:避免大量if-else或switch-case 3. **单一职责**:每个策略类职责单一,易于测试和维护 4. **可替换性**:可以在运行时切换不同的促销策略 ### 促销类型与配置 | 促销类型 | 配置示例 | 说明 | |---------|---------|------| | FULL_REDUCTION | `{"threshold": 100, "discount": 10}` | 满100减10元 | | DISCOUNT | `{"discountRate": 0.8}` | 打8折 | | FIXED_PRICE | `{"fixedPrice": 5.99}` | 固定价格5.99元 | 前端界面添加FIXED_PRICE时,又前端写入{"fixedPrice": 5.99} ### 扩展新促销类型 只需3步: 1. 在 `PromotionType` 枚举中添加新类型 2. 创建新的策略实现类(实现 `PromotionStrategy` 接口) 3. 在策略实现类上添加 `@Component` 注解(自动注册到工厂) ## API接口 ### 水果管理 | 方法 | 路径 | 说明 | |-----|------|------| | GET | /api/fruits | 获取所有水果 | | GET | /api/fruits/active | 获取上架水果 | | GET | /api/fruits/{id} | 获取水果详情 | | POST | /api/fruits | 创建水果 | | PUT | /api/fruits/{id} | 更新水果 | | PATCH | /api/fruits/{id}/price | 更新价格 | | DELETE | /api/fruits/{id} | 删除水果 | ### 促销管理 | 方法 | 路径 | 说明 | |-----|------|------| | GET | /api/promotions | 获取所有促销 | | GET | /api/promotions/active | 获取启用促销 | | GET | /api/promotions/valid | 获取有效促销 | | GET | /api/promotions/types | 获取支持的促销类型 | | POST | /api/promotions | 创建促销 | | PUT | /api/promotions/{id} | 更新促销 | | DELETE | /api/promotions/{id} | 删除促销 | ### 价格计算 | 方法 | 路径 | 说明 | |-----|------|------| | POST | /api/calculate | 计算订单价格 | | GET | /api/calculate/preview | 预览促销效果 | ## 价格计算示例 ### 请求 ```json POST /api/calculate { "carts": [ { "fruitId": 1, "quantity": 40 }, { "fruitId": 2, "quantity": 50 } ], "promotionIds": [1] } ``` ### 响应 ```json { "originalTotal": 970, "finalTotal": 889, "discountAmount": 81, "orderItems": [ { "fruitName": "苹果", "unitPrice": 8, "quantity": 40, "subtotal": 320 }, { "fruitName": "草莓", "unitPrice": 13, "quantity": 50, "subtotal": 650 } ], "promotionItems": [ { "promotionType": "FULL_REDUCTION", "promotionName": "满100减10元", "originalTotal": 970, "finalTotal": 889, "discountAmount": 81 } ] } ``` ## 运行项目 ### 环境要求 - JDK 17+ - MySQL 8.0+ - Redis 6.0+ - Maven 3.8+ ### 配置数据库 修改 `application.yml` 中的数据库配置: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/fruit_market username: root password: your_password data: redis: host: localhost port: 6379 ``` ### 启动服务 ```bash # 编译项目 mvn clean package # 运行项目 mvn spring-boot:run # 部署方式 java -jar target/fruit-market-1.0.0.jar ``` linux 部署: 修改一下 deploy.sh 的文件路径,即可部署 ### 访问API文档 启动后访问:http://localhost:{port}/doc.html ## 缓存策略 - 水果列表缓存:1天 - 水果详情缓存:1天 - 促销列表缓存:1天 - 数据更新时自动清除相关缓存