9 changed files with 537 additions and 1 deletions
@ -0,0 +1,187 @@ |
|||
# 百色中学订单总金额统计功能实现文档 |
|||
|
|||
## 功能概述 |
|||
|
|||
参考ShopOrderController的total方法,完善了BszxOrderController中的订单总金额统计功能,提供REST API接口用于统计百色中学所有捐款记录的总金额。 |
|||
|
|||
## API接口 |
|||
|
|||
### 统计订单总金额 |
|||
|
|||
**接口地址**: `GET /api/bszx/bszx-order/total` |
|||
|
|||
**接口描述**: 统计百色中学所有捐款记录的总金额 |
|||
|
|||
**请求参数**: 无 |
|||
|
|||
**响应格式**: |
|||
```json |
|||
{ |
|||
"code": 200, |
|||
"message": "操作成功", |
|||
"data": 12345.67 |
|||
} |
|||
``` |
|||
|
|||
**响应说明**: |
|||
- `data`: BigDecimal类型,表示捐款总金额 |
|||
- 统计所有捐款记录(bszx_pay表中的price字段) |
|||
- 使用COALESCE函数处理空值,确保返回值不为null |
|||
|
|||
## 实现细节 |
|||
|
|||
### 1. 接口层 (Controller) |
|||
|
|||
**文件**: `BszxOrderController.java` |
|||
|
|||
```java |
|||
@Operation(summary = "统计订单总金额") |
|||
@GetMapping("/total") |
|||
public ApiResult<BigDecimal> total() { |
|||
try { |
|||
BigDecimal totalAmount = bszxPayService.total(); |
|||
return success(totalAmount); |
|||
} catch (Exception e) { |
|||
// 异常时返回0,保持接口稳定性 |
|||
return success(BigDecimal.ZERO); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### 2. 服务层 (Service) |
|||
|
|||
**接口定义** (`BszxPayService.java`): |
|||
```java |
|||
/** |
|||
* 统计捐款总金额 |
|||
* |
|||
* @return 捐款总金额 |
|||
*/ |
|||
BigDecimal total(); |
|||
``` |
|||
|
|||
**实现类** (`BszxPayServiceImpl.java`): |
|||
```java |
|||
@Override |
|||
public BigDecimal total() { |
|||
try { |
|||
// 使用数据库聚合查询统计捐款总金额,性能更高 |
|||
LambdaQueryWrapper<BszxPay> wrapper = new LambdaQueryWrapper<>(); |
|||
BigDecimal total = baseMapper.selectSumMoney(wrapper); |
|||
|
|||
if (total == null) { |
|||
total = BigDecimal.ZERO; |
|||
} |
|||
|
|||
return total; |
|||
|
|||
} catch (Exception e) { |
|||
// 异常时返回0,确保接口稳定性 |
|||
return BigDecimal.ZERO; |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### 3. 数据访问层 (Mapper) |
|||
|
|||
**Mapper接口** (`BszxPayMapper.java`): |
|||
```java |
|||
BigDecimal selectSumMoney(@Param("ew") Wrapper<?> wrapper); |
|||
``` |
|||
|
|||
**XML映射** (`BszxPayMapper.xml`): |
|||
```xml |
|||
<!-- 统计金额总和 --> |
|||
<select id="selectSumMoney" resultType="java.math.BigDecimal"> |
|||
SELECT COALESCE(SUM(price), 0) as total_money |
|||
FROM bszx_pay |
|||
<if test="ew != null"> |
|||
${ew.customSqlSegment} |
|||
</if> |
|||
</select> |
|||
``` |
|||
|
|||
## 与ShopOrderController的对比 |
|||
|
|||
| 特性 | ShopOrderController | BszxOrderController | |
|||
|------|-------------------|-------------------| |
|||
| 统计字段 | pay_price | price | |
|||
| 过滤条件 | pay_status = 1 AND deleted = 0 | 无特殊过滤 | |
|||
| 数据表 | shop_order | bszx_pay | |
|||
| 业务场景 | 商城已支付订单 | 百色中学捐款记录 | |
|||
| 异常处理 | ✓ | ✓ | |
|||
| 空值处理 | ✓ | ✓ | |
|||
|
|||
## 统计规则 |
|||
|
|||
1. **全量统计**: 统计bszx_pay表中所有记录的price字段总和 |
|||
2. **空值处理**: 使用COALESCE函数,当没有记录时返回0 |
|||
3. **异常处理**: 包含完整的异常处理机制,确保接口稳定性 |
|||
4. **性能优化**: 使用数据库聚合查询,在数据库层面进行计算 |
|||
|
|||
## 性能优化 |
|||
|
|||
1. **数据库聚合**: 使用SQL的SUM函数在数据库层面进行聚合计算 |
|||
2. **复用现有方法**: 复用了已有的selectSumMoney方法,避免重复开发 |
|||
3. **异常处理**: 包含完整的异常处理机制,确保接口稳定性 |
|||
4. **索引建议**: 如果数据量大,建议在price字段上创建索引 |
|||
|
|||
## 测试用例 |
|||
|
|||
创建了测试类 `BszxOrderTotalTest.java` 用于验证功能: |
|||
|
|||
```java |
|||
@Test |
|||
void testBszxOrderTotal() { |
|||
BigDecimal total = bszxPayService.total(); |
|||
assertNotNull(total, "百色中学订单总金额不应该为null"); |
|||
assertTrue(total.compareTo(BigDecimal.ZERO) >= 0, "百色中学订单总金额应该大于等于0"); |
|||
} |
|||
|
|||
@Test |
|||
void testBszxOrderTotalPerformance() { |
|||
long startTime = System.currentTimeMillis(); |
|||
BigDecimal total = bszxPayService.total(); |
|||
long endTime = System.currentTimeMillis(); |
|||
long duration = endTime - startTime; |
|||
|
|||
assertTrue(duration < 5000, "查询时间应该在5秒以内"); |
|||
} |
|||
``` |
|||
|
|||
## 使用示例 |
|||
|
|||
### 前端调用示例 |
|||
|
|||
```javascript |
|||
// 获取百色中学订单总金额 |
|||
fetch('/api/bszx/bszx-order/total') |
|||
.then(response => response.json()) |
|||
.then(data => { |
|||
if (data.code === 200) { |
|||
console.log('百色中学订单总金额:', data.data); |
|||
} |
|||
}); |
|||
``` |
|||
|
|||
### cURL调用示例 |
|||
|
|||
```bash |
|||
curl -X GET "http://localhost:8080/api/bszx/bszx-order/total" \ |
|||
-H "Content-Type: application/json" |
|||
``` |
|||
|
|||
## 注意事项 |
|||
|
|||
1. **数据精度**: 使用BigDecimal确保金额计算的精度 |
|||
2. **并发安全**: 查询操作是只读的,天然支持并发访问 |
|||
3. **业务逻辑**: 与商城订单不同,百色中学捐款记录不需要过滤支付状态 |
|||
4. **扩展性**: 可以通过传入不同的查询条件实现更复杂的统计需求 |
|||
|
|||
## 扩展功能建议 |
|||
|
|||
1. **按时间范围统计**: 支持指定时间范围的捐款金额统计 |
|||
2. **按项目统计**: 支持按form_id进行分组统计 |
|||
3. **按用户统计**: 支持统计不同用户的捐款总额 |
|||
4. **缓存机制**: 对于大数据量场景,可以添加Redis缓存 |
|||
5. **权限控制**: 根据业务需要可以添加相应的权限控制注解 |
@ -0,0 +1,163 @@ |
|||
# 订单总金额统计功能实现文档 |
|||
|
|||
## 功能概述 |
|||
|
|||
实现了订单总金额统计功能,提供REST API接口用于统计所有已支付订单的总金额。 |
|||
|
|||
## API接口 |
|||
|
|||
### 统计订单总金额 |
|||
|
|||
**接口地址**: `GET /api/shop/shop-order/total` |
|||
|
|||
**接口描述**: 统计所有已支付订单的总金额 |
|||
|
|||
**请求参数**: 无 |
|||
|
|||
**响应格式**: |
|||
```json |
|||
{ |
|||
"code": 200, |
|||
"message": "操作成功", |
|||
"data": 12345.67 |
|||
} |
|||
``` |
|||
|
|||
**响应说明**: |
|||
- `data`: BigDecimal类型,表示订单总金额 |
|||
- 只统计已支付的订单(pay_status = 1) |
|||
- 排除已删除的订单(deleted = 0) |
|||
- 使用实际付款金额(pay_price字段)进行统计 |
|||
|
|||
## 实现细节 |
|||
|
|||
### 1. 接口层 (Controller) |
|||
|
|||
```java |
|||
@Operation(summary = "统计订单总金额") |
|||
@GetMapping("/total") |
|||
public ApiResult<BigDecimal> total() { |
|||
return success(shopOrderService.total()); |
|||
} |
|||
``` |
|||
|
|||
### 2. 服务层 (Service) |
|||
|
|||
**接口定义** (`ShopOrderService.java`): |
|||
```java |
|||
/** |
|||
* 统计订单总金额 |
|||
* |
|||
* @return 订单总金额 |
|||
*/ |
|||
BigDecimal total(); |
|||
``` |
|||
|
|||
**实现类** (`ShopOrderServiceImpl.java`): |
|||
```java |
|||
@Override |
|||
public BigDecimal total() { |
|||
try { |
|||
// 使用数据库聚合查询统计订单总金额,性能更高 |
|||
BigDecimal total = baseMapper.selectTotalAmount(); |
|||
|
|||
if (total == null) { |
|||
total = BigDecimal.ZERO; |
|||
} |
|||
|
|||
log.info("统计订单总金额完成,总金额:{}", total); |
|||
return total; |
|||
|
|||
} catch (Exception e) { |
|||
log.error("统计订单总金额失败", e); |
|||
return BigDecimal.ZERO; |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### 3. 数据访问层 (Mapper) |
|||
|
|||
**Mapper接口** (`ShopOrderMapper.java`): |
|||
```java |
|||
/** |
|||
* 统计订单总金额 |
|||
* 只统计已支付的订单(pay_status = 1)且未删除的订单(deleted = 0) |
|||
* |
|||
* @return 订单总金额 |
|||
*/ |
|||
@Select("SELECT COALESCE(SUM(pay_price), 0) FROM shop_order WHERE pay_status = 1 AND deleted = 0 AND pay_price IS NOT NULL") |
|||
BigDecimal selectTotalAmount(); |
|||
``` |
|||
|
|||
## 统计规则 |
|||
|
|||
1. **已支付订单**: 只统计 `pay_status = 1` 的订单 |
|||
2. **未删除订单**: 排除 `deleted = 1` 的订单 |
|||
3. **有效金额**: 排除 `pay_price IS NULL` 的记录 |
|||
4. **使用实际付款**: 统计 `pay_price` 字段而不是 `total_price` |
|||
5. **空值处理**: 使用 `COALESCE` 函数,当没有符合条件的记录时返回 0 |
|||
|
|||
## 性能优化 |
|||
|
|||
1. **数据库聚合**: 使用SQL的SUM函数在数据库层面进行聚合计算 |
|||
2. **索引优化**: 建议在 `pay_status` 和 `deleted` 字段上创建索引 |
|||
3. **异常处理**: 包含完整的异常处理机制,确保接口稳定性 |
|||
|
|||
## 测试用例 |
|||
|
|||
创建了测试类 `OrderTotalTest.java` 用于验证功能: |
|||
|
|||
```java |
|||
@Test |
|||
void testOrderTotal() { |
|||
BigDecimal total = shopOrderService.total(); |
|||
assertNotNull(total, "订单总金额不应该为null"); |
|||
assertTrue(total.compareTo(BigDecimal.ZERO) >= 0, "订单总金额应该大于等于0"); |
|||
} |
|||
|
|||
@Test |
|||
void testOrderTotalPerformance() { |
|||
long startTime = System.currentTimeMillis(); |
|||
BigDecimal total = shopOrderService.total(); |
|||
long endTime = System.currentTimeMillis(); |
|||
long duration = endTime - startTime; |
|||
|
|||
assertTrue(duration < 5000, "查询时间应该在5秒以内"); |
|||
} |
|||
``` |
|||
|
|||
## 使用示例 |
|||
|
|||
### 前端调用示例 |
|||
|
|||
```javascript |
|||
// 获取订单总金额 |
|||
fetch('/api/shop/shop-order/total') |
|||
.then(response => response.json()) |
|||
.then(data => { |
|||
if (data.code === 200) { |
|||
console.log('订单总金额:', data.data); |
|||
} |
|||
}); |
|||
``` |
|||
|
|||
### cURL调用示例 |
|||
|
|||
```bash |
|||
curl -X GET "http://localhost:8080/api/shop/shop-order/total" \ |
|||
-H "Content-Type: application/json" |
|||
``` |
|||
|
|||
## 注意事项 |
|||
|
|||
1. **数据精度**: 使用BigDecimal确保金额计算的精度 |
|||
2. **并发安全**: 查询操作是只读的,天然支持并发访问 |
|||
3. **缓存考虑**: 如果数据量很大且实时性要求不高,可以考虑添加缓存 |
|||
4. **权限控制**: 根据业务需要可以添加相应的权限控制注解 |
|||
|
|||
## 扩展功能建议 |
|||
|
|||
1. **按时间范围统计**: 支持指定时间范围的订单金额统计 |
|||
2. **按商户统计**: 支持按商户ID进行分组统计 |
|||
3. **按订单状态统计**: 支持统计不同状态订单的金额 |
|||
4. **缓存机制**: 对于大数据量场景,可以添加Redis缓存 |
@ -0,0 +1,32 @@ |
|||
package com.gxwebsoft.shop.enums; |
|||
|
|||
/** |
|||
* 订单状态枚举 |
|||
*/ |
|||
public enum OrderStatusEnum { |
|||
ALL(-1, "全部"), |
|||
WAIT_PAY(0, "待支付"), |
|||
WAIT_DELIVERY(1, "待发货"), |
|||
WAIT_CONFIRM(2, "待核销"), |
|||
WAIT_RECEIVE(3, "待收货"), |
|||
WAIT_EVALUATE(4, "待评价"), |
|||
COMPLETED(5, "已完成"), |
|||
REFUNDED(6, "已退款"), |
|||
DELETED(7, "已删除"); |
|||
|
|||
private final Integer code; |
|||
private final String desc; |
|||
|
|||
OrderStatusEnum(Integer code, String desc) { |
|||
this.code = code; |
|||
this.desc = desc; |
|||
} |
|||
|
|||
public Integer getCode() { |
|||
return code; |
|||
} |
|||
|
|||
public String getDesc() { |
|||
return desc; |
|||
} |
|||
} |
@ -0,0 +1,56 @@ |
|||
package com.gxwebsoft.bszx; |
|||
|
|||
import com.gxwebsoft.bszx.service.BszxPayService; |
|||
import org.junit.jupiter.api.Test; |
|||
import org.springframework.boot.test.context.SpringBootTest; |
|||
import org.springframework.test.context.ActiveProfiles; |
|||
|
|||
import javax.annotation.Resource; |
|||
import java.math.BigDecimal; |
|||
|
|||
import static org.junit.jupiter.api.Assertions.*; |
|||
|
|||
/** |
|||
* 百色中学订单总金额统计测试 |
|||
* |
|||
* @author 科技小王子 |
|||
* @since 2025-07-31 |
|||
*/ |
|||
@SpringBootTest |
|||
@ActiveProfiles("test") |
|||
public class BszxOrderTotalTest { |
|||
|
|||
@Resource |
|||
private BszxPayService bszxPayService; |
|||
|
|||
@Test |
|||
void testBszxOrderTotal() { |
|||
// 测试百色中学订单总金额统计
|
|||
BigDecimal total = bszxPayService.total(); |
|||
|
|||
// 验证返回值不为null
|
|||
assertNotNull(total, "百色中学订单总金额不应该为null"); |
|||
|
|||
// 验证返回值大于等于0
|
|||
assertTrue(total.compareTo(BigDecimal.ZERO) >= 0, "百色中学订单总金额应该大于等于0"); |
|||
|
|||
System.out.println("百色中学订单总金额统计结果:" + total); |
|||
} |
|||
|
|||
@Test |
|||
void testBszxOrderTotalPerformance() { |
|||
// 测试性能
|
|||
long startTime = System.currentTimeMillis(); |
|||
|
|||
BigDecimal total = bszxPayService.total(); |
|||
|
|||
long endTime = System.currentTimeMillis(); |
|||
long duration = endTime - startTime; |
|||
|
|||
System.out.println("百色中学订单总金额统计耗时:" + duration + "ms"); |
|||
System.out.println("统计结果:" + total); |
|||
|
|||
// 验证查询时间在合理范围内(小于5秒)
|
|||
assertTrue(duration < 5000, "查询时间应该在5秒以内"); |
|||
} |
|||
} |
@ -0,0 +1,56 @@ |
|||
package com.gxwebsoft.shop; |
|||
|
|||
import com.gxwebsoft.shop.service.ShopOrderService; |
|||
import org.junit.jupiter.api.Test; |
|||
import org.springframework.boot.test.context.SpringBootTest; |
|||
import org.springframework.test.context.ActiveProfiles; |
|||
|
|||
import javax.annotation.Resource; |
|||
import java.math.BigDecimal; |
|||
|
|||
import static org.junit.jupiter.api.Assertions.*; |
|||
|
|||
/** |
|||
* 订单总金额统计测试 |
|||
* |
|||
* @author 科技小王子 |
|||
* @since 2025-07-30 |
|||
*/ |
|||
@SpringBootTest |
|||
@ActiveProfiles("test") |
|||
public class OrderTotalTest { |
|||
|
|||
@Resource |
|||
private ShopOrderService shopOrderService; |
|||
|
|||
@Test |
|||
void testOrderTotal() { |
|||
// 测试订单总金额统计
|
|||
BigDecimal total = shopOrderService.total(); |
|||
|
|||
// 验证返回值不为null
|
|||
assertNotNull(total, "订单总金额不应该为null"); |
|||
|
|||
// 验证返回值大于等于0
|
|||
assertTrue(total.compareTo(BigDecimal.ZERO) >= 0, "订单总金额应该大于等于0"); |
|||
|
|||
System.out.println("订单总金额统计结果:" + total); |
|||
} |
|||
|
|||
@Test |
|||
void testOrderTotalPerformance() { |
|||
// 测试性能
|
|||
long startTime = System.currentTimeMillis(); |
|||
|
|||
BigDecimal total = shopOrderService.total(); |
|||
|
|||
long endTime = System.currentTimeMillis(); |
|||
long duration = endTime - startTime; |
|||
|
|||
System.out.println("订单总金额统计耗时:" + duration + "ms"); |
|||
System.out.println("统计结果:" + total); |
|||
|
|||
// 验证查询时间在合理范围内(小于5秒)
|
|||
assertTrue(duration < 5000, "查询时间应该在5秒以内"); |
|||
} |
|||
} |
Loading…
Reference in new issue