采购订单管理系统用于管理企业的采购流程,包括采购订单、送货通知、收货等功能。系统主要实现了ERP系统与SRM系统之间的采购数据比对功能,帮助企业及时发现并处理两个系统之间的数据差异。
POST /api/dingtalk/sendMessage
{
"releaseNo": "检验单号"
}
参数说明:
releaseNo
(String, 必填): 检验单号,用于查询对应的钉钉消息内容{
"code": 200,
"message": null,
"successful": 0,
"data": "接收成功"
}
响应字段说明:
code
(Integer): 响应状态码,200表示成功,500表示失败message
(String): 错误信息,成功时为nullsuccessful
(Integer): 成功标识,0表示成功,1表示失败data
(String): 响应数据,成功时为"接收成功",失败时为"接收失败"请求示例:
curl -X POST http://localhost:9095/api/dingtalk/sendMessage \
-H "Content-Type: application/json" \
-d '{"releaseNo": "IQC202501270001"}'
成功响应示例:
{
"code": 200,
"message": null,
"successful": 0,
"data": "接收成功"
}
失败响应示例:
{
"code": 500,
"message": "检验单号不能为空",
"successful": 1,
"data": "接收失败"
}
接口会处理以下错误情况:
DINGTALK_MSG
表中有对应的记录更多详细的API使用说明、错误处理、最佳实践等内容,请参考 API_DOCUMENTATION.md 文件。
项目中包含以下主要数据表:
PURCHASE_ORDER_DETAIL
- 存储SRM系统采购订单明细数据MES_ROH_IN_DATA
- 存储ERP系统采购订单数据PURCHASE_ORDER_COMPARE
- 存储ERP与SRM系统数据比对结果CREATE TABLE PURCHASE_ORDER_DETAIL
(
ID NUMBER(19) PRIMARY KEY,
PRODUCT_CODE VARCHAR2(50),
PRODUCT_NAME VARCHAR2(100),
PRODUCT_SCALE VARCHAR2(200),
INNER_VENDOR_CODE VARCHAR2(50),
INNER_VENDOR_NAME VARCHAR2(100),
PROFIT_CENTER_CODE VARCHAR2(50),
PROFIT_CENTER_NAME VARCHAR2(100),
PURCHASE_TYPE NUMBER(2),
PO_ERP_NO VARCHAR2(50),
LINE_NO VARCHAR2(50),
PO_LINE_NO_SHOW VARCHAR2(50),
ERP_PURCHASE_DATE NUMBER(19),
ORDER_STATUS VARCHAR2(2),
PO_LINE_STATUS NUMBER(2),
PURCHASE_UNIT_CODE VARCHAR2(20),
PURCHASE_UNIT_NAME VARCHAR2(20),
TOTAL_ANSWER_QTY NUMBER(10),
TOTAL_DELIVERY_QTY NUMBER(10),
TOTAL_RECEIVE_QTY NUMBER(10),
TOTAL_RETURN_QTY NUMBER(10),
PO_WAIT_DELIVERY_QTY NUMBER(10),
SYS_WAIT_DELIVERY_QTY NUMBER(10),
RETURN_WAIT_DELIVERY_QTY NUMBER(10),
EXPECTED_DATE NUMBER(19),
NOTICE_QTY NUMBER(10),
NOTICE_UN_DELIVERY_QTY NUMBER(10),
TOTAL_REPORT_FINISH_QTY NUMBER(10),
ISSUED_SETS NUMBER(10),
RECEIVE_STATUS NUMBER(2),
VALID_FLAG NUMBER(1),
EXTEND_N01 VARCHAR2(200),
EXTEND_N02 VARCHAR2(200),
EXTEND_N03 VARCHAR2(200),
EXTEND_N04 VARCHAR2(200),
EXTEND_N05 VARCHAR2(200),
EXTEND_N06 VARCHAR2(200),
EXTEND_N07 VARCHAR2(200),
EXTEND_N08 VARCHAR2(200),
EXTEND_N09 VARCHAR2(200),
EXTEND_N10 VARCHAR2(200),
EXTEND_N11 VARCHAR2(200),
EXTEND_N12 VARCHAR2(200)
);
CREATE TABLE PURCHASE_ORDER_COMPARE
(
ID NUMBER(19) PRIMARY KEY,
BILL_NO VARCHAR2(50),
ORDER_LINE_ID VARCHAR2(50),
LINE_NO VARCHAR2(50),
ERP_PURCHASE_QTY NUMBER(10),
ERP_RECEIVED_QTY NUMBER(10),
ERP_WAIT_RECEIVE_QTY NUMBER(10),
SRM_PURCHASE_QTY NUMBER(10),
SRM_RECEIVED_QTY NUMBER(10),
SRM_WAIT_RECEIVE_QTY NUMBER(10),
DIFF_FLAG NUMBER(1),
DIFF_QTY NUMBER(10),
PRODUCT_CODE VARCHAR2(50),
PRODUCT_NAME VARCHAR2(100),
CREATE_TIME DATE,
UPDATE_TIME DATE
);
用于主键ID生成的序列:
CREATE SEQUENCE SEQ_PURCHASE_ORDER_DETAIL
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
CREATE SEQUENCE SEQ_PURCHASE_ORDER_COMPARE
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
如需修改或添加字段,请在相应的实体类文件中进行修改,并保持与数据库表结构同步。
如需修改数据库表结构,请按照以下步骤:
系统在处理大量数据时可能会遇到内存占用过高的问题,特别是在执行以下操作时:
syncPurchaseOrderDetails
方法)在启动应用时,可以通过以下JVM参数优化内存使用:
java -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar XkyCollection.jar
参数说明:
-Xms512m
:初始堆内存大小为512MB-Xmx1024m
:最大堆内存大小为1024MB(根据服务器实际可用内存调整)-XX:MetaspaceSize=128m
:初始元空间大小为128MB-XX:MaxMetaspaceSize=256m
:最大元空间大小为256MB-XX:+UseG1GC
:使用G1垃圾收集器,适合大内存应用-XX:MaxGCPauseMillis=200
:最大GC暂停时间目标为200毫秒 -Xloggc:/path/to/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
如果遇到内存溢出问题:
如果服务出现卡顿:
系统使用异步任务处理机制来执行耗时操作,避免阻塞主线程和定时任务调度线程。主要包括以下几个部分:
系统配置了两个专用线程池:
采购订单同步线程池 (purchaseTaskExecutor)
通用异步任务线程池 (taskExecutor)
所有定时任务都使用异步执行方式,防止互相阻塞:
使用 AtomicBoolean 标记任务执行状态,避免同一任务重复执行:
private final AtomicBoolean isRunning = new AtomicBoolean(false);
// 任务开始前检查
if(!isRunning.
compareAndSet(false,true)){
log.
info("上一次任务还在执行中,跳过本次执行");
return;
}
// 任务结束后重置状态
finally{
isRunning.
set(false);
}
这种机制确保了即使某个任务执行时间较长,也不会影响其他定时任务的正常执行。
在最近的优化中,我们进一步改进了系统性能和稳定性:
送货单数据处理优化
异步任务处理增强
错误处理改进
以下是一个典型的异步执行流程:
主线程: 开始处理100条数据
主线程: 将数据分为5批,每批20条
主线程: 提交批次1到异步线程池
主线程: 提交批次2到异步线程池
主线程: 提交批次3到异步线程池
主线程: 提交批次4到异步线程池
主线程: 提交批次5到异步线程池
主线程: 全部数据处理提交完成
异步线程1: 开始处理批次1
异步线程2: 开始处理批次2
异步线程3: 开始处理批次3
异步线程1: 批次1处理完成
异步线程1: 开始处理批次4
异步线程2: 批次2处理完成
异步线程2: 开始处理批次5
异步线程3: 批次3处理完成
异步线程1: 批次4处理完成
异步线程2: 批次5处理完成
这种方式确保了主线程不会被长时间阻塞,同时充分利用了系统资源进行并行处理。
系统集成了钉钉消息通知功能,用于在重要事件发生时向指定用户发送通知。主要包括以下几个部分:
通知场景:
通知方式:
钉钉用户信息存储在 DINGTALK_INFO
表中,表结构如下:
字段名 | 类型 | 说明 |
---|---|---|
id | Long | 主键 |
sid | Long | 职工ID |
phone | String | 电话号码 |
dingtalk_id | String | 钉钉用户ID |
is_send_dingtalk | Integer | 是否发送钉钉通知(1:是, 0:否) |
不合格检验单信息存储在 DINGTALK_MSG
表中,表结构如下:
字段名 | 类型 | 说明 |
---|---|---|
release_no | String | 检验单号 |
supp_name | String | 供应商名称 |
create_date | Date | 来料日期 |
project_codes | String | 项目代码 |
item_no | String | 料号 |
fname | String | 审核人 |
fng_handle | String | 处理方式 |
获取通知用户:
DINGTALK_INFO
表中筛选 is_send_dingtalk
为1的用户发送通知:
DINGTALK_MSG
表获取消息内容钉钉应用配置信息存储在 DataAcquisitionConfiguration
中:
// 钉钉应用Key
public static final String TALK_APP_KEY = "your_app_key";
// 钉钉应用Secret
public static final String TALK_APP_SECRET = "your_app_secret";
// 钉钉自定义机器人Token
public static final String CUSTOM_ROBOT_TOKEN = "your_robot_token";
要发送钉钉通知,可以调用 DingtalkInfoService
的 sendMessage
方法:
@Autowired
private DingtalkInfoService dingtalkInfoService;
// 发送不合格检验单通知
boolean result = dingtalkInfoService.sendMessage("检验单号");
系统配置了定时任务自动发送不合格检验单通知:
/**
* 定时发送不合格检验单钉钉通知
* 每小时检查一次是否有新的不合格检验单
*/
@Scheduled(cron = "0 0 */1 * * ?")
public void sendInspectionNotification() {
// 任务实现...
}
不合格检验单通知的格式如下:
供应商[xxx] 来料日期[yyyy-MM-dd] 项目[xxx] 料号[xxx]的不合格检验单被[xxx]审批为[xxx],请查收!
DINGTALK_MSG
表中必须有对应的记录