chore(assets): 参赛提交规范红线修复(ASCII 化 + 相对路径)
按《参赛成果物提交规范·赛道一》§6 红线: - samples/ 目录改名 sample/(git mv,保留历史) - 10 个中日文样本文件 + docs 参赛手册 PDF 重命名为 ASCII (requirements_*/template_*/rules_*/contestant-handbook.pdf) - tests/test_zh_template.py 硬编码绝对路径 D:\00_project\Genesis 改为相对路径 - 全局更新 21 个活动文件引用;历史日志/审查文档不改(追加说明记录) 全量 pytest 431 passed / 99.15%
This commit is contained in:
+18
@@ -0,0 +1,18 @@
|
||||
package com.stock.trade.order;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* 订单服务启动类
|
||||
*
|
||||
* @author tianxin
|
||||
*/
|
||||
@SpringBootApplication(scanBasePackages = {"com.stock.trade"})
|
||||
public class OrderApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(OrderApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.stock.trade.order.controller;
|
||||
|
||||
import com.stock.trade.common.core.domain.CommonResult;
|
||||
import com.stock.trade.common.core.domain.PageResult;
|
||||
import com.stock.trade.order.controller.request.OrderCreateReqVO;
|
||||
import com.stock.trade.order.controller.request.OrderPageReqVO;
|
||||
import com.stock.trade.order.controller.request.OrderUpdateReqVO;
|
||||
import com.stock.trade.order.controller.response.OrderRespVO;
|
||||
import com.stock.trade.order.convert.OrderConvert;
|
||||
import com.stock.trade.order.dal.dataobject.OrderDO;
|
||||
import com.stock.trade.order.service.OrderService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import static com.stock.trade.common.core.domain.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 订单")
|
||||
@RestController
|
||||
@RequestMapping("/trade/order")
|
||||
@Validated
|
||||
public class OrderController {
|
||||
|
||||
@Resource
|
||||
private OrderService orderService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建订单")
|
||||
@PreAuthorize("@ss.hasPermission('trade:order:create')")
|
||||
public CommonResult<Long> createOrder(@Valid @RequestBody OrderCreateReqVO createReqVO) {
|
||||
return success(orderService.createOrder(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新订单")
|
||||
@PreAuthorize("@ss.hasPermission('trade:order:update')")
|
||||
public CommonResult<Boolean> updateOrder(@Valid @RequestBody OrderUpdateReqVO updateReqVO) {
|
||||
orderService.updateOrder(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除订单")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('trade:order:delete')")
|
||||
public CommonResult<Boolean> deleteOrder(@RequestParam("id") Long id) {
|
||||
orderService.deleteOrder(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得订单")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('trade:order:query')")
|
||||
public CommonResult<OrderRespVO> getOrder(@RequestParam("id") Long id) {
|
||||
OrderDO order = orderService.getOrder(id);
|
||||
return success(OrderConvert.INSTANCE.convert(order));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得订单分页")
|
||||
@PreAuthorize("@ss.hasPermission('trade:order:query')")
|
||||
public CommonResult<PageResult<OrderRespVO>> getOrderPage(@Valid OrderPageReqVO pageVO) {
|
||||
PageResult<OrderDO> pageResult = orderService.getOrderPage(pageVO);
|
||||
return success(OrderConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@PostMapping("/cancel")
|
||||
@Operation(summary = "撤销订单")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('trade:order:cancel')")
|
||||
public CommonResult<Boolean> cancelOrder(@RequestParam("id") Long id,
|
||||
@RequestParam("userId") Long userId) {
|
||||
orderService.cancelOrder(id, userId);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.stock.trade.order.controller.request;
|
||||
|
||||
import com.stock.trade.order.enums.OrderDirectionEnum;
|
||||
import com.stock.trade.order.enums.OrderTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 订单创建 Request VO")
|
||||
@Data
|
||||
public class OrderCreateReqVO {
|
||||
|
||||
@Schema(description = "用户编号", required = true, example = "1024")
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "股票代码", required = true, example = "600000")
|
||||
@NotEmpty(message = "股票代码不能为空")
|
||||
private String stockCode;
|
||||
|
||||
@Schema(description = "股票名称", required = true, example = "浦发银行")
|
||||
@NotEmpty(message = "股票名称不能为空")
|
||||
private String stockName;
|
||||
|
||||
@Schema(description = "订单类型,参见 OrderTypeEnum 枚举", required = true, example = "0")
|
||||
@NotNull(message = "订单类型不能为空")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "订单方向,参见 OrderDirectionEnum 枚举", required = true, example = "0")
|
||||
@NotNull(message = "订单方向不能为空")
|
||||
private Integer direction;
|
||||
|
||||
@Schema(description = "订单价格,市价单可为空", example = "10.24")
|
||||
private BigDecimal price;
|
||||
|
||||
@Schema(description = "订单数量", required = true, example = "100")
|
||||
@NotNull(message = "订单数量不能为空")
|
||||
private Integer quantity;
|
||||
|
||||
@Schema(description = "备注", example = "测试订单")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.stock.trade.order.controller.request;
|
||||
|
||||
import com.stock.trade.common.core.dal.qo.PageQuery;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - 订单分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class OrderPageReqVO extends PageQuery {
|
||||
|
||||
@Schema(description = "用户编号", example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "股票代码", example = "600000")
|
||||
private String stockCode;
|
||||
|
||||
@Schema(description = "订单类型,参见 OrderTypeEnum 枚举", example = "0")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "订单方向,参见 OrderDirectionEnum 枚举", example = "0")
|
||||
private Integer direction;
|
||||
|
||||
@Schema(description = "订单状态,参见 OrderStatusEnum 枚举", example = "0")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.stock.trade.order.controller.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Schema(description = "管理后台 - 订单更新 Request VO")
|
||||
@Data
|
||||
public class OrderUpdateReqVO {
|
||||
|
||||
@Schema(description = "订单编号", required = true, example = "1024")
|
||||
@NotNull(message = "订单编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "订单价格,市价单可为空", example = "10.24")
|
||||
private BigDecimal price;
|
||||
|
||||
@Schema(description = "订单数量", example = "100")
|
||||
private Integer quantity;
|
||||
|
||||
@Schema(description = "备注", example = "修改订单")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.stock.trade.order.controller.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 订单项 Response VO")
|
||||
@Data
|
||||
public class OrderItemRespVO {
|
||||
|
||||
@Schema(description = "订单项编号", required = true, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "订单编号", required = true, example = "2048")
|
||||
private Long orderId;
|
||||
|
||||
@Schema(description = "成交编号", required = true, example = "T202305200001")
|
||||
private String tradeNo;
|
||||
|
||||
@Schema(description = "成交价格", required = true, example = "10.24")
|
||||
private BigDecimal price;
|
||||
|
||||
@Schema(description = "成交数量", required = true, example = "100")
|
||||
private Integer quantity;
|
||||
|
||||
@Schema(description = "成交时间", required = true)
|
||||
private LocalDateTime tradeTime;
|
||||
|
||||
@Schema(description = "交易费用", required = true, example = "5.12")
|
||||
private BigDecimal fee;
|
||||
|
||||
@Schema(description = "创建时间", required = true)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.stock.trade.order.controller.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 订单日志 Response VO")
|
||||
@Data
|
||||
public class OrderLogRespVO {
|
||||
|
||||
@Schema(description = "日志编号", required = true, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "订单编号", required = true, example = "2048")
|
||||
private Long orderId;
|
||||
|
||||
@Schema(description = "操作前订单状态,参见 OrderStatusEnum 枚举", required = true, example = "0")
|
||||
private Integer beforeStatus;
|
||||
|
||||
@Schema(description = "操作后订单状态,参见 OrderStatusEnum 枚举", required = true, example = "1")
|
||||
private Integer afterStatus;
|
||||
|
||||
@Schema(description = "操作内容", required = true, example = "创建订单")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "操作时间", required = true)
|
||||
private LocalDateTime operateTime;
|
||||
|
||||
@Schema(description = "操作人编号", required = true, example = "1001")
|
||||
private Long operatorId;
|
||||
|
||||
@Schema(description = "创建时间", required = true)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.stock.trade.order.controller.response;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 订单 Response VO")
|
||||
@Data
|
||||
public class OrderRespVO {
|
||||
|
||||
@Schema(description = "订单编号", required = true, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户编号", required = true, example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "股票代码", required = true, example = "600000")
|
||||
private String stockCode;
|
||||
|
||||
@Schema(description = "股票名称", required = true, example = "浦发银行")
|
||||
private String stockName;
|
||||
|
||||
@Schema(description = "订单类型,参见 OrderTypeEnum 枚举", required = true, example = "0")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "订单方向,参见 OrderDirectionEnum 枚举", required = true, example = "0")
|
||||
private Integer direction;
|
||||
|
||||
@Schema(description = "订单价格", example = "10.24")
|
||||
private BigDecimal price;
|
||||
|
||||
@Schema(description = "订单数量", required = true, example = "100")
|
||||
private Integer quantity;
|
||||
|
||||
@Schema(description = "已成交数量", required = true, example = "50")
|
||||
private Integer filledQuantity;
|
||||
|
||||
@Schema(description = "订单状态,参见 OrderStatusEnum 枚举", required = true, example = "0")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "订单时间", required = true)
|
||||
private LocalDateTime orderTime;
|
||||
|
||||
@Schema(description = "成交均价", example = "10.24")
|
||||
private BigDecimal avgFillPrice;
|
||||
|
||||
@Schema(description = "备注", example = "测试订单")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间", required = true)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.stock.trade.order.convert;
|
||||
|
||||
import com.stock.trade.common.core.domain.PageResult;
|
||||
import com.stock.trade.order.controller.request.OrderCreateReqVO;
|
||||
import com.stock.trade.order.controller.response.OrderRespVO;
|
||||
import com.stock.trade.order.dal.dataobject.OrderDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface OrderConvert {
|
||||
|
||||
OrderConvert INSTANCE = Mappers.getMapper(OrderConvert.class);
|
||||
|
||||
OrderDO convert(OrderCreateReqVO bean);
|
||||
|
||||
OrderRespVO convert(OrderDO bean);
|
||||
|
||||
PageResult<OrderRespVO> convertPage(PageResult<OrderDO> page);
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.stock.trade.order.convert;
|
||||
|
||||
import com.stock.trade.order.controller.response.OrderItemRespVO;
|
||||
import com.stock.trade.order.dal.dataobject.OrderItemDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface OrderItemConvert {
|
||||
|
||||
OrderItemConvert INSTANCE = Mappers.getMapper(OrderItemConvert.class);
|
||||
|
||||
OrderItemRespVO convert(OrderItemDO bean);
|
||||
|
||||
List<OrderItemRespVO> convertList(List<OrderItemDO> list);
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.stock.trade.order.convert;
|
||||
|
||||
import com.stock.trade.order.controller.response.OrderLogRespVO;
|
||||
import com.stock.trade.order.dal.dataobject.OrderLogDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface OrderLogConvert {
|
||||
|
||||
OrderLogConvert INSTANCE = Mappers.getMapper(OrderLogConvert.class);
|
||||
|
||||
OrderLogRespVO convert(OrderLogDO bean);
|
||||
|
||||
List<OrderLogRespVO> convertList(List<OrderLogDO> list);
|
||||
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package com.stock.trade.order.dal.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.stock.trade.common.core.dataobject.BaseDO;
|
||||
import com.stock.trade.order.enums.OrderDirectionEnum;
|
||||
import com.stock.trade.order.enums.OrderStatusEnum;
|
||||
import com.stock.trade.order.enums.OrderTypeEnum;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 订单 DO
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
@TableName("trade_order")
|
||||
@KeySequence("trade_order_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class OrderDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 订单编号,主键自增
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 股票代码
|
||||
*/
|
||||
private String stockCode;
|
||||
/**
|
||||
* 股票名称
|
||||
*/
|
||||
private String stockName;
|
||||
/**
|
||||
* 订单类型
|
||||
*
|
||||
* 枚举 {@link OrderTypeEnum}
|
||||
*/
|
||||
private Integer type;
|
||||
/**
|
||||
* 订单方向
|
||||
*
|
||||
* 枚举 {@link OrderDirectionEnum}
|
||||
*/
|
||||
private Integer direction;
|
||||
/**
|
||||
* 订单价格
|
||||
*/
|
||||
private BigDecimal price;
|
||||
/**
|
||||
* 订单数量
|
||||
*/
|
||||
private Integer quantity;
|
||||
/**
|
||||
* 已成交数量
|
||||
*/
|
||||
private Integer filledQuantity;
|
||||
/**
|
||||
* 订单状态
|
||||
*
|
||||
* 枚举 {@link OrderStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 订单时间
|
||||
*/
|
||||
private LocalDateTime orderTime;
|
||||
/**
|
||||
* 成交均价
|
||||
*/
|
||||
private BigDecimal avgFillPrice;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.stock.trade.order.dal.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.stock.trade.common.core.dataobject.BaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 订单项 DO
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
@TableName("trade_order_item")
|
||||
@KeySequence("trade_order_item_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class OrderItemDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 订单项编号,主键自增
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 订单编号,关联 {@link OrderDO#getId()}
|
||||
*/
|
||||
private Long orderId;
|
||||
/**
|
||||
* 成交编号 (如果部分成交,一个订单可能会有多条成交记录)
|
||||
*/
|
||||
private String tradeNo;
|
||||
/**
|
||||
* 成交价格
|
||||
*/
|
||||
private BigDecimal fillPrice;
|
||||
/**
|
||||
* 成交数量
|
||||
*/
|
||||
private Integer fillQuantity;
|
||||
/**
|
||||
* 成交时间
|
||||
*/
|
||||
private LocalDateTime fillTime;
|
||||
/**
|
||||
* 交易费用
|
||||
*/
|
||||
private BigDecimal commission;
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.stock.trade.order.dal.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.stock.trade.common.core.dataobject.BaseDO;
|
||||
import com.stock.trade.order.enums.OrderStatusEnum;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 订单日志 DO
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
@TableName("trade_order_log")
|
||||
@KeySequence("trade_order_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class OrderLogDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 日志编号,主键自增
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 订单编号,关联 {@link OrderDO#getId()}
|
||||
*/
|
||||
private Long orderId;
|
||||
/**
|
||||
* 操作前订单状态
|
||||
*
|
||||
* 枚举 {@link OrderStatusEnum}
|
||||
*/
|
||||
private Integer beforeStatus;
|
||||
/**
|
||||
* 操作后订单状态
|
||||
*
|
||||
* 枚举 {@link OrderStatusEnum}
|
||||
*/
|
||||
private Integer afterStatus;
|
||||
/**
|
||||
* 操作内容
|
||||
*/
|
||||
private String content;
|
||||
/**
|
||||
* 操作时间
|
||||
*/
|
||||
private LocalDateTime operationTime;
|
||||
/**
|
||||
* 操作人编号 (系统操作时,可以为空)
|
||||
*/
|
||||
private Long operatorUserId;
|
||||
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.stock.trade.order.dal.mysql;
|
||||
|
||||
import com.stock.trade.common.core.dal.mapper.BaseMapperX;
|
||||
import com.stock.trade.order.dal.dataobject.OrderItemDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 订单项 Mapper
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
@Mapper
|
||||
public interface OrderItemMapper extends BaseMapperX<OrderItemDO> {
|
||||
|
||||
default List<OrderItemDO> selectListByOrderId(Long orderId) {
|
||||
return selectList(OrderItemDO::getOrderId, orderId);
|
||||
}
|
||||
|
||||
default List<OrderItemDO> selectListByOrderIds(List<Long> orderIds) {
|
||||
return selectList(new LambdaQueryWrapperX<OrderItemDO>()
|
||||
.in(OrderItemDO::getOrderId, orderIds));
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.stock.trade.order.dal.mysql;
|
||||
|
||||
import com.stock.trade.common.core.dal.mapper.BaseMapperX;
|
||||
import com.stock.trade.order.dal.dataobject.OrderLogDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 订单日志 Mapper
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
@Mapper
|
||||
public interface OrderLogMapper extends BaseMapperX<OrderLogDO> {
|
||||
|
||||
default List<OrderLogDO> selectListByOrderId(Long orderId) {
|
||||
return selectList(new LambdaQueryWrapperX<OrderLogDO>()
|
||||
.eq(OrderLogDO::getOrderId, orderId)
|
||||
.orderByDesc(OrderLogDO::getId)); // 按时间倒序,最新的日志在前面
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package com.stock.trade.order.dal.mysql;
|
||||
|
||||
import com.stock.trade.common.core.dal.mapper.BaseMapperX;
|
||||
import com.stock.trade.common.core.dal.qo.PageQuery;
|
||||
import com.stock.trade.order.dal.dataobject.OrderDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 订单 Mapper
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
@Mapper
|
||||
public interface OrderMapper extends BaseMapperX<OrderDO> {
|
||||
|
||||
default List<OrderDO> selectPage(PageQuery pageQuery, Long userId, String stockCode, Integer type, Integer direction, Integer status) {
|
||||
return selectList(new LambdaQueryWrapperX<OrderDO>()
|
||||
.eqIfPresent(OrderDO::getUserId, userId)
|
||||
.likeIfPresent(OrderDO::getStockCode, stockCode)
|
||||
.eqIfPresent(OrderDO::getType, type)
|
||||
.eqIfPresent(OrderDO::getDirection, direction)
|
||||
.eqIfPresent(OrderDO::getStatus, status)
|
||||
.orderByDesc(OrderDO::getId),
|
||||
pageQuery.getPageNo(), pageQuery.getPageSize());
|
||||
}
|
||||
|
||||
default Long selectCount(Long userId, String stockCode, Integer type, Integer direction, Integer status) {
|
||||
return selectCount(new LambdaQueryWrapperX<OrderDO>()
|
||||
.eqIfPresent(OrderDO::getUserId, userId)
|
||||
.likeIfPresent(OrderDO::getStockCode, stockCode)
|
||||
.eqIfPresent(OrderDO::getType, type)
|
||||
.eqIfPresent(OrderDO::getDirection, direction)
|
||||
.eqIfPresent(OrderDO::getStatus, status));
|
||||
}
|
||||
|
||||
default List<OrderDO> selectListByUserId(Long userId) {
|
||||
return selectList(OrderDO::getUserId, userId);
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.stock.trade.order.enums;
|
||||
|
||||
import com.stock.trade.common.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* trade-order 模块错误码枚举
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 订单 1003001000 开头 ============
|
||||
ErrorCode ORDER_NOT_EXISTS = new ErrorCode(1003001000, "订单不存在");
|
||||
ErrorCode ORDER_CREATE_FAILED = new ErrorCode(1003001001, "订单创建失败");
|
||||
ErrorCode ORDER_UPDATE_FAILED = new ErrorCode(1003001002, "订单更新失败");
|
||||
ErrorCode ORDER_DELETE_FAILED = new ErrorCode(1003001003, "订单删除失败");
|
||||
ErrorCode ORDER_STATUS_INVALID = new ErrorCode(1003001004, "订单状态不合法");
|
||||
ErrorCode ORDER_PRICE_INVALID = new ErrorCode(1003001005, "订单价格不合法");
|
||||
ErrorCode ORDER_QUANTITY_INVALID = new ErrorCode(1003001006, "订单数量不合法");
|
||||
ErrorCode ORDER_TYPE_INVALID = new ErrorCode(1003001007, "订单类型不合法");
|
||||
ErrorCode ORDER_DIRECTION_INVALID = new ErrorCode(1003001008, "订单方向不合法");
|
||||
|
||||
// ========== 订单项 1003002000 开头 ============
|
||||
ErrorCode ORDER_ITEM_NOT_EXISTS = new ErrorCode(1003002000, "订单项不存在");
|
||||
|
||||
// ========== 订单日志 1003003000 开头 ============
|
||||
ErrorCode ORDER_LOG_NOT_EXISTS = new ErrorCode(1003003000, "订单日志不存在");
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.stock.trade.order.enums;
|
||||
|
||||
import com.stock.trade.common.core.IntArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 订单方向枚举
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum OrderDirectionEnum implements IntArrayValuable {
|
||||
|
||||
BUY(0, "买入"),
|
||||
SELL(1, "卖出");
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(OrderDirectionEnum::getDirection).toArray();
|
||||
|
||||
/**
|
||||
* 方向编码
|
||||
*/
|
||||
private final Integer direction;
|
||||
/**
|
||||
* 方向描述
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package com.stock.trade.order.enums;
|
||||
|
||||
import com.stock.trade.common.core.IntArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 订单状态枚举
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum OrderStatusEnum implements IntArrayValuable {
|
||||
|
||||
PENDING_NEW(0, "待报"), // 订单已创建,但尚未发送到交易所
|
||||
NEW(1, "已报"), // 订单已发送到交易所,等待撮合
|
||||
PARTIALLY_FILLED(2, "部分成交"),
|
||||
FILLED(3, "全部成交"),
|
||||
CANCELED(4, "已撤销"),
|
||||
REJECTED(5, "已拒绝"), // 订单被交易所拒绝
|
||||
EXPIRED(6, "已过期"); // 订单因过期未成交而失效
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(OrderStatusEnum::getStatus).toArray();
|
||||
|
||||
/**
|
||||
* 状态编码
|
||||
*/
|
||||
private final Integer status;
|
||||
/**
|
||||
* 状态描述
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断订单是否为最终状态 (不可再变更)
|
||||
*
|
||||
* @param status 订单状态
|
||||
* @return 是否为最终状态
|
||||
*/
|
||||
public static boolean isFinalStatus(Integer status) {
|
||||
return FILLED.getStatus().equals(status)
|
||||
|| CANCELED.getStatus().equals(status)
|
||||
|| REJECTED.getStatus().equals(status)
|
||||
|| EXPIRED.getStatus().equals(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断订单是否可以被撤销
|
||||
*
|
||||
* @param status 订单状态
|
||||
* @return 是否可以被撤销
|
||||
*/
|
||||
public static boolean canCancel(Integer status) {
|
||||
return PENDING_NEW.getStatus().equals(status)
|
||||
|| NEW.getStatus().equals(status)
|
||||
|| PARTIALLY_FILLED.getStatus().equals(status);
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.stock.trade.order.enums;
|
||||
|
||||
import com.stock.trade.common.core.IntArrayValuable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 订单类型枚举
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum OrderTypeEnum implements IntArrayValuable {
|
||||
|
||||
LIMIT(0, "限价单"),
|
||||
MARKET(1, "市价单"),
|
||||
STOP(2, "止损单"),
|
||||
STOP_LIMIT(3, "止损限价单");
|
||||
// TODO 后续可以根据实际需求扩展更多订单类型,例如 FOK, FAK 等
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(OrderTypeEnum::getType).toArray();
|
||||
|
||||
/**
|
||||
* 类型编码
|
||||
*/
|
||||
private final Integer type;
|
||||
/**
|
||||
* 类型描述
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.stock.trade.order.mq.consumer;
|
||||
|
||||
import com.stock.trade.order.service.OrderService;
|
||||
import com.stock.trade.tradeengine.message.TradeOrderReturnMessage; // 假设成交回报消息定义在 trade-engine 模块
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 订单成交回报消息消费者
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class TradeOrderReturnConsumer {
|
||||
|
||||
@Resource
|
||||
private OrderService orderService;
|
||||
|
||||
@EventListener
|
||||
public void onMessage(TradeOrderReturnMessage message) {
|
||||
log.info("[onMessage][消息内容({})]", message);
|
||||
try {
|
||||
orderService.processOrderReturn(message);
|
||||
} catch (Throwable e) {
|
||||
log.error("[onMessage][处理订单成交回报({}) 异常]", message, e);
|
||||
// TODO: 考虑增加重试机制或死信队列
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.stock.trade.order.mq.message;
|
||||
|
||||
import com.stock.trade.common.mq.message.AbstractStreamMessage;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class OrderMessage extends AbstractStreamMessage {
|
||||
|
||||
public static final String STREAM_KEY = "stock.trade.order.change";
|
||||
|
||||
/**
|
||||
* 订单编号
|
||||
*/
|
||||
@NotNull(message = "订单编号不能为空")
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 订单状态
|
||||
*/
|
||||
@NotNull(message = "订单状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
@Override
|
||||
public String getStreamKey() {
|
||||
return STREAM_KEY;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.stock.trade.order.mq.producer;
|
||||
|
||||
import com.stock.trade.common.mq.producer.AbstractStreamProducer;
|
||||
import com.stock.trade.order.mq.message.OrderMessage;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class OrderProducer extends AbstractStreamProducer<OrderMessage> {
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.stock.trade.order.service;
|
||||
|
||||
import com.stock.trade.order.dal.dataobject.OrderItemDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 订单项 Service 接口
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
public interface OrderItemService {
|
||||
|
||||
/**
|
||||
* 根据订单编号获取订单项列表
|
||||
*
|
||||
* @param orderId 订单编号
|
||||
* @return 订单项列表
|
||||
*/
|
||||
List<OrderItemDO> getOrderItemListByOrderId(Long orderId);
|
||||
|
||||
/**
|
||||
* 根据订单编号列表获取订单项列表
|
||||
*
|
||||
* @param orderIds 订单编号列表
|
||||
* @return 订单项列表
|
||||
*/
|
||||
List<OrderItemDO> getOrderItemListByOrderIds(List<Long> orderIds);
|
||||
|
||||
/**
|
||||
* 创建订单项
|
||||
*
|
||||
* @param orderItem 订单项信息
|
||||
* @return 订单项编号
|
||||
*/
|
||||
Long createOrderItem(OrderItemDO orderItem);
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.stock.trade.order.service;
|
||||
|
||||
import com.stock.trade.order.dal.dataobject.OrderLogDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 订单日志 Service 接口
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
public interface OrderLogService {
|
||||
|
||||
/**
|
||||
* 创建订单日志
|
||||
*
|
||||
* @param orderLog 订单日志信息
|
||||
*/
|
||||
void createOrderLog(OrderLogDO orderLog);
|
||||
|
||||
/**
|
||||
* 根据订单编号获取订单日志列表
|
||||
*
|
||||
* @param orderId 订单编号
|
||||
* @return 订单日志列表
|
||||
*/
|
||||
List<OrderLogDO> getOrderLogListByOrderId(Long orderId);
|
||||
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
package com.stock.trade.order.service;
|
||||
|
||||
import com.stock.trade.common.core.domain.PageResult;
|
||||
import com.stock.trade.order.controller.request.OrderCreateReqVO;
|
||||
import com.stock.trade.order.controller.request.OrderPageReqVO;
|
||||
import com.stock.trade.order.controller.request.OrderUpdateReqVO;
|
||||
import com.stock.trade.order.dal.dataobject.OrderDO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 订单 Service 接口
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
public interface OrderService {
|
||||
|
||||
/**
|
||||
* 创建订单
|
||||
*
|
||||
* @param createReqVO 创建信息
|
||||
* @return 订单编号
|
||||
*/
|
||||
Long createOrder(@Valid OrderCreateReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 更新订单
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updateOrder(@Valid OrderUpdateReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 更新订单状态
|
||||
*
|
||||
* @param id 订单编号
|
||||
* @param status 订单状态
|
||||
* @param remark 备注 (可选)
|
||||
*/
|
||||
void updateOrderStatus(Long id, Integer status, String remark);
|
||||
|
||||
/**
|
||||
* 撤销订单
|
||||
*
|
||||
* @param id 订单编号
|
||||
* @param userId 用户编号 (用于权限校验)
|
||||
*/
|
||||
void cancelOrder(Long id, Long userId);
|
||||
|
||||
/**
|
||||
* 删除订单 (逻辑删除)
|
||||
*
|
||||
* @param id 订单编号
|
||||
*/
|
||||
void deleteOrder(Long id);
|
||||
|
||||
/**
|
||||
* 获取订单信息
|
||||
*
|
||||
* @param id 订单编号
|
||||
* @return 订单信息
|
||||
*/
|
||||
OrderDO getOrder(Long id);
|
||||
|
||||
/**
|
||||
* 获取订单列表
|
||||
*
|
||||
* @param ids 订单编号集合
|
||||
* @return 订单列表
|
||||
*/
|
||||
List<OrderDO> getOrderList(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 获取订单分页
|
||||
*
|
||||
* @param pageReqVO 分页查询参数
|
||||
* @return 订单分页结果
|
||||
*/
|
||||
PageResult<OrderDO> getOrderPage(OrderPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 根据用户编号获取其所有未完成订单列表
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @return 未完成订单列表
|
||||
*/
|
||||
List<OrderDO> getUnfinishedOrdersByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 处理订单成交回报
|
||||
*
|
||||
* @param orderId 订单编号
|
||||
* @param fillPrice 成交价格
|
||||
* @param fillQuantity 成交数量
|
||||
* @param tradeNo 成交编号
|
||||
*/
|
||||
void processOrderFill(Long orderId, String stockCode, Integer direction, java.math.BigDecimal fillPrice, Integer fillQuantity, String tradeNo);
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.stock.trade.order.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.stock.trade.order.dal.dataobject.OrderItemDO;
|
||||
import com.stock.trade.order.dal.mysql.OrderItemMapper;
|
||||
import com.stock.trade.order.service.OrderItemService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 订单项 Service 实现类
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class OrderItemServiceImpl implements OrderItemService {
|
||||
|
||||
@Resource
|
||||
private OrderItemMapper orderItemMapper;
|
||||
|
||||
@Override
|
||||
public List<OrderItemDO> getOrderItemListByOrderId(Long orderId) {
|
||||
return orderItemMapper.selectListByOrderId(orderId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OrderItemDO> getOrderItemListByOrderIds(List<Long> orderIds) {
|
||||
if (CollUtil.isEmpty(orderIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return orderItemMapper.selectListByOrderIds(orderIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long createOrderItem(OrderItemDO orderItem) {
|
||||
orderItemMapper.insert(orderItem);
|
||||
return orderItem.getId();
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.stock.trade.order.service.impl;
|
||||
|
||||
import com.stock.trade.order.dal.dataobject.OrderLogDO;
|
||||
import com.stock.trade.order.dal.mysql.OrderLogMapper;
|
||||
import com.stock.trade.order.service.OrderLogService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 订单日志 Service 实现类
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class OrderLogServiceImpl implements OrderLogService {
|
||||
|
||||
@Resource
|
||||
private OrderLogMapper orderLogMapper;
|
||||
|
||||
@Override
|
||||
public void createOrderLog(OrderLogDO orderLog) {
|
||||
orderLogMapper.insert(orderLog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OrderLogDO> getOrderLogListByOrderId(Long orderId) {
|
||||
return orderLogMapper.selectListByOrderId(orderId);
|
||||
}
|
||||
|
||||
}
|
||||
+345
@@ -0,0 +1,345 @@
|
||||
package com.stock.trade.order.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.stock.trade.common.core.domain.PageResult;
|
||||
import com.stock.trade.common.core.exception.ServiceException;
|
||||
import com.stock.trade.order.controller.request.OrderCreateReqVO;
|
||||
import com.stock.trade.order.controller.request.OrderPageReqVO;
|
||||
import com.stock.trade.order.controller.request.OrderUpdateReqVO;
|
||||
import com.stock.trade.order.convert.OrderConvert;
|
||||
import com.stock.trade.order.dal.dataobject.OrderDO;
|
||||
import com.stock.trade.order.dal.dataobject.OrderItemDO;
|
||||
import com.stock.trade.order.dal.dataobject.OrderLogDO;
|
||||
import com.stock.trade.order.dal.mysql.OrderMapper;
|
||||
import com.stock.trade.order.enums.ErrorCodeConstants;
|
||||
import com.stock.trade.order.enums.OrderStatusEnum;
|
||||
import com.stock.trade.order.service.OrderItemService;
|
||||
import com.stock.trade.order.service.OrderLogService;
|
||||
import com.stock.trade.order.service.OrderService;
|
||||
import com.stock.trade.order.mq.message.OrderMessage;
|
||||
import com.stock.trade.order.mq.producer.OrderProducer;
|
||||
import com.stock.trade.order.mq.message.TradeOrderReturnMessage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.stock.trade.common.core.exception.util.ServiceExceptionUtil.exception;
|
||||
|
||||
/**
|
||||
* 订单 Service 实现类
|
||||
*
|
||||
* @author xxx
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class OrderServiceImpl implements OrderService {
|
||||
|
||||
@Resource
|
||||
private OrderMapper orderMapper;
|
||||
|
||||
@Resource
|
||||
private OrderItemService orderItemService;
|
||||
|
||||
@Resource
|
||||
private OrderLogService orderLogService;
|
||||
|
||||
@Resource
|
||||
private OrderProducer orderProducer;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createOrder(OrderCreateReqVO createReqVO) {
|
||||
// 1. 校验订单参数
|
||||
validateCreateOrder(createReqVO);
|
||||
|
||||
// 2. 创建订单
|
||||
OrderDO order = OrderConvert.INSTANCE.convert(createReqVO);
|
||||
order.setStatus(OrderStatusEnum.PENDING_NEW.getStatus());
|
||||
order.setOrderTime(LocalDateTime.now());
|
||||
order.setFilledQuantity(0);
|
||||
orderMapper.insert(order);
|
||||
|
||||
// 3. 创建订单日志
|
||||
OrderLogDO orderLog = new OrderLogDO()
|
||||
.setOrderId(order.getId())
|
||||
.setBeforeStatus(null)
|
||||
.setAfterStatus(order.getStatus())
|
||||
.setContent("创建订单")
|
||||
.setOperationTime(LocalDateTime.now())
|
||||
.setOperatorUserId(order.getUserId());
|
||||
orderLogService.createOrderLog(orderLog);
|
||||
|
||||
// 发送订单状态变更消息
|
||||
orderProducer.sendOrderMessage(new OrderMessage().setOrderId(order.getId()).setUserId(order.getUserId()).setStatus(order.getStatus()));
|
||||
|
||||
return order.getId();
|
||||
}
|
||||
|
||||
private void validateCreateOrder(OrderCreateReqVO createReqVO) {
|
||||
// 1. 校验价格
|
||||
if (createReqVO.getPrice() != null && createReqVO.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw exception(ErrorCodeConstants.ORDER_PRICE_INVALID);
|
||||
}
|
||||
// 2. 校验数量
|
||||
if (createReqVO.getQuantity() <= 0) {
|
||||
throw exception(ErrorCodeConstants.ORDER_QUANTITY_INVALID);
|
||||
}
|
||||
// 3. 校验订单类型
|
||||
if (!OrderTypeEnum.ARRAYS.contains(createReqVO.getType())) {
|
||||
throw exception(ErrorCodeConstants.ORDER_TYPE_INVALID);
|
||||
}
|
||||
// 4. 校验订单方向
|
||||
if (!OrderDirectionEnum.ARRAYS.contains(createReqVO.getDirection())) {
|
||||
throw exception(ErrorCodeConstants.ORDER_DIRECTION_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateOrder(OrderUpdateReqVO updateReqVO) {
|
||||
// 1. 校验订单存在
|
||||
OrderDO order = validateOrderExists(updateReqVO.getId());
|
||||
|
||||
// 2. 校验订单状态是否允许修改
|
||||
if (OrderStatusEnum.isFinalStatus(order.getStatus())) {
|
||||
throw exception(ErrorCodeConstants.ORDER_STATUS_INVALID);
|
||||
}
|
||||
|
||||
// 3. 更新订单
|
||||
OrderDO updateObj = OrderConvert.INSTANCE.convert(updateReqVO);
|
||||
orderMapper.updateById(updateObj);
|
||||
|
||||
// 4. 创建订单日志
|
||||
OrderLogDO orderLog = new OrderLogDO()
|
||||
.setOrderId(order.getId())
|
||||
.setBeforeStatus(order.getStatus())
|
||||
.setAfterStatus(order.getStatus())
|
||||
.setContent("更新订单信息")
|
||||
.setOperationTime(LocalDateTime.now())
|
||||
.setOperatorUserId(order.getUserId());
|
||||
orderLogService.createOrderLog(orderLog);
|
||||
|
||||
// 发送订单状态变更消息
|
||||
orderProducer.sendOrderMessage(new OrderMessage().setOrderId(order.getId()).setUserId(userId).setStatus(OrderStatusEnum.CANCELED.getStatus()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateOrderStatus(Long id, Integer status, String remark) {
|
||||
// 1. 校验订单存在
|
||||
OrderDO order = validateOrderExists(id);
|
||||
|
||||
// 2. 更新订单状态
|
||||
OrderDO updateObj = new OrderDO()
|
||||
.setId(id)
|
||||
.setStatus(status)
|
||||
.setRemark(remark);
|
||||
orderMapper.updateById(updateObj);
|
||||
|
||||
// 3. 创建订单日志
|
||||
OrderLogDO orderLog = new OrderLogDO()
|
||||
.setOrderId(order.getId())
|
||||
.setBeforeStatus(order.getStatus())
|
||||
.setAfterStatus(status)
|
||||
.setContent("更新订单状态")
|
||||
.setOperationTime(LocalDateTime.now())
|
||||
.setOperatorUserId(order.getUserId());
|
||||
orderLogService.createOrderLog(orderLog);
|
||||
|
||||
// 发送订单状态变更消息
|
||||
orderProducer.sendOrderMessage(new OrderMessage().setOrderId(order.getId()).setUserId(userId).setStatus(OrderStatusEnum.CANCELED.getStatus()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void cancelOrder(Long id, Long userId) {
|
||||
// 1. 校验订单存在
|
||||
OrderDO order = validateOrderExists(id);
|
||||
|
||||
// 2. 校验订单是否属于当前用户
|
||||
if (!order.getUserId().equals(userId)) {
|
||||
throw exception(ErrorCodeConstants.ORDER_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 3. 校验订单状态是否允许撤销
|
||||
if (!OrderStatusEnum.canCancel(order.getStatus())) {
|
||||
throw exception(ErrorCodeConstants.ORDER_STATUS_INVALID);
|
||||
}
|
||||
|
||||
// 4. 更新订单状态为已撤销
|
||||
OrderDO updateObj = new OrderDO()
|
||||
.setId(id)
|
||||
.setStatus(OrderStatusEnum.CANCELED.getStatus())
|
||||
.setRemark("用户主动撤销");
|
||||
orderMapper.updateById(updateObj);
|
||||
|
||||
// 5. 创建订单日志
|
||||
OrderLogDO orderLog = new OrderLogDO()
|
||||
.setOrderId(order.getId())
|
||||
.setBeforeStatus(order.getStatus())
|
||||
.setAfterStatus(OrderStatusEnum.CANCELED.getStatus())
|
||||
.setContent("撤销订单")
|
||||
.setOperationTime(LocalDateTime.now())
|
||||
.setOperatorUserId(userId);
|
||||
orderLogService.createOrderLog(orderLog);
|
||||
|
||||
// 发送订单状态变更消息
|
||||
orderProducer.sendOrderMessage(new OrderMessage().setOrderId(order.getId()).setUserId(userId).setStatus(OrderStatusEnum.CANCELED.getStatus()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteOrder(Long id) {
|
||||
// 校验订单存在
|
||||
validateOrderExists(id);
|
||||
// 删除订单
|
||||
orderMapper.deleteById(id);
|
||||
}
|
||||
|
||||
private OrderDO validateOrderExists(Long id) {
|
||||
OrderDO order = orderMapper.selectById(id);
|
||||
if (order == null) {
|
||||
throw exception(ErrorCodeConstants.ORDER_NOT_EXISTS);
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderDO getOrder(Long id) {
|
||||
return orderMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OrderDO> getOrderList(Collection<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
return orderMapper.selectBatchIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<OrderDO> getOrderPage(OrderPageReqVO pageReqVO) {
|
||||
// 查询订单分页
|
||||
List<OrderDO> list = orderMapper.selectPage(pageReqVO.getPageQuery(),
|
||||
pageReqVO.getUserId(), pageReqVO.getStockCode(), pageReqVO.getType(),
|
||||
pageReqVO.getDirection(), pageReqVO.getStatus());
|
||||
// 查询总数
|
||||
Long total = orderMapper.selectCount(pageReqVO.getUserId(), pageReqVO.getStockCode(),
|
||||
pageReqVO.getType(), pageReqVO.getDirection(), pageReqVO.getStatus());
|
||||
return new PageResult<>(list, total);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OrderDO> getUnfinishedOrdersByUserId(Long userId) {
|
||||
return orderMapper.selectList(new LambdaQueryWrapperX<OrderDO>()
|
||||
.eq(OrderDO::getUserId, userId)
|
||||
.in(OrderDO::getStatus, OrderStatusEnum.PENDING_NEW.getStatus(),
|
||||
OrderStatusEnum.NEW.getStatus(),
|
||||
OrderStatusEnum.PARTIALLY_FILLED.getStatus()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processOrderReturn(TradeOrderReturnMessage message) {
|
||||
log.info("[processOrderReturn][接收到订单成交回报消息:{}]", message);
|
||||
processOrderFillInternal(message.getOrderId(), message.getStockCode(), message.getDirection(),
|
||||
message.getFillPrice(), message.getFillQuantity(), message.getTradeNo(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processOrderFill(Long orderId, String stockCode, Integer direction,
|
||||
BigDecimal fillPrice, Integer fillQuantity, String tradeNo) {
|
||||
processOrderFillInternal(orderId, stockCode, direction, fillPrice, fillQuantity, tradeNo, false);
|
||||
}
|
||||
|
||||
private void processOrderFillInternal(Long orderId, String stockCode, Integer direction,
|
||||
BigDecimal fillPrice, Integer fillQuantity, String tradeNo, boolean fromMq) {
|
||||
// 1. 校验订单存在
|
||||
OrderDO order = validateOrderExists(orderId);
|
||||
|
||||
// 2. 校验成交回报参数
|
||||
if (!order.getStockCode().equals(stockCode) || !order.getDirection().equals(direction)) {
|
||||
log.error("[processOrderFillInternal][订单({})的股票代码({})或方向({})不匹配, fromMq:{}]", orderId, stockCode, direction, fromMq);
|
||||
throw exception(ErrorCodeConstants.ORDER_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 3. 创建订单项
|
||||
OrderItemDO orderItem = new OrderItemDO()
|
||||
.setOrderId(orderId)
|
||||
.setTradeNo(tradeNo)
|
||||
.setFillPrice(fillPrice)
|
||||
.setFillQuantity(fillQuantity)
|
||||
.setFillTime(LocalDateTime.now())
|
||||
.setCommission(calculateCommission(fillPrice, fillQuantity)); // 计算手续费
|
||||
orderItemService.createOrderItem(orderItem);
|
||||
|
||||
// 4. 更新订单成交信息
|
||||
Integer newFilledQuantity = order.getFilledQuantity() + fillQuantity;
|
||||
BigDecimal newAvgFillPrice = calculateAvgFillPrice(order.getAvgFillPrice(),
|
||||
order.getFilledQuantity(), fillPrice, fillQuantity);
|
||||
Integer newStatus = newFilledQuantity.equals(order.getQuantity()) ?
|
||||
OrderStatusEnum.FILLED.getStatus() : OrderStatusEnum.PARTIALLY_FILLED.getStatus();
|
||||
|
||||
OrderDO updateObj = new OrderDO()
|
||||
.setId(orderId)
|
||||
.setFilledQuantity(newFilledQuantity)
|
||||
.setAvgFillPrice(newAvgFillPrice)
|
||||
.setStatus(newStatus);
|
||||
orderMapper.updateById(updateObj);
|
||||
|
||||
// 5. 创建订单日志
|
||||
OrderLogDO orderLog = new OrderLogDO()
|
||||
.setOrderId(orderId)
|
||||
.setBeforeStatus(order.getStatus())
|
||||
.setAfterStatus(newStatus)
|
||||
.setContent(String.format("订单成交: 成交数量 %d, 成交价格 %.3f", fillQuantity, fillPrice))
|
||||
.setOperationTime(LocalDateTime.now())
|
||||
.setOperatorUserId(order.getUserId()); // 补充操作用户ID
|
||||
orderLogService.createOrderLog(orderLog);
|
||||
|
||||
// 6. 发送订单状态变更消息
|
||||
orderProducer.sendOrderMessage(new OrderMessage().setOrderId(orderId).setUserId(order.getUserId()).setStatus(newStatus));
|
||||
log.info("[processOrderFillInternal][订单({})处理完成,来源MQ:{}]", orderId, fromMq);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算手续费
|
||||
*
|
||||
* @param price 成交价格
|
||||
* @param quantity 成交数量
|
||||
* @return 手续费
|
||||
*/
|
||||
private BigDecimal calculateCommission(BigDecimal price, Integer quantity) {
|
||||
// TODO 根据实际业务规则计算手续费
|
||||
BigDecimal amount = price.multiply(new BigDecimal(quantity));
|
||||
return amount.multiply(new BigDecimal("0.0003")).setScale(2, RoundingMode.UP); // 暂定千分之三
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算成交均价
|
||||
*
|
||||
* @param oldAvgPrice 原成交均价
|
||||
* @param oldQuantity 原成交数量
|
||||
* @param newPrice 新成交价格
|
||||
* @param newQuantity 新成交数量
|
||||
* @return 新的成交均价
|
||||
*/
|
||||
private BigDecimal calculateAvgFillPrice(BigDecimal oldAvgPrice, Integer oldQuantity,
|
||||
BigDecimal newPrice, Integer newQuantity) {
|
||||
if (oldAvgPrice == null || oldQuantity == 0) {
|
||||
return newPrice;
|
||||
}
|
||||
BigDecimal totalAmount = oldAvgPrice.multiply(new BigDecimal(oldQuantity))
|
||||
.add(newPrice.multiply(new BigDecimal(newQuantity)));
|
||||
return totalAmount.divide(new BigDecimal(oldQuantity + newQuantity), 3, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.trade.order;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
/**
|
||||
* 订单服务启动类
|
||||
* @author Trade Team
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
@EnableFeignClients(basePackages = {"com.trade.user.api"}) // 扫描Feign客户端,例如用户服务的API
|
||||
@MapperScan("com.trade.order.mapper") // 扫描MyBatis Mapper接口
|
||||
@ComponentScan(basePackages = {"com.trade.order", "com.trade.common.config"}) // 扫描通用配置和当前模块
|
||||
public class OrderApplication {
|
||||
|
||||
/**
|
||||
* 主函数,启动订单服务应用。
|
||||
*
|
||||
* @param args 命令行参数
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(OrderApplication.class, args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ Trade Order Service 启动成功 ლ(´ڡ`ლ)゙ \n" +
|
||||
" .-------. ____ __ \n" +
|
||||
" | _ _ | \\ \\ / / \n" +
|
||||
" | ( ' ) | \\ _. / ' \n" +
|
||||
" |(_ o _) / _( )_ .' \n" +
|
||||
" | (_,_).' __ ___(_ o _)' \n" +
|
||||
" | |\\ \\ | || |(_,_)' \n" +
|
||||
" | | \\ `' /| `-' / \n" +
|
||||
" | | \\ / \\ / \n" +
|
||||
" ''-' `'-' `-..-' ");
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.trade.order;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
|
||||
/**
|
||||
* 订单服务启动类
|
||||
* Created by macro on 2020/8/3.
|
||||
*/
|
||||
@EnableDiscoveryClient
|
||||
@SpringBootApplication
|
||||
public class TradeOrderApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TradeOrderApplication.class, args);
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放订单模块的配置类。
|
||||
*/
|
||||
package com.trade.order.config;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放订单模块相关的常量定义。
|
||||
*/
|
||||
package com.trade.order.constant;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放订单模块的Controller层,负责处理HTTP请求和响应。
|
||||
*/
|
||||
package com.trade.order.controller;
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放订单模块的数据传输对象 (DTO)。
|
||||
*/
|
||||
package com.trade.order.dto;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放订单模块的数据库实体类。
|
||||
*/
|
||||
package com.trade.order.entity;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* 此包存放订单模块相关的枚举类。
|
||||
* 例如:订单状态枚举、支付方式枚举等。
|
||||
*/
|
||||
package com.trade.order.enums;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放订单服务模块的事件监听器,例如监听支付成功事件、库存扣减事件等。
|
||||
*/
|
||||
package com.trade.order.listener;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放订单模块的Mapper接口,用于数据库操作。
|
||||
*/
|
||||
package com.trade.order.mapper;
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 订单服务模块主包。
|
||||
*/
|
||||
package com.trade.order;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放订单模块Service接口的实现类。
|
||||
*/
|
||||
package com.trade.order.service.impl;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放订单模块的Service层,负责业务逻辑处理。
|
||||
*/
|
||||
package com.trade.order.service;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放订单模块相关的工具类。
|
||||
*/
|
||||
package com.trade.order.util;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放订单服务模块的工具类。
|
||||
*/
|
||||
package com.trade.order.utils;
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 此包存放订单模块的视图对象 (VO)。
|
||||
*/
|
||||
package com.trade.order.vo;
|
||||
@@ -0,0 +1,11 @@
|
||||
server:
|
||||
port: 8003
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
application:
|
||||
name: trade-order
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848
|
||||
@@ -0,0 +1,11 @@
|
||||
server:
|
||||
port: 8003
|
||||
spring:
|
||||
profiles:
|
||||
active: prod
|
||||
application:
|
||||
name: trade-order
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848
|
||||
@@ -0,0 +1,11 @@
|
||||
server:
|
||||
port: 8003
|
||||
spring:
|
||||
profiles:
|
||||
active: test
|
||||
application:
|
||||
name: trade-order
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848
|
||||
@@ -0,0 +1,111 @@
|
||||
server:
|
||||
port: 8082 # 订单服务端口,避免与网关或其他服务冲突
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: trade-order # 应用名称
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848 # Nacos Server地址
|
||||
namespace: # Nacos命名空间ID,根据实际情况配置
|
||||
group: DEFAULT_GROUP # Nacos分组,根据实际情况配置
|
||||
config:
|
||||
server-addr: ${spring.cloud.nacos.discovery.server-addr} # Nacos配置中心地址
|
||||
namespace: ${spring.cloud.nacos.discovery.namespace}
|
||||
group: ${spring.cloud.nacos.discovery.group}
|
||||
file-extension: yml # 配置文件格式
|
||||
shared-configs: # 共享配置
|
||||
- data-id: application-common.yml # 通用应用配置
|
||||
group: ${spring.cloud.nacos.discovery.group}
|
||||
refresh: true
|
||||
- data-id: datasource-mysql-config.yml # MySQL数据源配置
|
||||
group: ${spring.cloud.nacos.discovery.group}
|
||||
refresh: true
|
||||
# ext-config: # 可选的扩展配置
|
||||
# - data-id: trade-order-ext.yml
|
||||
# group: ${spring.cloud.nacos.discovery.group}
|
||||
# refresh: true
|
||||
|
||||
# Spring Profiles: 用于区分不同环境的配置 (dev, test, prod)
|
||||
profiles:
|
||||
active: dev # 默认激活开发环境配置
|
||||
|
||||
# MyBatis Plus 配置
|
||||
mybatis-plus:
|
||||
mapper-locations: classpath*:/mapper/**/*.xml # Mapper XML文件位置
|
||||
# type-aliases-package: com.trade.order.entity # 实体类别名扫描包 (如果需要)
|
||||
global-config:
|
||||
db-config:
|
||||
id-type: auto # 全局主键策略
|
||||
# table-prefix: t_ # 全局表前缀
|
||||
# logic-delete-field: deleted # 全局逻辑删除字段名
|
||||
# logic-not-delete-value: 0
|
||||
# logic-delete-value: 1
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true # 开启驼峰命名转换
|
||||
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # MyBatis日志实现
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.trade.order: INFO # 订单模块日志级别
|
||||
com.trade.order.mapper: DEBUG # Mapper接口日志级别 (开发时可设为DEBUG查看SQL)
|
||||
org.springframework.web: INFO
|
||||
org.springframework.security: INFO # 如果集成了Spring Security
|
||||
# file:
|
||||
# name: ./logs/trade-order.log # 日志文件路径和名称
|
||||
|
||||
# Actuator端点配置
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: '*' # 暴露所有端点,生产环境请按需配置
|
||||
endpoint:
|
||||
health:
|
||||
show-details: always # 显示健康检查详情
|
||||
|
||||
# Feign 配置 (如果需要调用其他服务)
|
||||
feign:
|
||||
client:
|
||||
config:
|
||||
default:
|
||||
connectTimeout: 5000 # 连接超时时间 (ms)
|
||||
readTimeout: 5000 # 读取超时时间 (ms)
|
||||
# sentinel:
|
||||
# enabled: true # 开启Sentinel对Feign的支持 (如果集成了Sentinel)
|
||||
|
||||
# Seata 分布式事务配置 (如果需要)
|
||||
# seata:
|
||||
# tx-service-group: trade_tx_group # 事务分组,需要与Seata Server配置一致
|
||||
# service:
|
||||
# vgroup-mapping:
|
||||
# trade_tx_group: default
|
||||
# registry:
|
||||
# type: nacos
|
||||
# nacos:
|
||||
# server-addr: ${spring.cloud.nacos.discovery.server-addr}
|
||||
# namespace: ${spring.cloud.nacos.discovery.namespace}
|
||||
# group: DEFAULT_GROUP
|
||||
# application: seata-server
|
||||
# config:
|
||||
# type: nacos
|
||||
# nacos:
|
||||
# server-addr: ${spring.cloud.nacos.discovery.server-addr}
|
||||
# namespace: ${spring.cloud.nacos.discovery.namespace}
|
||||
# group: SEATA_GROUP
|
||||
# data-id: seataServer.properties
|
||||
|
||||
# Swagger/OpenAPI 配置 (如果使用SpringDoc)
|
||||
# springdoc:
|
||||
# api-docs:
|
||||
# path: /v3/api-docs
|
||||
# swagger-ui:
|
||||
# path: /swagger-ui.html
|
||||
# display-request-duration: true
|
||||
# groups-order: DESC
|
||||
# group-configs:
|
||||
# - group: 'Order API'
|
||||
# paths-to-match: '/order/**'
|
||||
# packages-to-scan: com.trade.order.controller
|
||||
@@ -0,0 +1,102 @@
|
||||
spring:
|
||||
application:
|
||||
name: trade-order # 服务名
|
||||
cloud:
|
||||
nacos:
|
||||
# Nacos 作为注册中心的配置项
|
||||
discovery:
|
||||
server-addr: 127.0.0.1:8848 # Nacos 服务器地址
|
||||
# namespace: # Nacos 命名空间
|
||||
# group: # Nacos 分组
|
||||
# Nacos 作为配置中心的配置项
|
||||
config:
|
||||
server-addr: 127.0.0.1:8848 # Nacos 服务器地址
|
||||
file-extension: yaml # 文件后缀名
|
||||
# namespace: # Nacos 命名空间
|
||||
# group: # Nacos 分组
|
||||
# shared-configs: # 共享配置
|
||||
# - data-id: common.yaml # 共享配置的 Data ID
|
||||
# group: DEFAULT_GROUP # 共享配置的 Group
|
||||
# refresh: true # 是否动态刷新
|
||||
# extension-configs: # 拓展配置
|
||||
# - data-id:
|
||||
# group:
|
||||
# refresh: true
|
||||
|
||||
# HTTP Server 相关配置
|
||||
server:
|
||||
port: 8083 # 服务器端口,默认为 8080
|
||||
servlet:
|
||||
context-path: /trade-order # 应用的访问路径,默认为 /
|
||||
undertow:
|
||||
threads:
|
||||
# 设置 IO 线程数,它主要执行非阻塞的任务,它们会负责多个连接,默认设置每个 CPU 核心一个线程
|
||||
# 不要设置过大,如果过大,启动项目会报错:打开文件数过多
|
||||
io: 16
|
||||
# 阻塞任务线程池,当执行类似 Servlet 请求阻塞 IO 操作,Undertow 会从这个线程池中取得线程
|
||||
# 它的值设置取决于系统线程执行任务的阻塞系数,默认值是 IO 线程数 * 8
|
||||
worker: 256
|
||||
buffer-size: 1024 # 每块 buffer 的大小,越小空间占用越小,一旦设置过小,对于大的请求则会打开更多 buffer,所以建议不要设置过小
|
||||
direct-buffers: true # 是否分配的直接内存
|
||||
|
||||
# MyBatis Plus 相关配置
|
||||
mybatis-plus:
|
||||
# Mapper XML 文件的路径
|
||||
mapper-locations: classpath*:mapper/*.xml
|
||||
# 类型别名扫描包,多个package用逗号或者分号分隔
|
||||
type-aliases-package: com.stock.trade.order.dal.dataobject
|
||||
# 全局配置
|
||||
global-config:
|
||||
db-config:
|
||||
# 全局默认主键类型
|
||||
id-type: ASSIGN_ID
|
||||
# 逻辑删除配置
|
||||
logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
|
||||
logic-delete-value: true # 逻辑已删除值(默认为 1)
|
||||
logic-not-delete-value: false # 逻辑未删除值(默认为 0)
|
||||
banner: false # 是否关闭 MyBatis Plus 的 Banner
|
||||
# MyBatis Plus 的具体配置
|
||||
configuration:
|
||||
# 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射。
|
||||
map-underscore-to-camel-case: true
|
||||
# 对于数据库中值为 null 的字段,默认情况下,MyBatis 在返回的 Map 中并不会包含这个字段的键值对。
|
||||
# 通过设置 callSettersOnNulls 为 true,MyBatis 会在返回的 Map 中包含值为 null 的字段,并将其值设置为 null。
|
||||
call-setters-on-nulls: true
|
||||
# 对于数据库中值为 null 的字段,默认情况下,MyBatis 在返回的实体类对象中会将该字段设置为 null。
|
||||
# 通过设置 default-enum-type-handler 为 org.apache.ibatis.type.EnumOrdinalTypeHandler,MyBatis 会将枚举类型的字段值转换为其序数(ordinal)进行存储和查询。
|
||||
default-enum-type-handler: org.apache.ibatis.type.EnumOrdinalTypeHandler
|
||||
|
||||
# Spring Doc 相关配置
|
||||
springdoc:
|
||||
# Knife4j 配置
|
||||
knife4j:
|
||||
enable: true # 是否开启 Knife4j,默认为 false
|
||||
setting:
|
||||
language: zh_CN # API 列表的语言,可选 zh_CN、en_US
|
||||
# API 分组
|
||||
group-configs:
|
||||
- group: default
|
||||
paths-to-match: /**
|
||||
packages-to-scan: com.stock.trade.order.controller # 分组的 Controller 包路径
|
||||
|
||||
# Actuator 相关配置
|
||||
management:
|
||||
# /actuator/health 端点配置
|
||||
health:
|
||||
# 默认情况下,/actuator/health 只会展示整体的应用健康情况,通过设置为 SHOW_ALWAYS 后,可以展示详细的应用健康情况,例如:磁盘、数据库等。
|
||||
show-details: ALWAYS
|
||||
# /actuator/metrics 端点配置
|
||||
metrics:
|
||||
# /actuator/metrics 端点,默认情况下不会展示 tag 标签。通过设置为 true 后,可以展示 tag 标签,更加清晰。
|
||||
tags:
|
||||
application: ${spring.application.name}
|
||||
# /actuator 端点配置
|
||||
endpoints:
|
||||
# Web 端点的暴露范围,设置为 * 时,表示暴露所有端点。
|
||||
web:
|
||||
exposure:
|
||||
include: '*'
|
||||
# JMX 端点的暴露范围,设置为 * 时,表示暴露所有端点。
|
||||
jmx:
|
||||
exposure:
|
||||
include: '*'
|
||||
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<!-- 应用名称 -->
|
||||
<springProperty name="APP_NAME" scope="context" source="spring.application.name" defaultValue="trade-order"/>
|
||||
<!-- 日志路径 -->
|
||||
<property name="LOG_PATH" value="logs/${APP_NAME}"/>
|
||||
<!-- 日志格式 -->
|
||||
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 文件输出 -->
|
||||
<appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_PATH}/info.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||
<maxFileSize>100MB</maxFileSize>
|
||||
<maxHistory>30</maxHistory>
|
||||
<totalSizeCap>10GB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>INFO</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_PATH}/error.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_PATH}/error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||
<maxFileSize>100MB</maxFileSize>
|
||||
<maxHistory>30</maxHistory>
|
||||
<totalSizeCap>10GB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>ERROR</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 异步输出 -->
|
||||
<appender name="ASYNC_FILE_INFO" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<queueSize>256</queueSize>
|
||||
<appender-ref ref="FILE_INFO"/>
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNC_FILE_ERROR" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<queueSize>256</queueSize>
|
||||
<appender-ref ref="FILE_ERROR"/>
|
||||
</appender>
|
||||
|
||||
<!-- Spring Profile 相关配置 -->
|
||||
<springProfile name="dev,test">
|
||||
<logger name="com.stock.trade.order" level="DEBUG"/>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="ASYNC_FILE_INFO"/>
|
||||
<appender-ref ref="ASYNC_FILE_ERROR"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
<springProfile name="prod">
|
||||
<logger name="com.stock.trade.order" level="INFO"/>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="ASYNC_FILE_INFO"/>
|
||||
<appender-ref ref="ASYNC_FILE_ERROR"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user