飞算JavaAI高效开发电商核心功能模块实战
一、飞算 Ja vaAI 电商开发环境准备
1.1 开发环境配置
打开IDEA,戳进插件市场(快捷键:Ctrl+Alt+S),搜索“CalEx-Ja vaAI”或“飞算”,安装完成后重启,登录飞算就行。
1.2 核心技术栈说明
| 技术组件 | 版本 | 飞算 Ja vaAI 支持能力 |
|---|---|---|
| Spring Boot | 2.7.10 | 自动生成启动类、配置类 |
| MyBatis-Plus | 3.5.3.1 | 逆向工程生成实体类、Mapper 接口 |
| Redis | 6.2.8 | 缓存注解自动生成、分布式锁实现 |
| RocketMQ | 4.9.4 | 消息生产者/消费者模板代码生成 |
| Spring Security | 5.6.10 | 权限拦截器、JWT 工具类自动生成 |
二、商品管理模块开发(核心功能)
商品管理模块是电商系统的底座,包含商品CRUD、库存管理、分类查询等功能。飞算Ja vaAI的亮点在于,你只要用自然语言描述需求,它就能直接转成核心业务代码。2.1 需求定义与 AI 代码生成
在飞算Ja vaAI的“智能开发”面板里输入需求:
飞算Ja vaAI会自动完成这些事:
1. 生成商品相关的数据库表结构(SQL脚本)
2. 创建实体类、DTO、VO对象
3. 实现Service层核心业务逻辑(含参数校验、异常处理)
4. 生成Controller层API接口(含Swagger文档注解)
2.2 核心代码实现(飞算 Ja vaAI 自动生成)
2.2.1 数据库表结构(自动生成 SQL)
-- 商品表
CREATE TABLE `product` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '商品ID',
`product_name` varchar(200) NOT NULL COMMENT '商品名称',
`category_id` bigint NOT NULL COMMENT '分类ID',
`price` decimal(10,2) NOT NULL COMMENT '商品价格',
`stock` int NOT NULL DEFAULT '0' COMMENT '库存数量',
`status` tinyint NOT NULL DEFAULT '1' COMMENT '状态:0-下架,1-上架',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_product_name` (`product_name`),
KEY `idx_category_id` (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表';
-- 商品分类表
CREATE TABLE `product_category` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '分类ID',
`category_name` varchar(100) NOT NULL COMMENT '分类名称',
`parent_id` bigint NOT NULL DEFAULT '0' COMMENT '父分类ID',
`sort` int NOT NULL DEFAULT '0' COMMENT '排序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品分类表';
2.2.2 实体类与 DTO(自动生成)
// 商品实体类
@NoArgsConstructor
@Data
@TableName("product")
public class Product {
@TableId(type = IdType.AUTO)
private Long id;
@NotBlank(message = "商品名称不能为空")
private String productName;
@NotNull(message = "分类ID不能为空")
private Long categoryId;
@DecimalMin(value = "0.01", message = "商品价格必须大于0")
private BigDecimal price;
@Min(value = 0, message = "库存数量不能为负数")
private Integer stock;
private Integer status;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
// 商品新增DTO(实际使用中请用Lombok的@AllArgsConstructor等,此处简化)
@Data
public class ProductAddDTO {
@NotBlank(message = "商品名称不能为空")
private String productName;
@NotNull(message = "分类ID不能为空")
private Long categoryId;
@DecimalMin(value = "0.01", message = "商品价格必须大于0")
private BigDecimal price;
@Min(value = 0, message = "库存数量不能为负数")
private Integer stock;
}
2.2.3 Service 层核心逻辑(含 AI 优化)
@Service
@RequiredArgsConstructor
public class ProductServiceImpl extends ServiceImpl implements ProductService {
private final ProductMapper productMapper;
private final RedissonClient redissonClient;
/**
* 新增商品(飞算Ja vaAI自动生成,含唯一性校验)
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean addProduct(ProductAddDTO dto) {
// 1. 验证商品名称唯一性(使用Redis分布式锁防止并发问题)
RLock lock = redissonClient.getLock("product:name:lock:" + dto.getProductName());
lock.lock(5, TimeUnit.SECONDS);
try {
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Product::getProductName, dto.getProductName());
if (baseMapper.exists(queryWrapper)) {
throw new BusinessException("商品名称已存在");
}
// 2. 转换DTO为实体类并保存
Product product = new Product();
BeanUtils.copyProperties(dto, product);
product.setStatus(1); // 默认上架状态
return sa ve(product);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
/**
* 库存扣减(飞算Ja vaAI自动生成,含库存校验与乐观锁)
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deductStock(Long productId, Integer quantity) {
// 使用MyBatis-Plus乐观锁实现库存扣减,防止超卖
Product product = getById(productId);
if (product == null) {
throw new BusinessException("商品不存在");
}
if (product.getStock() < quantity) {
throw new BusinessException("库存不足,当前库存:" + product.getStock());
}
Product updateProduct = new Product();
updateProduct.setId(productId);
updateProduct.setStock(product.getStock() - quantity);
// 乐观锁版本控制(需在实体类中添加@Version注解)
updateProduct.setVersion(product.getVersion());
int rows = baseMapper.updateById(updateProduct);
if (rows == 0) {
// 库存扣减失败,重试机制(飞算Ja vaAI自动添加)
throw new RetryException("库存扣减冲突,请重试");
}
return true;
}
/**
* 按分类分页查询商品(飞算Ja vaAI自动生成,含VO转换)
*/
@Override
public IPage getProductByCategory(ProductQueryDTO dto) {
// 分页查询(飞算Ja vaAI自动生成分页逻辑)
Page page = new Page<>(dto.getPageNum(), dto.getPageSize());
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Product::getCategoryId, dto.getCategoryId())
.eq(Product::getStatus, 1) // 只查询上架商品
.orderByDesc(Product::getCreateTime);
IPage productPage = baseMapper.selectPage(page, queryWrapper);
// 转换为VO返回(飞算Ja vaAI自动生成VO转换逻辑)
return productPage.convert(product -> {
ProductVO vo = new ProductVO();
BeanUtils.copyProperties(product, vo);
// 补充分类名称(飞算Ja vaAI自动关联分类表查询)
ProductCategory category = categoryMapper.selectById(product.getCategoryId());
vo.setCategoryName(category != null ? category.getCategoryName() : "未知分类");
return vo;
});
}
}
2.2.4 Controller 层 API(含 Swagger 文档)
@RestController
@RequestMapping("/api/v1/product")
@RequiredArgsConstructor
@Tag(name = "商品管理接口", description = "电商商品CRUD、库存管理接口")
public class ProductController {
private final ProductService productService;
@PostMapping("/add")
@Operation(summary = "新增商品", description = "新增商品,需保证商品名称唯一性")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "成功"),
@ApiResponse(responseCode = "400", description = "参数错误:商品名称为空/价格小于0等"),
@ApiResponse(responseCode = "500", description = "服务器错误")
})
public Result addProduct(@Valid @RequestBody ProductAddDTO dto) {
return Result.success(productService.addProduct(dto));
}
@PostMapping("/deduct-stock")
@Operation(summary = "库存扣减", description = "下单时扣减商品库存,返回是否成功")
public Result deductStock(@RequestParam Long productId, @RequestParam Integer quantity) {
return Result.success(productService.deductStock(productId, quantity));
}
@GetMapping("/list-by-category")
@Operation(summary = "按分类分页查询商品", description = "查询指定分类下的上架商品,支持分页")
public Result> getProductByCategory(ProductQueryDTO dto) {
return Result.success(productService.getProductByCategory(dto));
}
}
2.3 API 接口说明(飞算 Ja vaAI 自动生成文档)
| 接口路径 | 请求方式 | 功能描述 | 请求参数 | 响应示例 |
|---|---|---|---|---|
/api/v1/product/add | POST | 新增商品 | {"productName":"iPhone 14","categoryId":1,"price":5999.00,"stock":100} | {"code":200,"msg":"success","data":true} |
/api/v1/product/deduct-stock | POST | 库存扣减 | productId=1&quantity=2 | {"code":200,"msg":"success","data":true} |
/api/v1/product/list-by-category | GET | 分类分页查询 | categoryId=1&pageNum=1&pageSize=10 | {"code":200,"msg":"success","data":{"records":[{"id":1,"productName":"iPhone 14","categoryName":"手机","price":5999.00,"stock":98}],"total":1,"size":10,"current":1}} |
三、订单管理模块开发(高并发场景)
订单模块是电商系统的核心交易环节,涉及订单创建、状态流转、超时关闭等关键功能。飞算Ja vaAI针对高并发场景,提供了自动化的解决方案,从架构设计到代码落地一气呵成。3.1 核心功能设计
基于飞算Ja vaAI的“架构设计助手”,订单模块采用了分层设计: - **订单状态机**:自动生成订单状态流转逻辑(待付款→已付款→已发货→已完成→已取消) - **分布式事务**:使用Seata实现订单创建与库存扣减的分布式事务一致性 - **超时处理**:基于RocketMQ延迟队列实现订单超时自动关闭3.2 核心代码实现(飞算 Ja vaAI 生成)
3.2.1 订单 Service 层核心逻辑
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl implements OrderService {
private final ProductService productService;
private final OrderItemService orderItemService;
private final RocketMQTemplate rocketMQTemplate;
private final IdGenerator idGenerator; // 飞算Ja vaAI自动集成雪花ID生成器
/**
* 创建订单(飞算Ja vaAI自动生成,含分布式事务)
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class) // Seata分布式事务注解
public OrderVO createOrder(OrderCreateDTO dto) {
// 1. 生成订单号(雪花ID)
String orderNo = idGenerator.nextIdStr();
// 2. 扣减商品库存(调用商品服务)
boolean deductResult = productService.deductStock(dto.getProductId(), dto.getQuantity());
if (!deductResult) {
throw new BusinessException("库存扣减失败");
}
// 3. 查询商品信息
Product product = productService.getById(dto.getProductId());
if (product == null) {
throw new BusinessException("商品不存在");
}
// 4. 创建订单主表
Order order = new Order();
order.setOrderNo(orderNo);
order.setUserId(dto.getUserId());
order.setTotalAmount(product.getPrice().multiply(new BigDecimal(dto.getQuantity())));
order.setPayAmount(order.getTotalAmount());
order.setOrderStatus(1); // 1-待付款
order.setPayStatus(0); // 0-未支付
sa ve(order);
// 5. 创建订单明细表
OrderItem orderItem = new OrderItem();
orderItem.setOrderId(order.getId());
orderItem.setProductId(product.getId());
orderItem.setProductName(product.getProductName());
orderItem.setUnitPrice(product.getPrice());
orderItem.setQuantity(dto.getQuantity());
orderItem.setTotalPrice(order.getTotalAmount());
orderItemService.sa ve(orderItem);
// 6. 发送延迟消息(订单超时关闭,延迟30分钟)
sendOrderTimeoutMsg(orderNo);
// 7. 转换为VO返回
OrderVO orderVO = new OrderVO();
BeanUtils.copyProperties(order, orderVO);
orderVO.setOrderItemList(Collections.singletonList(orderItem));
return orderVO;
}
/**
* 发送订单超时消息(飞算Ja vaAI自动生成延迟队列逻辑)
*/
private void sendOrderTimeoutMsg(String orderNo) {
OrderTimeoutMsg msg = new OrderTimeoutMsg();
msg.setOrderNo(orderNo);
msg.setCreateTime(LocalDateTime.now());
// 发送延迟消息(RocketMQ延迟级别:18代表30分钟)
rocketMQTemplate.syncSend(
"order-timeout-topic",
MessageBuilder.withPayload(msg).build(),
3000,
18
);
}
/**
* 订单超时关闭(飞算Ja vaAI自动生成消费者逻辑)
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void closeOrderTimeout(String orderNo) {
// 查询订单(只处理待付款状态的订单)
LambdaQueryWrapper> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Order::getOrderNo, orderNo)
.eq(Order::getOrderStatus, 1) // 1-待付款
.eq(Order::getPayStatus, 0); // 0-未支付
Order order = getOne(queryWrapper);
if (order == null) {
log.info("订单已处理,无需关闭:{}", orderNo);
return;
}
// 更新订单状态为已取消
Order updateOrder = new Order();
updateOrder.setId(order.getId());
updateOrder.setOrderStatus(5); // 5-已取消
updateOrder.setCancelTime(LocalDateTime.now());
updateById(updateOrder);
// 7. 恢复商品库存(订单取消后回补库存)
OrderItem orderItem = orderItemService.getOne(
new LambdaQueryWrapper().eq(OrderItem::getOrderId, order.getId()));
if (orderItem != null) {
productService.recoverStock(orderItem.getProductId(), orderItem.getQuantity());
log.info("订单超时关闭,库存已恢复:订单号={}, 商品ID={}, 恢复数量={}",
orderNo, orderItem.getProductId(), orderItem.getQuantity());
}
}
/**
* 订单状态流转(飞算Ja vaAI自动生成状态机逻辑)
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateOrderStatus(String orderNo, Integer targetStatus) {
// 1. 校验订单状态合法性(基于状态机规则)
Order order = getOne(new LambdaQueryWrapper().eq(Order::getOrderNo, orderNo));
if (order == null) {
throw new BusinessException("订单不存在");
}
// 状态流转规则:待付款(1)→已取消(5)、待付款(1)→已付款(2);已付款(2)→已发货(3);已发货(3)→已完成(4)
Map> statusFlow = new HashMap<>();
statusFlow.put(1, Arrays.asList(2, 5));
statusFlow.put(2, Collections.singletonList(3));
statusFlow.put(3, Collections.singletonList(4));
if (!statusFlow.getOrDefault(order.getOrderStatus(), Collections.emptyList()).contains(targetStatus)) {
throw new BusinessException("非法状态流转:当前状态=" + order.getOrderStatus() + ", 目标状态=" + targetStatus);
}
// 2. 更新订单状态
Order updateOrder = new Order();
updateOrder.setId(order.getId());
updateOrder.setOrderStatus(targetStatus);
// 补充状态变更相关时间
if (targetStatus == 2) { // 已付款
updateOrder.setPayStatus(1);
updateOrder.setPayTime(LocalDateTime.now());
} else if (targetStatus == 3) { // 已发货
updateOrder.setShipTime(LocalDateTime.now());
} else if (targetStatus == 4) { // 已完成
updateOrder.setFinishTime(LocalDateTime.now());
}
return updateById(updateOrder);
}
}
3.2.2 订单 Controller 层 API(飞算 Ja vaAI 生成)
@RestController
@RequestMapping("/api/v1/order")
@RequiredArgsConstructor
@Tag(name = "订单管理接口", description = "电商订单创建、状态更新、查询接口")
public class OrderController {
private final OrderService orderService;
@PostMapping("/create")
@Operation(summary = "创建订单", description = "用户下单接口,含库存扣减与分布式事务")
public Result createOrder(@Valid @RequestBody OrderCreateDTO dto) {
return Result.success(orderService.createOrder(dto));
}
@PostMapping("/update-status")
@Operation(summary = "更新订单状态", description = "支持待付款→已付款/已取消、已付款→已发货、已发货→已完成")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "成功"),
@ApiResponse(responseCode = "400", description = "非法状态流转/订单不存在")
})
public Result updateOrderStatus(
@RequestParam String orderNo,
@RequestParam Integer targetStatus) {
return Result.success(orderService.updateOrderStatus(orderNo, targetStatus));
}
@GetMapping("/detail")
@Operation(summary = "查询订单详情", description = "根据订单号查询订单主信息与明细")
public Result getOrderDetail(@RequestParam String orderNo) {
return Result.success(orderService.getOrderDetail(orderNo));
}
@GetMapping("/user/list")
@Operation(summary = "用户订单列表", description = "查询指定用户的订单列表,支持分页与状态筛选")
public Result> getUserOrderList(
@RequestParam Long userId,
@RequestParam(required = false) Integer orderStatus,
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize) {
OrderQueryDTO dto = new OrderQueryDTO();
dto.setUserId(userId);
dto.setOrderStatus(orderStatus);
dto.setPageNum(pageNum);
dto.setPageSize(pageSize);
return Result.success(orderService.getUserOrderList(dto));
}
}
3.3 订单模块 API 说明
| 接口路径 | 请求方式 | 功能描述 | 请求参数示例 | 响应示例片段 |
|---|---|---|---|---|
/api/v1/order/create | POST | 创建订单 | {"userId":1001,"productId":1,"quantity":2} | {"code":200,"msg":"success","data":{"orderNo":"1688812345678901234","totalAmount":11998.00,"orderStatus":1,"orderItemList":[...]}} |
/api/v1/order/update-status | POST | 更新订单状态 | orderNo=1688812345678901234&targetStatus=2 | {"code":200,"msg":"success","data":true} |
/api/v1/order/detail | GET | 查询订单详情 | orderNo=1688812345678901234 | {"code":200,"msg":"success","data":{"orderNo":"1688812345678901234","userName":"张三","orderStatus":2,"payTime":"2024-05-20T14:30:00",...}} |
/api/v1/order/user/list | GET | 用户订单列表 | userId=1001&orderStatus=2&pageNum=1&pageSize=10 | {"code":200,"msg":"success","data":{"records":[...],"total":5,"size":10,"current":1}} |
四、支付集成模块开发(安全合规)
支付模块是电商交易的关键闭环,需保障支付安全、资金合规与异步通知处理。飞算Ja vaAI已经内置了主流支付渠道(支付宝、微信支付)的集成模板,从支付流程设计到代码实现,全面覆盖。4.1 支付流程设计
基于飞算Ja vaAI的“支付方案助手”,标准化流程如下: 1. **支付发起**:用户选择支付方式,系统生成支付参数(如支付宝支付链接、微信支付二维码) 2. **支付回调**:支付渠道异步通知支付结果,系统验证签名并更新订单状态 3. **支付查询**:提供主动查询接口,处理异步通知丢失场景 4. **退款处理**:支持订单全额/部分退款,同步更新退款状态4.2 核心代码实现(飞算 Ja vaAI 生成)
4.2.1 支付配置类(自动生成渠道配置)
@Configuration
@ConfigurationProperties(prefix = "pay")
@Data
public class PayConfig {
// 支付宝配置
private AlipayConfig alipay;
// 微信支付配置
private WxPayConfig wxpay;
@Data
public static class AlipayConfig {
private String appId;
private String privateKey;
private String publicKey;
private String notifyUrl; // 异步通知地址
private String returnUrl; // 同步跳转地址
private String charset = "UTF-8";
private String signType = "RSA2";
private String gatewayUrl = "https://openapi.alipay.com/gateway.do";
}
@Data
public static class WxPayConfig {
private String appId;
private String mchId;
private String mchKey;
private String notifyUrl;
private String tradeType = "NATIVE"; // 扫码支付
private String apiKey3; // 微信V3接口密钥
private String certPath; // 商户证书路径
}
}
4.2.2 支付 Service 层核心逻辑
@Service
@RequiredArgsConstructor
public class PayServiceImpl implements PayService {
private final PayConfig payConfig;
private final OrderService orderService;
private final PayRecordService payRecordService;
private final AlipayClient alipayClient; // 飞算Ja vaAI自动注入支付宝客户端
private final WxPayService wxPayService; // 飞算Ja vaAI自动注入微信支付客户端
/**
* 发起支付(飞算Ja vaAI自动生成多渠道适配逻辑)
*/
@Override
@Transactional(rollbackFor = Exception.class)
public PayVO createPay(PayCreateDTO dto) {
// 1. 校验订单状态(仅待付款订单可发起支付)
Order order = orderService.getOne(
new LambdaQueryWrapper()
.eq(Order::getOrderNo, dto.getOrderNo())
.eq(Order::getOrderStatus, 1) // 待付款
);
if (order == null) {
throw new BusinessException("订单不存在或状态不允许支付");
}
// 2. 生成支付记录
PayRecord payRecord = new PayRecord();
payRecord.setPayNo(generatePayNo()); // 生成唯一支付单号
payRecord.setOrderNo(dto.getOrderNo());
payRecord.setUserId(order.getUserId());
payRecord.setPayAmount(order.getPayAmount());
payRecord.setPayType(dto.getPayType()); // 1-支付宝,2-微信支付
payRecord.setPayStatus(0); // 0-未支付
payRecordService.sa ve(payRecord);
// 3. 适配不同支付渠道
if (dto.getPayType() == 1) {
return createAlipay(payRecord, order);
} else if (dto.getPayType() == 2) {
return createWxPay(payRecord, order);
} else {
throw new BusinessException("不支持的支付方式");
}
}
/**
* 支付宝支付参数生成(飞算Ja vaAI自动集成支付宝SDK)
*/
private PayVO createAlipay(PayRecord payRecord, Order order) {
try {
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setReturnUrl(payConfig.getAlipay().getReturnUrl());
request.setNotifyUrl(payConfig.getAlipay().getNotifyUrl());
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", payRecord.getPayNo());
bizContent.put("total_amount", order.getPayAmount().toString());
bizContent.put("subject", "订单支付-" + order.getOrderNo());
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
request.setBizContent(bizContent.toString());
AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
if (response.isSuccess()) {
PayVO payVO = new PayVO();
payVO.setPayNo(payRecord.getPayNo());
payVO.setPayUrl(response.getBody()); // 支付宝支付表单HTML
return payVO;
} else {
throw new BusinessException("支付宝支付参数生成失败:" + response.getMsg());
}
} catch (AlipayApiException e) {
log.error("支付宝支付异常", e);
throw new BusinessException("支付发起失败,请重试");
}
}
/**
* 微信支付参数生成(飞算Ja vaAI自动集成微信支付SDK)
*/
private PayVO createWxPay(PayRecord payRecord, Order order) {
try {
WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
request.setBody("订单支付-" + order.getOrderNo());
request.setOutTradeNo(payRecord.getPayNo());
request.setTotalFee(order.getPayAmount().multiply(new BigDecimal(100)).intValue()); // 金额(分)
request.setSpbillCreateIp(WebUtils.getClientIp());
request.setNotifyUrl(payConfig.getWxpay().getNotifyUrl());
request.setTradeType(payConfig.getWxpay().getTradeType());
WxPayUnifiedOrderResult result = wxPayService.unifiedOrder(request);
if ("SUCCESS".equals(result.getReturnCode()) && "SUCCESS".equals(result.getResultCode())) {
PayVO payVO = new PayVO();
payVO.setPayNo(payRecord.getPayNo());
payVO.setQrCodeUrl(result.getCodeUrl()); // 微信支付二维码地址
return payVO;
} else {
throw new BusinessException("微信支付参数生成失败:" + result.getReturnMsg());
}
} catch (WxPayException e) {
log.error("微信支付异常", e);
throw new BusinessException("支付发起失败,请重试");
}
}
/**
* 支付回调处理(飞算Ja vaAI自动生成签名验证与状态更新逻辑)
*/
@Override
@Transactional(rollbackFor = Exception.class)
public String handlePayNotify(Integer payType, Map params) {
// 1. 签名验证(不同渠道验证逻辑不同)
boolean signValid = false;
if (payType == 1) { // 支付宝回调
try {
signValid = AlipaySignature.rsaCheckV1(
params,
payConfig.getAlipay().getPublicKey(),
payConfig.getAlipay().getCharset(),
payConfig.getAlipay().getSignType()
);
} catch (AlipayApiException e) {
log.error("支付宝回调签名验证失败", e);
return "fail";
}
} else if (payType == 2) { // 微信支付回调
try {
signValid = wxPayService.verifyNotifySign(params);
} catch (WxPayException e) {
log.error("微信支付回调签名验证失败", e);
return "fail";
}
}
if (!signValid) {
log.warn("支付回调签名验证失败:payType={}, params={}", payType, params);
return "fail";
}
// 2. 解析回调参数,更新支付记录与订单状态
String payNo = params.get("out_trade_no"); // 商户支付单号
String tradeNo = params.get(payType == 1 ? "trade_no" : "transaction_id"); // 渠道交易号
String tradeStatus = params.get(payType == 1 ? "trade_status" : "result_code"); // 支付状态
boolean paySuccess = (payType == 1 && "TRADE_SUCCESS".equals(tradeStatus)) ||
(payType == 2 && "SUCCESS".equals(tradeStatus));
if (paySuccess) {
PayRecord payRecord = payRecordService.getOne(
new LambdaQueryWrapper().eq(PayRecord::getPayNo, payNo));
if (payRecord == null || payRecord.getPayStatus() == 1) {
return payType == 1 ? "success" : " ";
}
payRecord.setPayStatus(1); // 1-已支付
payRecord.setTradeNo(tradeNo);
payRecord.setPayTime(LocalDateTime.now());
payRecordService.updateById(payRecord);
// 更新订单状态为已付款
orderService.updateOrderStatus(payRecord.getOrderNo(), 2);
log.info("支付成功,已更新订单状态:payNo={}, orderNo={}", payNo, payRecord.getOrderNo());
}
// 3. 返回回调结果
return payType == 1 ? "success" : " ";
}
/**
* 生成唯一支付单号(雪花ID+支付类型,这里简单实现)
*/
private String generatePayNo() {
return "P" + System.currentTimeMillis() + RandomUtils.nextInt(1000, 9999);
}
/**
* 支付结果查询(飞算Ja vaAI自动生成多渠道查询逻辑)
*/
@Override
public PayStatusVO queryPayStatus(String payNo) {
PayRecord payRecord = payRecordService.getOne(new LambdaQueryWrapper().eq(PayRecord::getPayNo, payNo));
if (payRecord == null) {
throw new BusinessException("支付记录不存在");
}
if (payRecord.getPayStatus() == 1) {
PayStatusVO statusVO = new PayStatusVO();
statusVO.setPayNo(payNo);
statusVO.setOrderNo(payRecord.getOrderNo());
statusVO.setPayStatus(1);
statusVO.setPayTime(payRecord.getPayTime());
statusVO.setTradeNo(payRecord.getTradeNo());
return statusVO;
}
if (payRecord.getPayType() == 1) {
return queryAlipayStatus(payRecord);
} else if (payRecord.getPayType() == 2) {
return queryWxPayStatus(payRecord);
} else {
throw new BusinessException("不支持的支付方式");
}
}
/**
* 支付宝支付状态查询
*/
private PayStatusVO queryAlipayStatus(PayRecord payRecord) {
try {
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", payRecord.getPayNo());
request.setBizContent(bizContent.toString());
AlipayTradeQueryResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
PayStatusVO statusVO = new PayStatusVO();
statusVO.setPayNo(payRecord.getPayNo());
statusVO.setOrderNo(payRecord.getOrderNo());
String tradeStatus = response.getTradeStatus();
statusVO.setPayStatus("TRADE_SUCCESS".equals(tradeStatus) ? 1 : 0);
if ("TRADE_SUCCESS".equals(tradeStatus)) {
statusVO.setPayTime(LocalDateTime.parse(response.getGmtPayment(),
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
statusVO.setTradeNo(response.getTradeNo());
// 更新本地支付记录状态
payRecord.setPayStatus(1);
payRecord.setTradeNo(response.getTradeNo());
payRecord.setPayTime(statusVO.getPayTime());
payRecordService.updateById(payRecord);
orderService.updateOrderStatus(payRecord.getOrderNo(), 2);
}
return statusVO;
} else {
throw new BusinessException("支付宝状态查询失败:" + response.getMsg());
}
} catch (AlipayApiException e) {
log.error("支付宝查询异常", e);
throw new BusinessException("支付状态查询失败,请重试");
}
}
/**
* 微信支付状态查询
*/
private PayStatusVO queryWxPayStatus(PayRecord payRecord) {
try {
WxPayOrderQueryRequest request = new WxPayOrderQueryRequest();
request.setOutTradeNo(payRecord.getPayNo());
WxPayOrderQueryResult result = wxPayService.queryOrder(request);
if ("SUCCESS".equals(result.getReturnCode()) && "SUCCESS".equals(result.getResultCode())) {
PayStatusVO statusVO = new PayStatusVO();
statusVO.setPayNo(payRecord.getPayNo());
statusVO.setOrderNo(payRecord.getOrderNo());
statusVO.setPayStatus("SUCCESS".equals(result.getTradeState()) ? 1 : 0);
if ("SUCCESS".equals(result.getTradeState())) {
statusVO.setPayTime(LocalDateTime.parse(result.getTimeEnd(),
DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
statusVO.setTradeNo(result.getTransactionId());
payRecord.setPayStatus(1);
payRecord.setTradeNo(result.getTransactionId());
payRecord.setPayTime(statusVO.getPayTime());
payRecordService.updateById(payRecord);
orderService.updateOrderStatus(payRecord.getOrderNo(), 2);
}
return statusVO;
} else {
throw new BusinessException("微信支付状态查询失败:" + result.getReturnMsg());
}
} catch (WxPayException e) {
log.error("微信支付查询异常", e);
throw new BusinessException("支付状态查询失败,请重试");
}
}
/**
* 订单退款(飞算Ja vaAI自动生成多渠道退款逻辑)
*/
@Override
@Transactional(rollbackFor = Exception.class)
public RefundVO createRefund(RefundCreateDTO dto) {
// 1. 校验订单与支付记录状态
Order order = orderService.getOne(
new LambdaQueryWrapper()
.eq(Order::getOrderNo, dto.getOrderNo())
.eq(Order::getOrderStatus, 2)); // 仅已付款订单可退款
if (order == null) {
throw new BusinessException("订单不存在或状态不允许退款");
}
PayRecord payRecord = payRecordService.getOne(
new LambdaQueryWrapper()
.eq(PayRecord::getOrderNo, dto.getOrderNo())
.eq(PayRecord::getPayStatus, 1)); // 已支付
if (payRecord == null) {
throw new BusinessException("支付记录不存在,无法退款");
}
// 2. 校验退款金额
if (dto.getRefundAmount().compareTo(payRecord.getPayAmount()) > 0) {
throw new BusinessException("退款金额不能超过支付金额:" + payRecord.getPayAmount());
}
// 3. 生成退款记录
RefundRecord refundRecord = new RefundRecord();
refundRecord.setRefundNo(generateRefundNo());
refundRecord.setOrderNo(dto.getOrderNo());
refundRecord.setPayNo(payRecord.getPayNo());
refundRecord.setRefundAmount(dto.getRefundAmount());
refundRecord.setRefundReason(dto.getRefundReason());
refundRecord.setRefundStatus(0); // 0-退款中
refundRecordService.sa ve(refundRecord);
// 4. 调用渠道退款接口
if (payRecord.getPayType() == 1) {
return createAlipayRefund(refundRecord, payRecord);
} else if (payRecord.getPayType() == 2) {
return createWxPayRefund(refundRecord, payRecord);
} else {
throw new BusinessException("不支持的支付方式");
}
}
/**
* 支付宝退款
*/
private RefundVO createAlipayRefund(RefundRecord refundRecord, PayRecord payRecord) {
try {
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", payRecord.getPayNo());
bizContent.put("out_request_no", refundRecord.getRefundNo());
bizContent.put("refund_amount", refundRecord.getRefundAmount().toString());
bizContent.put("refund_reason", refundRecord.getRefundReason());
request.setBizContent(bizContent.toString());
AlipayTradeRefundResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
RefundVO refundVO = new RefundVO();
refundVO.setRefundNo(refundRecord.getRefundNo());
refundVO.setOrderNo(refundRecord.getOrderNo());
refundVO.setRefundAmount(refundRecord.getRefundAmount());
refundVO.setRefundStatus(1); // 1-退款成功
refundVO.setRefundTime(LocalDateTime.now());
refundVO.setTradeNo(response.getTradeNo());
refundVO.setRefundTradeNo(response.getRefundTradeNo());
// 更新退款记录状态
refundRecord.setRefundStatus(1);
refundRecord.setRefundTime(refundVO.getRefundTime());
refundRecord.setRefundTradeNo(response.getRefundTradeNo());
refundRecordService.updateById(refundRecord);
// 更新订单状态为已退款
orderService.updateOrderStatus(refundRecord.getOrderNo(), 6); // 6-已退款
return refundVO;
} else {
throw new BusinessException("支付宝退款失败:" + response.getMsg());
}
} catch (AlipayApiException e) {
log.error("支付宝退款异常", e);
refundRecord.setRefundStatus(2); // 2-退款失败
refundRecord.setFailReason(e.getMessage());
refundRecordService.updateById(refundRecord);
throw new BusinessException("退款发起失败,请重试");
}
}
/**
* 微信支付退款
*/
private RefundVO createWxPayRefund(RefundRecord refundRecord, PayRecord payRecord) {
try {
WxPayRefundRequest request = new WxPayRefundRequest();
request.setOutTradeNo(payRecord.getPayNo());
request.setOutRefundNo(refundRecord.getRefundNo());
request.setTotalFee(payRecord.getPayAmount().multiply(new BigDecimal(100)).intValue());
request.setRefundFee(refundRecord.getRefundAmount().multiply(new BigDecimal(100)).intValue());
request.setRefundDesc(refundRecord.getRefundReason());
WxPayRefundResult result = wxPayService.refund(request);
if ("SUCCESS".equals(result.getReturnCode()) && "SUCCESS".equals(result.getResultCode())) {
RefundVO refundVO = new RefundVO();
refundVO.setRefundNo(refundRecord.getRefundNo());
refundVO.setOrderNo(refundRecord.getOrderNo());
refundVO.setRefundAmount(refundRecord.getRefundAmount());
refundVO.setRefundStatus(1);
refundVO.setRefundTime(LocalDateTime.now());
refundVO.setTradeNo(result.getTransactionId());
refundVO.setRefundTradeNo(result.getRefundId());
refundRecord.setRefundStatus(1);
refundRecord.setRefundTime(refundVO.getRefundTime());
refundRecord.setRefundTradeNo(result.getRefundId());
refundRecordService.updateById(refundRecord);
orderService.updateOrderStatus(refundRecord.getOrderNo(), 6);
return refundVO;
} else {
throw new BusinessException("微信支付退款失败:" + result.getReturnMsg());
}
} catch (WxPayException e) {
log.error("微信支付退款异常", e);
refundRecord.setRefundStatus(2);
refundRecord.setFailReason(e.getMessage());
refundRecordService.updateById(refundRecord);
throw new BusinessException("退款发起失败,请重试");
}
}
/**
* 生成唯一退款单号
*/
private String generateRefundNo() {
return "R" + System.currentTimeMillis() + RandomUtils.nextInt(1000, 9999);
}
}
4.2.3 支付 Controller 层 API(飞算 Ja vaAI 生成)
@RestController
@RequestMapping("/api/v1/pay")
@RequiredArgsConstructor
@Tag(name = "支付管理接口", description = "电商支付发起、回调、查询、退款接口")
public class PayController {
private final PayService payService;
@PostMapping("/create")
@Operation(summary = "发起支付", description = "支持支付宝(1)、微信支付(2),返回支付参数")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "成功"),
@ApiResponse(responseCode = "400", description = "订单状态异常/不支持的支付方式")
})
public Result createPay(@Valid @RequestBody PayCreateDTO dto) {
return Result.success(payService.createPay(dto));
}
@PostMapping("/notify/alipay")
@Operation(summary = "支付宝支付回调", description = "支付宝异步通知支付结果,需返回success/fail")
public String alipayNotify(HttpServletRequest request) {
Map params = new HashMap<>();
Enumeration parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
String name = parameterNames.nextElement();
params.put(name, request.getParameter(name));
}
return payService.handlePayNotify(1, params);
}
@PostMapping("/notify/wxpay")
@Operation(summary = "微信支付回调", description = "微信支付异步通知支付结果,需返回XML格式结果")
public String wxpayNotify(HttpServletRequest request) {
try {
String xml = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
Map params = WxPayXmlUtil.xmlToMap(xml);
return payService.handlePayNotify(2, params);
} catch (IOException e) {
log.error("微信支付回调参数解析失败", e);
return " ";
}
}
@GetMapping("/query-status")
@Operation(summary = "查询支付状态", description = "根据支付单号查询最新支付状态,支持主动补偿")
public Result queryPayStatus(@RequestParam String payNo) {
return Result.success(payService.queryPayStatus(payNo));
}
@PostMapping("/refund")
@Operation(summary = "发起退款", description = "仅已付款订单可发起退款,支持全额/部分退款")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "成功"),
@ApiResponse(responseCode = "400", description = "订单状态异常/退款金额超限")
})
public Result createRefund(@Valid @RequestBody RefundCreateDTO dto) {
return Result.success(payService.createRefund(dto));
}
@GetMapping("/refund/query")
@Operation(summary = "查询退款状态", description = "根据退款单号查询退款进度")
public Result queryRefundStatus(@RequestParam String refundNo) {
return Result.success(payService.queryRefundStatus(refundNo));
}
}
4.3 支付模块 API 说明
| 接口路径 | 请求方式 | 功能描述 | 请求参数示例 | 响应示例片段 |
|---|---|---|---|---|
/api/v1/pay/create | POST | 发起支付 | {"orderNo":"1688812345678901234","payType":1} | {"code":200,"msg":"success","data":{"payNo":"P1688812345678901234","payUrl":""}} |
/api/v1/pay/notify/alipay | POST | 支付宝支付回调 | 支付宝自动传递的表单参数(如 out_trade_no、trade_status 等) | success |
/api/v1/pay/notify/wxpay | POST | 微信支付回调 | 微信自动传递的 XML 参数(如 out_trade_no、result_code 等) | |
/api/v1/pay/query-status | GET | 查询支付状态 | payNo=P1688812345678901234 | {"code":200,"msg":"success","data":{"payNo":"P1688812345678901234","orderNo":"1688812345678901234","payStatus":1,"payTime":"2024-05-20T15:40:00","tradeNo":"2024052022001410010000000001"}} |
/api/v1/pay/refund | POST | 发起退款 | {"orderNo":"1688812345678901234","refundAmount":5999.00,"refundReason":"商品质量问题"} | {"code":200,"msg":"success","data":{"refundNo":"R1688812345678901234","orderNo":"1688812345678901234","refundAmount":5999.00,"refundStatus":1,"refundTime":"2024-05-21T10:30:00"}} |
/api/v1/pay/refund/query | GET | 查询退款状态 | refundNo=R1688812345678901234 | {"code":200,"msg":"success","data":{"refundNo":"R1688812345678901234","orderNo":"1688812345678901234","refundAmount":5999.00,"refundStatus":1,"refundTradeNo":"2024052122001410010000000002"}} |