在Java企业级开发中,一个功能模块的完成通常需要频繁切换多个工具:用Na vicat或DataGrip建表、在IDEA中编写接口代码、在Swagger编辑器中补充文档注解、用JUnit编写测试用例——每个环节都有各自的上下文和操作方式。工具链的频繁切换不仅消耗时间,也增加了遗漏和出错的概率。
飞算Ja vaAI(Java AI辅助开发工具)的核心思路是:在单一入口内完成从数据库设计、接口文档到单元测试的全链路产出。本文以「用户订单系统的尾款支付与优惠券改造」为真实场景,详细演示这一工作流。
实战场景:用户订单系统的「尾款 + 优惠券」改造
需求输入(飞算Ja vaAI → 智能会话 → Ja va Chat):
在现有订单系统中新增尾款支付功能:
- 订单支持「部分退款」,允许用户退订单一笔的不需要商品
- 退款金额需扣除已使用的优惠券金额
- 优惠券支持「满减券」和「折扣券」两种类型
- 订单退款后,优惠券需要退回用户账户(一次性券除外)
- 所有退款操作记录到退款流水表
- 订单新增「尾款状态」字段:未支付尾款/尾款已支付/尾款已退款
飞算Ja vaAI的智能会话即刻分析需求,并自动产出结果。
Step 1:数据库表结构设计
AI自动分析需求中的实体关系,并生成标准的DDL语句:
新增表:退款流水表
-- 退款流水表
CREATE TABLE `refund_record` ( `id` BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键', `refund_no` VARCHAR(32) NOT NULL UNIQUE COMMENT '退款编号', `order_id` BIGINT NOT NULL COMMENT '关联订单ID', `order_item_id` BIGINT COMMENT '关联订单明细ID(部分退款时指定)', `refund_amount` DECIMAL(10,2) NOT NULL COMMENT '退款金额(元)', `coupon_deduction` DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT '优惠券抵扣金额', `refund_type` VARCHAR(20) NOT NULL COMMENT '退款类型:FULL-全额退款 PARTIAL-部分退款', `reason` VARCHAR(500) COMMENT '退款原因', `status` VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT '退款状态', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_order_id (order_id), INDEX idx_refund_no (refund_no), INDEX idx_status_time (status, create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='退款流水表';
变更表:订单表新增字段
ALTER TABLE `order` ADD COLUMN `balance_status` VARCHAR(20) NOT NULL DEFAULT 'NO_BALANCE'
COMMENT '尾款状态:NO_BALANCE-无尾款 PENDING-未支付 PAID-已支付 REFUNDED-已退款', ADD COLUMN `balance_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00
COMMENT '尾款金额', ADD COLUMN `total_coupon_deduction` DECIMAL(10,2) NOT NULL DEFAULT 0.00
COMMENT '总优惠券抵扣金额', ADD INDEX idx_balance_status (balance_status);
新增表:优惠券退回记录表
CREATE TABLE `coupon_return_record` ( `id` BIGINT AUTO_INCREMENT PRIMARY KEY, `refund_id` BIGINT NOT NULL COMMENT '关联退款ID', `coupon_id` BIGINT NOT NULL COMMENT '关联优惠券ID', `coupon_type` VARCHAR(20) NOT NULL COMMENT '优惠券类型:FULL_REDUCTION-满减 PERCENTAGE-折扣', `return_status` VARCHAR(20) NOT NULL DEFAULT 'RETURNED', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX idx_refund_id (refund_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='优惠券退回记录表';
每个字段都包含中文注释(COMMENT),每个索引都有明确的设计依据,每个默认值都对应具体的业务含义,确保数据库设计清晰可维护。
Step 2:API接口文档自动生成
飞算Ja vaAI自动生成带有完整Swagger注解的Controller类,实现接口文档与代码同步产出:
退款核心接口
@RestController
@RequestMapping("/api/orders")
@Tag(name = "订单退款", description = "订单退款相关接口")
public class OrderRefundController {
@Autowired private OrderRefundService orderRefundService;
/** * 部分退款 */ @PostMapping("/{orderId}/partial-refund") @Operation(summary = "部分退款",
description = "退订一笔中指定的商品项,退款金额扣除已使用优惠券") @Parameters({
@Parameter(name = "orderId", description = "订单ID", required = true) }) public Result partialRefund( @PathVariable Long orderId, @Valid @RequestBody PartialRefundDTO dto) {
RefundVO result = orderRefundService.processPartialRefund(orderId, dto);
return Result.success(result); }
/** * 查询退款记录 */ @GetMapping("/{orderId}/refunds") @Operation(summary = "查询订单退款记录",
description = "按订单ID查询所有退款流水,支持分页") public Result> listRefunds( @PathVariable Long orderId, @Parameter(description = "页码") @RequestParam(defaultValue = "1") int page, @Parameter(description = "每页大小") @RequestParam(defaultValue = "20") int size) {
return Result.success(orderRefundService.listRefunds(orderId, page, size)); }
}
DTO注解自动生成
@Data
public class PartialRefundDTO {
@NotNull(message = "退款商品项ID不能为空") @ApiModelProperty(value = "退款商品项ID(订单明细ID)", required = true) private Long orderItemId;
@DecimalMin(value = "0.01", message = "退款金额不能小于0.01") @ApiModelProperty(value = "退款金额(元)", required = true, example = "29.90") private BigDecimal refundAmount;
@Size(max = 500, message = "退款原因不超过500字") @ApiModelProperty(value = "退款原因", example = "尺寸不合适") private String reason;
}
Swagger文档效果展示:项目启动后,访问本地Swagger页面(默认路径为 /doc.html,具体端口请参考启动日志)即可查看完整接口文档。
- 接口分组:订单退款相关接口
- 接口路径:
POST /api/orders/{orderId}/partial-refund - 参数说明:每个字段均标注中文含义及校验规则
- 请求示例:AI自动生成Mock请求体
- 响应示例:包含退款编号、状态的完整响应体
在常规开发流程中,开发人员写完接口后还需逐个补充@ApiModelProperty等注解,通常需要额外时间。而飞算Ja vaAI在生成代码的同时自动完成文档注解,真正做到代码完成即文档就绪,大幅提升效率。
Step 3:单元测试自动生成(覆盖完整场景)
飞算Ja vaAI的AI工具箱中的「单元测试生成器」能够自动检测测试框架(JUnit 5 + Mockito),并生成覆盖正常、异常、边界三类场景的全面测试用例:
退款服务单元测试
@ExtendWith(MockitoExtension.class)
@DisplayName("订单部分退款服务测试")
class OrderRefundServiceTest {
@Mock private OrderMapper orderMapper; @Mock private RefundRecordMapper refundRecordMapper; @Mock private CouponService couponService; @Mock private AccountService accountService;
@InjectMocks private OrderRefundServiceImpl orderRefundService;
// ========== 正常场景 ==========
@Test @DisplayName("部分退款:单个商品项退款成功") void shouldProcessPartialRefundSuccessfully() {
// Given
Long orderId = 1L;
Long orderItemId = 101L;
Order order = buildOrder(orderId, "PAID", 99.00);
OrderItem orderItem = buildOrderItem(orderItemId, 29.90);
PartialRefundDTO dto = buildRefundDTO(orderItemId, 29.90);
when(orderMapper.selectById(orderId)).thenReturn(order);
when(orderMapper.selectOrderItem(orderItemId)).thenReturn(orderItem);
when(couponService.calculateDeduction(any())).thenReturn(BigDecimal.valueOf(5.00));
doNothing().when(accountService).refund(any());
when(refundRecordMapper.insert(any())).thenReturn(1);
// When
RefundVO result = orderRefundService.processPartialRefund(orderId, dto);
// Then
assertNotNull(result);
assertEquals(BigDecimal.valueOf(24.90), result.getActualRefundAmount()); // 29.90 - 5.00
assertEquals("PARTIAL", result.getRefundType());
verify(couponService).returnCoupon(anyLong()); // 验证优惠券退回被调用 }
// ========== 异常场景 ==========
@Test @DisplayName("订单状态不是已支付,拒绝退款") void shouldRejectRefundWhenOrderNotPaid() {
Long orderId = 1L;
Order order = buildOrder(orderId, "PENDING", 99.00);
when(orderMapper.selectById(orderId)).thenReturn(order);
BusinessException ex = assertThrows(BusinessException.class,
() -> orderRefundService.processPartialRefund(orderId, buildRefundDTO(101L, 29.90)));
assertEquals("ORDER_NOT_PAID", ex.getErrorCode());
assertEquals("订单未支付,无法退款", ex.getMessage()); }
@Test @DisplayName("退款金额超过商品原价,拒绝退款") void shouldRejectRefundWhenAmountExceedsPrice() {
Long orderId = 1L;
Order order = buildOrder(orderId, "PAID", 99.00);
OrderItem orderItem = buildOrderItem(101L, 29.90);
when(orderMapper.selectById(orderId)).thenReturn(order);
when(orderMapper.selectOrderItem(101L)).thenReturn(orderItem);
BusinessException ex = assertThrows(BusinessException.class,
() -> orderRefundService.processPartialRefund(orderId, buildRefundDTO(101L, 50.00)));
assertEquals("REFUND_AMOUNT_EXCEEDS", ex.getErrorCode()); }
// ========== 边界场景 ==========
@Test @DisplayName("退完所有商品项后,订单状态变更为已关闭") void shouldCloseOrderWhenAllItemsRefunded() {
Long orderId = 1L;
Order order = buildOrder(orderId, "PAID", 99.00);
when(orderMapper.selectById(orderId)).thenReturn(order);
when(orderMapper.selectOrderItem(anyLong())).thenReturn(buildOrderItem(101L, 29.90));
when(orderMapper.countRemainingItems(orderId)).thenReturn(0);
orderRefundService.processPartialRefund(orderId, buildRefundDTO(101L, 29.90));
verify(orderMapper).updateStatus(orderId, "CLOSED"); }
@Test @DisplayName("一次性优惠券退款后不退回") void shouldNotReturnOneTimeCouponAfterRefund() {
Long orderId = 1L;
Order order = buildOrder(orderId, "PAID", 99.00);
Coupon coupon = buildCoupon(1L, "FULL_REDUCTION", true); // isOneTime = true
when(orderMapper.selectById(orderId)).thenReturn(order);
when(orderMapper.selectOrderItem(anyLong())).thenReturn(buildOrderItem(101L, 29.90));
when(couponService.getOrderCoupon(orderId)).thenReturn(coupon);
orderRefundService.processPartialRefund(orderId, buildRefundDTO(101L, 29.90));
verify(couponService, never()).returnCoupon(anyLong()); // 一次性券不退回 }
// ========== 测试数据构建 ==========
private Order buildOrder(Long id, String status, double amount) {
Order order = new Order();
order.setId(id);
order.setStatus(status);
order.setTotalAmount(BigDecimal.valueOf(amount));
return order; }
private OrderItem buildOrderItem(Long id, double price) {
OrderItem item = new OrderItem();
item.setId(id);
item.setUnitPrice(BigDecimal.valueOf(price));
return item; }
private PartialRefundDTO buildRefundDTO(Long orderItemId, double amount) {
PartialRefundDTO dto = new PartialRefundDTO();
dto.setOrderItemId(orderItemId);
dto.setRefundAmount(BigDecimal.valueOf(amount));
dto.setReason("测试退款");
return dto; }
}
测试覆盖范围:
- 正常退款流程:验证金额计算与优惠券退回逻辑
- 订单状态校验异常处理
- 金额越界检查与拒绝
- 全部退款后订单自动关闭
- 一次性优惠券退款后不退回的业务规则
各环节效率对比:飞算Ja vaAI vs 常规方式
| 步骤 | 常规方式 | 使用飞算Ja vaAI |
|---|---|---|
| 数据库设计(DDL+ALTER) | 手动编写,耗时约30分钟 | AI自动生成,耗时约1分钟 |
| 接口开发(Controller+Service+DTO) | 手动编码,耗时约60分钟 | AI自动生成,耗时约3分钟 |
| Swagger文档(注解+示例) | 逐个字段标注,耗时约30分钟 | 与代码同步生成 |
| 单元测试(正常+异常+边界) | 手动编写,耗时约60分钟 | 五步闭环自动生成,耗时约2分钟 |
| 代码Review+修改 | 自查修改,耗时约30分钟 | AI工具箱整洁+安全扫描,耗时约2分钟 |
飞算Ja vaAI的全链路价值不仅体现在单一环节的速度提升,更在于将多个工具链的切换成本彻底压缩到单一入口内,实现一站式开发体验。

