10 changed files with 281 additions and 11 deletions
@ -0,0 +1,127 @@ |
|||
package com.project.logistics.controller; |
|||
|
|||
import cn.hutool.core.date.DateUtil; |
|||
import cn.hutool.core.util.StrUtil; |
|||
import com.project.logistics.domain.entity.ApiRetryTaskEntity; |
|||
import com.project.logistics.domain.entity.LogisticsOrderEntity; |
|||
import com.project.logistics.domain.service.base.ApiRetryTaskService; |
|||
import com.project.logistics.domain.service.base.LogisticsOrderService; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import java.util.*; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Slf4j |
|||
@RestController |
|||
@RequestMapping("/api/task") |
|||
public class ApiRetryTaskController { |
|||
|
|||
@Autowired |
|||
private ApiRetryTaskService apiRetryTaskService; |
|||
|
|||
@Autowired |
|||
private LogisticsOrderService logisticsOrderService; |
|||
|
|||
@GetMapping("/{orderNo}") |
|||
public Map<String, Object> getTaskDetail(@PathVariable String orderNo) throws Exception { |
|||
// 1. 查订单信息
|
|||
LogisticsOrderEntity order = logisticsOrderService.getByOrderNo(orderNo); |
|||
if (order == null) { |
|||
return Map.of("code", 404, "msg", "订单不存在: " + orderNo); |
|||
} |
|||
|
|||
// 2. 查该订单所有任务(按创建时间正序,组成时间线)
|
|||
List<ApiRetryTaskEntity> tasks = apiRetryTaskService.lambdaQuery() |
|||
.eq(ApiRetryTaskEntity::getOrderNo, orderNo) |
|||
.orderByAsc(ApiRetryTaskEntity::getCreateTime) |
|||
.list(); |
|||
|
|||
// 3. 构时间线
|
|||
List<Map<String, Object>> timeline = tasks.stream().map(task -> { |
|||
Map<String, Object> item = new LinkedHashMap<>(); |
|||
item.put("actionCode", task.getActionCode()); |
|||
item.put("status", task.getTaskStatus()); |
|||
item.put("retryCount", task.getRetryCount() + "/" + task.getMaxRetries()); |
|||
item.put("createTime", formatTime(task.getCreateTime())); |
|||
item.put("executeTime", formatTime(task.getUpdateTime())); |
|||
item.put("nextExecuteTime", formatTime(task.getNextExecuteTime())); |
|||
item.put("errorMessage", task.getErrorMessage()); |
|||
|
|||
// 请求/响应报文太长的只显示前1000字符
|
|||
if (StrUtil.isNotBlank(task.getRequestData())) { |
|||
String req = task.getRequestData(); |
|||
item.put("requestData", req.length() > 1000 ? req.substring(0, 1000) + "..." : req); |
|||
} |
|||
if (StrUtil.isNotBlank(task.getResponseData())) { |
|||
String resp = task.getResponseData(); |
|||
item.put("responseData", resp.length() > 1000 ? resp.substring(0, 1000) + "..." : resp); |
|||
} |
|||
return item; |
|||
}).toList(); |
|||
|
|||
// 4. 汇总
|
|||
Map<String, Object> orderInfo = new LinkedHashMap<>(); |
|||
orderInfo.put("orderNo", order.getOrderNo()); |
|||
orderInfo.put("orderType", order.getOrderType()); |
|||
orderInfo.put("orderStatus", order.getOrderStatus()); |
|||
orderInfo.put("sfWaybillNo", order.getSfWaybillNo()); |
|||
orderInfo.put("resourceCode", order.getResourceCode()); |
|||
orderInfo.put("createTime", formatTime(order.getCreateTime())); |
|||
orderInfo.put("orderInfo", StrUtil.isNotBlank(order.getOrderInfo()) ? |
|||
(order.getOrderInfo().length() > 500 ? order.getOrderInfo().substring(0, 500) + "..." : order.getOrderInfo()) : null); |
|||
|
|||
return Map.of( |
|||
"code", 200, |
|||
"order", orderInfo, |
|||
"tasks", timeline, |
|||
"taskCount", tasks.size() |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* 可选:根据actionCode查看所有失败的任务(用于全局排查) |
|||
*/ |
|||
@GetMapping("/failed") |
|||
public Map<String, Object> listFailedTasks( |
|||
@RequestParam(required = false) String actionCode, |
|||
@RequestParam(defaultValue = "1") int page, |
|||
@RequestParam(defaultValue = "20") int size) { |
|||
|
|||
var query = apiRetryTaskService.lambdaQuery() |
|||
.in(ApiRetryTaskEntity::getTaskStatus, List.of("FAILED", "MAX_RETRY_FAILED")); |
|||
|
|||
|
|||
if (StrUtil.isNotBlank(actionCode)) { |
|||
query.eq(ApiRetryTaskEntity::getActionCode, actionCode); |
|||
} |
|||
|
|||
long total = query.count(); |
|||
List<ApiRetryTaskEntity> tasks = query |
|||
.orderByDesc(ApiRetryTaskEntity::getUpdateTime).list(); |
|||
|
|||
List<Map<String, Object>> list = tasks.stream().map(task -> { |
|||
Map<String, Object> item = new LinkedHashMap<>(); |
|||
item.put("orderNo", task.getOrderNo()); |
|||
item.put("actionCode", task.getActionCode()); |
|||
item.put("status", task.getTaskStatus()); |
|||
item.put("retryCount", task.getRetryCount()); |
|||
item.put("errorMessage", task.getErrorMessage()); |
|||
item.put("updateTime", formatTime(task.getUpdateTime())); |
|||
return item; |
|||
}).toList(); |
|||
//
|
|||
return Map.of( |
|||
"code", 200, |
|||
"data", list, |
|||
"total", total, |
|||
"page", page, |
|||
"size", size |
|||
); |
|||
} |
|||
|
|||
private String formatTime(Date date) { |
|||
return date == null ? null : DateUtil.format(date, "yyyy-MM-dd HH:mm:ss"); |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
package com.project.receive.controller; |
|||
|
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
@RestController |
|||
public class FaviconController { |
|||
@GetMapping("favicon.ico") |
|||
void returnNoFavicon() { |
|||
// 映射此路径但不做任何操作,默认返回 200 或 204
|
|||
} |
|||
} |
|||
@ -0,0 +1,113 @@ |
|||
server: |
|||
port: 9088 |
|||
spring: |
|||
main: |
|||
# 允许 Bean 覆盖,解决 dynamic-datasource 与 JPA 的初始化冲突 |
|||
allow-bean-definition-overriding: true |
|||
datasource: |
|||
url: jdbc:mysql://192.168.5.31:3306/auto_logistics?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&allowPublicKeyRetrieval=true&useSSL=false |
|||
username: root |
|||
password: Itc@123456 |
|||
driver-class-name: com.mysql.cj.jdbc.Driver |
|||
|
|||
# dynamic: |
|||
# primary: master |
|||
# datasource: |
|||
# master: |
|||
# driverClassName: com.mysql.cj.jdbc.Driver |
|||
# password: Itc@123456 |
|||
# url: jdbc:mysql://8.129.84.155:3306/auto_logistics?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&allowPublicKeyRetrieval=true&useSSL=false |
|||
# username: logistics_admin |
|||
|
|||
data: |
|||
redis: |
|||
host: 192.168.5.31 |
|||
port: 6379 |
|||
password: Itc@123456 |
|||
database: 5 |
|||
timeout: 5000ms |
|||
lettuce: |
|||
pool: |
|||
max-active: 8 |
|||
max-idle: 30 |
|||
max-wait: 10000 |
|||
min-idle: 10 |
|||
jpa: |
|||
hibernate: |
|||
# 确保是 update |
|||
ddl-auto: update |
|||
# 显式指定数据库平台 |
|||
database-platform: org.hibernate.dialect.MySQL8Dialect |
|||
show-sql: true |
|||
# 关键:告诉 Hibernate 自动扫描实体类 |
|||
open-in-view: true |
|||
properties: |
|||
hibernate: |
|||
dialect: org.hibernate.dialect.MySQL8Dialect |
|||
# 显式指定命名策略,防止大小写或下划线解析错误 |
|||
physical_strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl |
|||
sf: |
|||
api: |
|||
partnerId: Y847O1KA |
|||
secret: DgNS7ANgynXYcnhvu4moAe4rCAHkWvk9 |
|||
tokenUrl: https://bspgw.sf-express.com/oauth2/accessToken |
|||
baseUrl: https://bspgw.sf-express.com/std/service |
|||
channelCode: INC-VMOS-CORE |
|||
podSecret: b4fb275c23204056 |
|||
mybatis-plus: |
|||
configuration: |
|||
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开发环境下打印SQL |
|||
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl |
|||
map-underscore-to-camel-case: true # 开启驼峰命名 |
|||
global-config: |
|||
db-config: |
|||
id-type: assign_id # 使用雪花算法生成本地订单主键ID |
|||
webdav: |
|||
url: "http://192.168.5.31:8081" |
|||
username: "admin" |
|||
password: "123456" |
|||
logistics: |
|||
scanner: |
|||
enabled: true |
|||
# 允许在 10点、15-20点的 第 8 分和第 28 分唤醒 |
|||
# 唤醒时间点:10:08, 10:28, 15:08, 15:28, 16:08, 16:28 ... 20:28 |
|||
cron: "0 2,32 10-19 * * ?" |
|||
windows: |
|||
- name: "日间半小时波次" |
|||
# 10:00 开始,确保 10:02 第一波顺利执行 |
|||
startTime: "10:00" |
|||
# 【关键】设置为 19:15,这样 19:02 会执行,但 19:32 因为超过了 19:15 会被拦截 |
|||
endTime: "19:15" |
|||
# 设置为 25,确保 02 分和 32 分(30分钟间隔)能通过频率检查 |
|||
intervalMinutes: 25 |
|||
sample-scanner: |
|||
enabled: true |
|||
cron: "0 2,32 10-19 * * ?" |
|||
windows: |
|||
- name: "日间半小时波次" |
|||
# 10:00 开始,确保 10:02 第一波顺利执行 |
|||
startTime: "10:00" |
|||
# 【关键】设置为 19:15,这样 19:02 会执行,但 19:32 因为超过了 19:15 会被拦截 |
|||
endTime: "19:15" |
|||
# 设置为 25,确保 02 分和 32 分(30分钟间隔)能通过频率检查 |
|||
intervalMinutes: 25 |
|||
logging: |
|||
level: |
|||
# 强制打印 Hibernate 初始化过程 |
|||
org.hibernate.SQL: debug |
|||
org.hibernate.orm.deprecation: error |
|||
org.hibernate.tool.schema: debug |
|||
# 看看 Spring 到底有没有加载 JPA |
|||
org.springframework.orm.jpa: debug |
|||
u9-source: |
|||
url: jdbc:sqlserver://192.168.4.206;databaseName=DataCenter;encrypt=false;trustServerCertificate=true |
|||
username: sa |
|||
password: 'Hello2018.world' |
|||
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver |
|||
fixed-rule: |
|||
senderPayContact: '王盛荣' |
|||
senderMobile: '18998809792' |
|||
senderAddress: '广东省广州市番禺区石碁镇南荔东路56号' |
|||
monthlyCard: '0200467987' |
|||
scheduled-task: |
|||
owner: prod |
|||
Loading…
Reference in new issue