From 98c3d98d08ac4c05c97468202da95f3a777f8f41 Mon Sep 17 00:00:00 2001 From: litianxiang Date: Wed, 20 May 2026 11:09:31 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=A2=E5=8D=95=E7=9B=B8=E5=85=B3=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/constants/CommonConstants.java | 3 ++ .../aida/buyer/model/vo/AuthPrincipalVo.java | 2 +- .../service/impl/BuyerAccountServiceImpl.java | 2 +- .../module/feign/annotation/InternalCall.java | 17 +++++++ .../module/feign/config/FeignConfig.java | 18 +++++++ .../interceptor/InternalCallInterceptor.java | 34 +++++++++++++ .../listing/controller/ListingController.java | 4 +- .../controller/BuyerOrderController.java | 41 +++++++++++++++ .../module/order/dto/CreateOrderDTO.java | 23 +++++++++ .../module/order/feign/OrderFeignClient.java | 39 +++++++++++++++ .../order/service/IBuyerOrderService.java | 14 ++++++ .../service/impl/BuyerOrderServiceImpl.java | 50 +++++++++++++++++++ .../module/order/vo/BuyerOrderItemVO.java | 33 ++++++++++++ .../buyer/module/order/vo/BuyerOrderVO.java | 37 ++++++++++++++ .../module/order/vo/CreateOrderResultVO.java | 21 ++++++++ 15 files changed, 334 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/aida/buyer/module/feign/annotation/InternalCall.java create mode 100644 src/main/java/com/aida/buyer/module/feign/config/FeignConfig.java create mode 100644 src/main/java/com/aida/buyer/module/feign/interceptor/InternalCallInterceptor.java create mode 100644 src/main/java/com/aida/buyer/module/order/controller/BuyerOrderController.java create mode 100644 src/main/java/com/aida/buyer/module/order/dto/CreateOrderDTO.java create mode 100644 src/main/java/com/aida/buyer/module/order/feign/OrderFeignClient.java create mode 100644 src/main/java/com/aida/buyer/module/order/service/IBuyerOrderService.java create mode 100644 src/main/java/com/aida/buyer/module/order/service/impl/BuyerOrderServiceImpl.java create mode 100644 src/main/java/com/aida/buyer/module/order/vo/BuyerOrderItemVO.java create mode 100644 src/main/java/com/aida/buyer/module/order/vo/BuyerOrderVO.java create mode 100644 src/main/java/com/aida/buyer/module/order/vo/CreateOrderResultVO.java diff --git a/src/main/java/com/aida/buyer/common/constants/CommonConstants.java b/src/main/java/com/aida/buyer/common/constants/CommonConstants.java index efe2ee8..714700a 100644 --- a/src/main/java/com/aida/buyer/common/constants/CommonConstants.java +++ b/src/main/java/com/aida/buyer/common/constants/CommonConstants.java @@ -5,4 +5,7 @@ public class CommonConstants { public static final int MINIO_PATH_TIMEOUT = 7 * 24 * 60 * 60; // minio图片临时访问地址 7 天过期(second) public static final int TOKEN_EXPIRE_TIME = 7 * 24; // token 7 天过期(Hour) + + public static final String INTERNAL_CALL_HEADER = "X-Internal-Call"; + public static final String INTERNAL_CALL_VALUE = "true"; } diff --git a/src/main/java/com/aida/buyer/model/vo/AuthPrincipalVo.java b/src/main/java/com/aida/buyer/model/vo/AuthPrincipalVo.java index e1c6645..020a51e 100644 --- a/src/main/java/com/aida/buyer/model/vo/AuthPrincipalVo.java +++ b/src/main/java/com/aida/buyer/model/vo/AuthPrincipalVo.java @@ -19,6 +19,6 @@ public class AuthPrincipalVo implements Serializable { private String source; private Integer status; private String language; - private String country; + private String region; private List authorities; } diff --git a/src/main/java/com/aida/buyer/module/account/service/impl/BuyerAccountServiceImpl.java b/src/main/java/com/aida/buyer/module/account/service/impl/BuyerAccountServiceImpl.java index 6a4a029..79990ed 100644 --- a/src/main/java/com/aida/buyer/module/account/service/impl/BuyerAccountServiceImpl.java +++ b/src/main/java/com/aida/buyer/module/account/service/impl/BuyerAccountServiceImpl.java @@ -116,7 +116,7 @@ public class BuyerAccountServiceImpl implements IBuyerAccountService { principal.setUsername(account.getUsername()); principal.setSource("BUYER"); principal.setLanguage(account.getLanguage()); - principal.setCountry(account.getCountry()); + principal.setRegion(account.getRegion()); String token = tokenGenerateUtils.createToken(principal); long ttlMs = tokenGenerateUtils.getJwtExpiration(); diff --git a/src/main/java/com/aida/buyer/module/feign/annotation/InternalCall.java b/src/main/java/com/aida/buyer/module/feign/annotation/InternalCall.java new file mode 100644 index 0000000..01e77d0 --- /dev/null +++ b/src/main/java/com/aida/buyer/module/feign/annotation/InternalCall.java @@ -0,0 +1,17 @@ +package com.aida.buyer.module.feign.annotation; + +import java.lang.annotation.*; + +/** + * 标记 Feign 接口方法,表示该调用是内部服务间调用。 + *

+ * 被此注解标记的 Feign 方法会在请求时自动携带内部调用 Header, + * 用于标识为可信的内部服务调用。 + * + * @see com.aida.buyer.module.feign.interceptor.InternalCallInterceptor + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface InternalCall { +} diff --git a/src/main/java/com/aida/buyer/module/feign/config/FeignConfig.java b/src/main/java/com/aida/buyer/module/feign/config/FeignConfig.java new file mode 100644 index 0000000..0f79869 --- /dev/null +++ b/src/main/java/com/aida/buyer/module/feign/config/FeignConfig.java @@ -0,0 +1,18 @@ +package com.aida.buyer.module.feign.config; + +import com.aida.buyer.module.feign.interceptor.InternalCallInterceptor; +import feign.RequestInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Feign 全局配置:注册所有 Feign 拦截器。 + */ +@Configuration +public class FeignConfig { + + @Bean + public RequestInterceptor internalCallInterceptor() { + return new InternalCallInterceptor(); + } +} diff --git a/src/main/java/com/aida/buyer/module/feign/interceptor/InternalCallInterceptor.java b/src/main/java/com/aida/buyer/module/feign/interceptor/InternalCallInterceptor.java new file mode 100644 index 0000000..1a3c8b3 --- /dev/null +++ b/src/main/java/com/aida/buyer/module/feign/interceptor/InternalCallInterceptor.java @@ -0,0 +1,34 @@ +package com.aida.buyer.module.feign.interceptor; + +import com.aida.buyer.common.constants.CommonConstants; +import com.aida.buyer.module.feign.annotation.InternalCall; +import feign.MethodMetadata; +import feign.RequestInterceptor; +import feign.RequestTemplate; +import org.springframework.core.annotation.AnnotationUtils; + +/** + * Feign 请求拦截器:为标记了 {@link InternalCall} 注解的方法自动注入内部调用 Header。 + *

+ * 当 Feign Client 方法标注了 {@code @InternalCall} 时, + * 会在请求中自动添加 {@link CommonConstants#INTERNAL_CALL_HEADER} Header, + * 供服务端的 {@code @InternalOnly} 校验使用。 + */ +public class InternalCallInterceptor implements RequestInterceptor { + + @Override + public void apply(RequestTemplate template) { + MethodMetadata methodMetadata = template.methodMetadata(); + if (methodMetadata == null) { + return; + } + + try { + java.lang.reflect.Method feignMethod = methodMetadata.method(); + if (feignMethod != null && AnnotationUtils.findAnnotation(feignMethod, InternalCall.class) != null) { + template.header(CommonConstants.INTERNAL_CALL_HEADER, CommonConstants.INTERNAL_CALL_VALUE); + } + } catch (Exception ignored) { + } + } +} diff --git a/src/main/java/com/aida/buyer/module/listing/controller/ListingController.java b/src/main/java/com/aida/buyer/module/listing/controller/ListingController.java index 7d93416..e438c46 100644 --- a/src/main/java/com/aida/buyer/module/listing/controller/ListingController.java +++ b/src/main/java/com/aida/buyer/module/listing/controller/ListingController.java @@ -24,7 +24,7 @@ public class ListingController { private final ListingService listingService; - @Operation(summary = "商城首页商品分页列表", description = "面向所有卖家,支持分类筛选、多字段排序、分页") + @Operation(summary = "数字资产商品分页列表", description = "") @PostMapping("/mall") public PageResponse getMallListings( @RequestBody ListingMallQueryDTO dto) { @@ -38,7 +38,7 @@ public class ListingController { return listingService.getListingDetail(id); } - @Operation(summary = "获取店铺商品列表", description = "按 status=1、deleted=0、designFor 筛选,返回店铺已发布商品分页列表") + @Operation(summary = "获取店铺商品列表", description = "返回店铺已发布商品分页列表") @GetMapping("/shop/seller") public PageResponse getShopListings( @Parameter(description = "设计师用户ID") @RequestParam Long sellerId, diff --git a/src/main/java/com/aida/buyer/module/order/controller/BuyerOrderController.java b/src/main/java/com/aida/buyer/module/order/controller/BuyerOrderController.java new file mode 100644 index 0000000..5317a63 --- /dev/null +++ b/src/main/java/com/aida/buyer/module/order/controller/BuyerOrderController.java @@ -0,0 +1,41 @@ +package com.aida.buyer.module.order.controller; + +import com.aida.buyer.common.result.PageResponse; +import com.aida.buyer.common.result.Response; +import com.aida.buyer.module.order.service.IBuyerOrderService; +import com.aida.buyer.module.order.vo.BuyerOrderVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@Tag(name = "Buyer Order", description = "买家订单管理") +@RestController +@RequestMapping("/buyer/order") +@RequiredArgsConstructor +public class BuyerOrderController { + + private final IBuyerOrderService buyerOrderService; + + @GetMapping("/page") + @Operation(summary = "分页查询当前买家的订单列表") + public Response> getMyOrders( + @RequestParam(defaultValue = "1") long page, + @RequestParam(defaultValue = "10") long size, + @RequestParam(required = false) Integer status) { + return buyerOrderService.getMyOrders(page, size, status); + } + + @PostMapping("/create") + @Operation(summary = "创建订单,付款,用于单品结算和购物车结算") + public Response createOrder(@RequestBody List listingIds) { + return buyerOrderService.createOrder(listingIds); + } +} diff --git a/src/main/java/com/aida/buyer/module/order/dto/CreateOrderDTO.java b/src/main/java/com/aida/buyer/module/order/dto/CreateOrderDTO.java new file mode 100644 index 0000000..ff75520 --- /dev/null +++ b/src/main/java/com/aida/buyer/module/order/dto/CreateOrderDTO.java @@ -0,0 +1,23 @@ +package com.aida.buyer.module.order.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +@Schema(description = "创建订单请求参数") +public class CreateOrderDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "商品ID列表") + private List listingIds; + + @Schema(description = "买家ID") + private Long buyerId; + + @Schema(description = "买家账号") + private String buyerUsername; +} diff --git a/src/main/java/com/aida/buyer/module/order/feign/OrderFeignClient.java b/src/main/java/com/aida/buyer/module/order/feign/OrderFeignClient.java new file mode 100644 index 0000000..4faa044 --- /dev/null +++ b/src/main/java/com/aida/buyer/module/order/feign/OrderFeignClient.java @@ -0,0 +1,39 @@ +package com.aida.buyer.module.order.feign; + +import com.aida.buyer.common.result.PageResponse; +import com.aida.buyer.common.result.Response; +import com.aida.buyer.module.feign.annotation.InternalCall; +import com.aida.buyer.module.order.dto.CreateOrderDTO; +import com.aida.buyer.module.order.vo.BuyerOrderVO; +import com.aida.buyer.module.order.vo.CreateOrderResultVO; + +import com.aida.buyer.module.order.dto.UpdateOrderStatusDTO; + +import java.util.List; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * 订单服务 Feign Client + */ +@FeignClient(name = "aida-seller", contextId = "order", path = "/order") +public interface OrderFeignClient { + + @PostMapping("/buyer/orders") + Response> getOrdersByBuyerId( + @RequestParam Long buyerId, + @RequestParam(defaultValue = "1") long page, + @RequestParam(defaultValue = "10") long size, + @RequestParam(required = false) Integer status); + + @PostMapping("/create") + Response createOrder(@RequestBody CreateOrderDTO dto); + + @InternalCall + @PutMapping("/status/batch") + Response updateOrderStatus(@RequestBody UpdateOrderStatusDTO dto); +} diff --git a/src/main/java/com/aida/buyer/module/order/service/IBuyerOrderService.java b/src/main/java/com/aida/buyer/module/order/service/IBuyerOrderService.java new file mode 100644 index 0000000..146ce9d --- /dev/null +++ b/src/main/java/com/aida/buyer/module/order/service/IBuyerOrderService.java @@ -0,0 +1,14 @@ +package com.aida.buyer.module.order.service; + +import com.aida.buyer.common.result.PageResponse; +import com.aida.buyer.common.result.Response; +import com.aida.buyer.module.order.vo.BuyerOrderVO; + +import java.util.List; + +public interface IBuyerOrderService { + + Response> getMyOrders(long page, long size, Integer status); + + Response createOrder(List listingIds); +} diff --git a/src/main/java/com/aida/buyer/module/order/service/impl/BuyerOrderServiceImpl.java b/src/main/java/com/aida/buyer/module/order/service/impl/BuyerOrderServiceImpl.java new file mode 100644 index 0000000..5e40b08 --- /dev/null +++ b/src/main/java/com/aida/buyer/module/order/service/impl/BuyerOrderServiceImpl.java @@ -0,0 +1,50 @@ +package com.aida.buyer.module.order.service.impl; + +import com.aida.buyer.common.context.UserContext; +import com.aida.buyer.common.exception.BusinessException; +import com.aida.buyer.common.result.PageResponse; +import com.aida.buyer.common.result.Response; +import com.aida.buyer.module.account.entity.BuyerAccount; +import com.aida.buyer.module.account.mapper.BuyerAccountMapper; +import com.aida.buyer.module.order.dto.CreateOrderDTO; +import com.aida.buyer.module.order.feign.OrderFeignClient; +import com.aida.buyer.module.order.service.IBuyerOrderService; +import com.aida.buyer.module.order.vo.BuyerOrderVO; +import com.aida.buyer.module.order.vo.CreateOrderResultVO; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class BuyerOrderServiceImpl implements IBuyerOrderService { + + private final OrderFeignClient orderFeignClient; + private final BuyerAccountMapper buyerAccountMapper; + + @Override + public Response> getMyOrders(long page, long size, Integer status) { + Long buyerId = UserContext.getBuyerId(); + return orderFeignClient.getOrdersByBuyerId(buyerId, page, size, status); + } + + @Override + public Response createOrder(List listingIds) { + Long buyerId = UserContext.getBuyerId(); + BuyerAccount account = buyerAccountMapper.selectById(buyerId); + CreateOrderDTO dto = new CreateOrderDTO(); + dto.setListingIds(listingIds); + dto.setBuyerId(buyerId); + dto.setBuyerUsername(account.getUsername()); + + Response orderResp = orderFeignClient.createOrder(dto); + if (orderResp == null || orderResp.getErrCode() != 0) { + throw new BusinessException("创建订单失败"); + } + + CreateOrderResultVO result = orderResp.getData(); + // TODO:调用支付模块,传入buyerId,result.getOrderIds(),result.getTotalAmount() + return Response.success(); + } +} diff --git a/src/main/java/com/aida/buyer/module/order/vo/BuyerOrderItemVO.java b/src/main/java/com/aida/buyer/module/order/vo/BuyerOrderItemVO.java new file mode 100644 index 0000000..67637fd --- /dev/null +++ b/src/main/java/com/aida/buyer/module/order/vo/BuyerOrderItemVO.java @@ -0,0 +1,33 @@ +package com.aida.buyer.module.order.vo; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.List; + +@Data +@Schema(description = "买家订单商品明细") +public class BuyerOrderItemVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "订单商品ID") + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + + @Schema(description = "商品缩略图URL") + private String thumbnailUrl; + + @Schema(description = "商品名称") + private String listingName; + + @Schema(description = "商品分类列表") + private List productCategory; + + @Schema(description = "成交单价(HK$)") + private BigDecimal price; +} diff --git a/src/main/java/com/aida/buyer/module/order/vo/BuyerOrderVO.java b/src/main/java/com/aida/buyer/module/order/vo/BuyerOrderVO.java new file mode 100644 index 0000000..e5f0305 --- /dev/null +++ b/src/main/java/com/aida/buyer/module/order/vo/BuyerOrderVO.java @@ -0,0 +1,37 @@ +package com.aida.buyer.module.order.vo; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Schema(description = "买家订单信息") +public class BuyerOrderVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "订货号") + @JsonSerialize(using = ToStringSerializer.class) + private Long orderId; + + @Schema(description = "订单更新时间") + private LocalDateTime updateTime; + + @Schema(description = "订单总金额(HK$)") + private BigDecimal totalPrice; + + @Schema(description = "订单状态:0-未支付,1-已支付,2-已取消") + private Integer status; + + @Schema(description = "店铺名称") + private String shopName; + + @Schema(description = "商品明细列表") + private List items; +} diff --git a/src/main/java/com/aida/buyer/module/order/vo/CreateOrderResultVO.java b/src/main/java/com/aida/buyer/module/order/vo/CreateOrderResultVO.java new file mode 100644 index 0000000..3563228 --- /dev/null +++ b/src/main/java/com/aida/buyer/module/order/vo/CreateOrderResultVO.java @@ -0,0 +1,21 @@ +package com.aida.buyer.module.order.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.List; + +@Data +@Schema(description = "创建订单结果") +public class CreateOrderResultVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "订单ID列表(按卖家分组)") + private List orderIds; + + @Schema(description = "所有订单总金额(HK$)") + private BigDecimal totalAmount; +}