Merge remote-tracking branch 'origin/dev' into dev

tags/yfai-mes-ext-v1.0
jun 1 year ago
commit 76f35628d3

@ -0,0 +1,91 @@
package cn.estsh.i3plus.ext.mes.apiservice.controller.dbinterface;
import cn.estsh.i3plus.ext.mes.apiservice.dbinterface.MesSAPDbAdapter;
import cn.estsh.i3plus.icloud.softswitch.sdk.IBsSuitServiceCloud;
import cn.estsh.i3plus.mes.apiservice.serviceimpl.engine.script.EngineScriptManager;
import cn.estsh.i3plus.pojo.mes.dbinterface.MesInterfaceEnumUtil;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import cn.estsh.impp.framework.boot.util.ResultBean;
import cn.estsh.impp.framework.boot.util.SpringContextsUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Description : SAP
* @Reference :
* @Author : gsz
* @CreateDate : 2024-05-10 12:08
* @Modify:
**/
@RestController
@RequestMapping("/impp/white/mes-sap-if/")
@Api(description = "SAP接口同步控制器")
public class WmsSAPDbInterfaceController {
private static final Logger LOGGER = LoggerFactory.getLogger(WmsSAPDbInterfaceController.class);
@Autowired
IBsSuitServiceCloud bsSuitServiceCloud;
// 注入脚本引擎对象
@Autowired
private EngineScriptManager scriptManager;
@GetMapping(value = "sync-data/do")
@ApiOperation(value = "执行接口数据同步支持的参数SAP2MES, MES2SAP ")
public ResultBean doSyncSAPData(String syncParam) {
try {
// 判断作业参数是否支持
if (MesInterfaceEnumUtil.DIRECTION_TYPE.nameOf(syncParam) == -1) {
throw new IllegalArgumentException("不支持的同步参数:" + syncParam);
}
LOGGER.info("WmsSAPDbInterfaceController.doSyncSAPData start.....");
MesSAPDbAdapter wmsSAPDbAdapter = new MesSAPDbAdapter();
// new 的对象需要手工注入 bean
if (SpringContextsUtil.getApplicationContext() != null) {
SpringContextsUtil.getApplicationContext().
getAutowireCapableBeanFactory().autowireBean(wmsSAPDbAdapter);
}
wmsSAPDbAdapter.syncData(syncParam,null);
LOGGER.info("WmsSAPDbInterfaceController.doSyncSAPData end.....");
return new ResultBean(true).setMsg("SAP-->WMS接口数据同步执行成功");
} catch (Exception e) {
return ImppExceptionBuilder.newInstance().buildExceptionResult(e).setResultObject(e);
}
}
@GetMapping(value = "sync-data-id/do")
@ApiOperation(value = "按ID单个执行接口数据同步支持的参数SAP2MES, MES2SAP ")
public ResultBean doSyncSAPData(String syncParam,String o, String id) {
try {
// 判断作业参数是否支持
if (MesInterfaceEnumUtil.DIRECTION_TYPE.nameOf(syncParam) == -1) {
throw new IllegalArgumentException("不支持的同步参数:" + syncParam);
}
LOGGER.info("WmsSAPDbInterfaceController.doSyncSAPData start.....");
// 开始同步数据
// 一定要 new 对象,不然会有并发问题
MesSAPDbAdapter wmsSAPDbAdapter = new MesSAPDbAdapter();
// new 的对象需要手工注入 bean
if (SpringContextsUtil.getApplicationContext() != null) {
SpringContextsUtil.getApplicationContext().
getAutowireCapableBeanFactory().autowireBean(wmsSAPDbAdapter);
}
wmsSAPDbAdapter.syncData(syncParam, id);
LOGGER.info("WmsSAPDbInterfaceController.doSyncSAPData end.....");
return new ResultBean(true).setMsg("SAP-->WMS接口数据同步执行成功");
} catch (Exception e) {
return ImppExceptionBuilder.newInstance().buildExceptionResult(e).setResultObject(e);
}
}
}

@ -0,0 +1,479 @@
package cn.estsh.i3plus.ext.mes.apiservice.dbinterface;
import cn.estsh.i3plus.mes.apiservice.util.datatable.DataSet;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.platform.common.util.MesConstWords;
import cn.estsh.i3plus.platform.plugin.datasource.DynamicDataSourceProxy;
import cn.estsh.i3plus.pojo.base.codemaker.SnowflakeIdMaker;
import cn.estsh.i3plus.pojo.mes.dbinterface.MesInterfaceDataMapper;
import cn.estsh.i3plus.pojo.mes.dbinterface.MesInterfaceEnumUtil;
import cn.estsh.impp.framework.boot.util.ImppRedis;
import cn.estsh.impp.framework.boot.util.SpringContextsUtil;
import com.alibaba.fastjson.JSON;
import lombok.NoArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.sql.Connection;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* @Description :
*
* @Reference :
* @Author : rock.yu
* @CreateDate : 2019-06-11 19:34
* @Modify: 1.
**/
@Component
@NoArgsConstructor
public class MesSAPDbAdapter {
public static final Logger LOGGER = LoggerFactory.getLogger(WmsSAPDbWriter.class);
@Resource(name = "yfasDataSource")
private DynamicDataSourceProxy sapDataSourceProxy;
@Resource(name = "mesDataSource")
private DynamicDataSourceProxy mesDataSourceProxy;
@Value("${sync.redis.time:1800}")
private Integer redisTime;
private WmsSAPDbExpression wmsSAPDbExpression;
private WmsSAPDbWriter writer;
private WmsSAPDbReader reader;
private WmsSAPDbTranslator translator;
private MesSAPDbDataMapper dbDataMapper;
private Connection srcConn;
private Connection destConn;
private Connection mesConn;
@Resource(name = "redisMes")
private ImppRedis redisMes;
// 获取 IMPP ID
@Autowired
private SnowflakeIdMaker snowflakeIdMaker;
private WmsSAPDbWriter buildWriter(String groupName,
DynamicDataSourceProxy sapDataSourceProxy,
DynamicDataSourceProxy mesDataSourceProxy) throws Exception {
WmsSAPDbWriter wmsSAPDbWriter = null;
if (groupName.equals(MesInterfaceEnumUtil.DIRECTION_TYPE.SAP2MES.getName())) {
wmsSAPDbWriter = new WmsSAPDbWriter(sapDataSourceProxy, mesDataSourceProxy);
}
if (groupName.equals(MesInterfaceEnumUtil.DIRECTION_TYPE.MES2SAP.getName())) {
wmsSAPDbWriter = new WmsSAPDbWriter(mesDataSourceProxy, sapDataSourceProxy);
}
// new 的对象需要手工注入 bean
if (SpringContextsUtil.getApplicationContext() != null) {
SpringContextsUtil.getApplicationContext().
getAutowireCapableBeanFactory().autowireBean(wmsSAPDbWriter);
}
this.srcConn = wmsSAPDbWriter.getSrcDataSourceProxy().getWriteConnectionWithoutPool();
this.destConn = wmsSAPDbWriter.getDestDataSourceProxy().getWriteConnectionWithoutPool();
this.mesConn = mesDataSourceProxy.getWriteConnectionWithoutPool();
if (wmsSAPDbWriter != null) {
wmsSAPDbExpression = new WmsSAPDbExpression();
wmsSAPDbExpression.setSrcConn(mesConn);
// new 的对象需要手工注入 bean
if (SpringContextsUtil.getApplicationContext() != null) {
SpringContextsUtil.getApplicationContext().
getAutowireCapableBeanFactory().autowireBean(wmsSAPDbExpression);
}
wmsSAPDbWriter.setWmsSAPDbExpression(wmsSAPDbExpression);
}
return wmsSAPDbWriter;
}
private WmsSAPDbReader buildReader(String groupName,
DynamicDataSourceProxy sapDataSourceProxy,
DynamicDataSourceProxy mesDataSourceProxy) {
WmsSAPDbReader wmsSAPDbReader = null;
if (groupName.equals(MesInterfaceEnumUtil.DIRECTION_TYPE.SAP2MES.getName())) {
wmsSAPDbReader = new WmsSAPDbReader(sapDataSourceProxy);
}
if (groupName.equals(MesInterfaceEnumUtil.DIRECTION_TYPE.MES2SAP.getName())) {
wmsSAPDbReader = new WmsSAPDbReader(mesDataSourceProxy);
}
// if (groupName.equals(MesInterfaceEnumUtil.DIRECTION_TYPE.WMS2MES.getName())) {
// wmsSAPDbReader = new WmsSAPDbReader(mesDataSourceProxy);
// }
//
// if (groupName.equals(MesInterfaceEnumUtil.DIRECTION_TYPE.MES2WMS.getName())) {
// wmsSAPDbReader = new WmsSAPDbReader(mesDataSourceProxy);
// }
if (wmsSAPDbReader != null && SpringContextsUtil.getApplicationContext() != null) {
SpringContextsUtil.getApplicationContext().
getAutowireCapableBeanFactory().autowireBean(wmsSAPDbReader);
}
return wmsSAPDbReader;
}
private String getTime() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
return df.format(new Date());// new Date()为获取当前系统时间
}
/**
*
*
*/
public void syncData(String groupName, String id) throws Exception {
String redisKey = MesConstWords.SAP_TRANS_JOB_LOCK_TAG + ":" + groupName;
// 按ID单个调试时 key 要带上 id防止跟正常 job 冲突
if (id != null && !id.isEmpty()) {
redisKey = redisKey + ":" + id;
}
//添加redis锁半小时失效
if (redisMes.getObject(redisKey) != null) {
LOGGER.error("数据正在处理中不能并发处理RedisKey: {}", redisKey);
// 直接返回
return;
}
LOGGER.info("WmsSAPDbAdapter.syncData start...");
// 存放错误信息
StringBuilder errorMessage = new StringBuilder();
try {
redisMes.putObject(redisKey, "starting...", redisTime);
// 一次性拿到数据源连接,处理完成后再统一关闭
// 不需要在这里处理
//initConnection();
writer = buildWriter(groupName, sapDataSourceProxy, mesDataSourceProxy);
writer.setSrcConn(this.srcConn);
writer.setDestConn(this.destConn);
reader = buildReader(groupName, sapDataSourceProxy, mesDataSourceProxy);
reader.setSrcConn(this.srcConn);
// 映射关系始终从 WMS 表获取
dbDataMapper = new MesSAPDbDataMapper(mesDataSourceProxy);
dbDataMapper.setSrcConn(mesConn);
translator = new WmsSAPDbTranslator(wmsSAPDbExpression);
List<MesInterfaceDataMapper> dataMappers = dbDataMapper.readDataMappersBySQL(groupName, id, null, null, null);
LOGGER.info("WmsSAPDbAdapter.foreach dataMapper ...");
// 遍历所有已配置的接口表
for (MesInterfaceDataMapper dataMapper : dataMappers) {
try {
// 检查同步周期是否达到预设值
if (!checkSyncTime(dataMapper)) {
// 未到达同步时间,继续判断下一个接口
continue;
}
} catch (Exception e) {
LOGGER.error("同步数据发生异常", e);
}
try {
// 设置本此发送的 SID
dataMapper.setSid(snowflakeIdMaker.nextId());
// 用当前配置信息初始化对象
reader.setDataMapper(dataMapper);
writer.setDataMapper(dataMapper);
translator.setDataMapper(dataMapper);
// 从来源表读取数据
LOGGER.info("WmsSAPDbAdapter.syncData softAdapter:{} read data", dataMapper.getSoftAdaptorCode());
List<Map<String, Object>> srcData = reader.readData();
// 来源表中没有数据,跳过当前循环,处理下一个表
if (srcData == null || srcData.size() == 0) {
continue;
}
LOGGER.info("WmsSAPDbAdapter.syncData softAdapter:{},size:{}", dataMapper.getSoftAdaptorCode(), srcData.size());
// 把来源表转换成目标表
LOGGER.info("WmsSAPDbAdapter.syncData softAdapter:{} start translateData", dataMapper.getSoftAdaptorCode());
DataSet dataSet = translator.translateData(srcData);
LOGGER.info("WmsSAPDbAdapter.syncData softAdapter:{} end translateData", dataMapper.getSoftAdaptorCode());
// 没有获取到转换后的数据,不执行写入操作,处理下一个表
if (dataSet == null || dataSet.size() == 0) {
continue;
}
LOGGER.info("WmsSAPDbAdapter.syncData.saveData softAdapter:{} start", dataMapper.getSoftAdaptorCode());
// 写入目标表信息并更新来源表标志字段
writer.saveData(srcData, dataSet, reader.getOriginReadData());
LOGGER.info("WmsSAPDbAdapter.syncData.saveData softAdapter:{} end", dataMapper.getSoftAdaptorCode());
String updateSql = String.format("update mes_interface_data_mapper set" +
" last_sync_time ='%s' where id =%s", TimeTool.getNowTime(true), dataMapper.getId());
mesDataSourceProxy.execute(mesConn, updateSql);
mesConn.setAutoCommit(false);
// 把当前时间写入 redis便于跟踪
redisMes.putObject(redisKey, getTime(), 1800);
dbDataMapper.updateWmsInterfaceDataMapperLastSyncTimeById(dataMapper.getId());
// 更新下次执行时间
dbDataMapper.updateNextSyncTime(dataMapper);
} catch (Exception e) {
LOGGER.error("接口同步错误! 接口对象:" + JSON.toJSONString(dataMapper) + "\n" + e.getMessage());
errorMessage.append("接口同步错误! 接口对象:" + JSON.toJSONString(dataMapper) + "\n");
errorMessage.append(e.getMessage() + ", " + e.getCause());
errorMessage.append("\n\n");
}
}
} catch (Exception e) {
LOGGER.error("WmsSAPDbAdapter: " + e.getStackTrace().toString());
throw e;
} finally {
// 解除REDIS执行锁这个要放到第一行否则执行有异常时可能导致 KEY 删不掉
redisMes.deleteKey(redisKey);
// 手工关闭连接
//closeConnection();
mesDataSourceProxy.closeConnectionWithoutPoll(this.srcConn);
mesDataSourceProxy.closeConnectionWithoutPoll(this.destConn);
mesDataSourceProxy.closeConnectionWithoutPoll(this.mesConn);
}
LOGGER.info("WmsSAPDbAdapter.syncData stop...");
// 执行过程中出现了异常,抛出异常
if (errorMessage.length() > 0) {
throw new RuntimeException(errorMessage.toString());
}
}
/**
*
*
* @param dataMapper
* @return
*/
private boolean checkSyncTime(MesInterfaceDataMapper dataMapper) {
try {
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
int syncFrequency = dataMapper.getSyncFrequency();//间隔分钟数
String lastSyncTimes = dataMapper.getLastSyncTime();//时分秒的三种数据
LocalDateTime localDateTimeSatrt = LocalDateTime.parse(lastSyncTimes, df);
LocalDateTime localDateTimeEnd = LocalDateTime.now();
Duration duration = Duration.between(localDateTimeSatrt, localDateTimeEnd);
long minutes = duration.toMinutes();
// 间隔时间未到达预设的同步周期
if (minutes < syncFrequency) {
String msg = String.format("上次同步频率时间相差太短!syncFrequency=%s " +
"--- localDateTimeSatrt=%s " +
"--- localDateTimeEnd=%s",
syncFrequency, localDateTimeSatrt, localDateTimeEnd);
LOGGER.info(msg);
return false;
}
} catch (Exception e) {
}
return true;
}
/**
* +
*
*/
public void syncDataByOrganizeCode(String groupName, String organizeCode, List<String> destBeanNameList, List<String> destBeanNameNotList) throws Exception {
//分组代码+工厂代码作业KEY值
String redisKey = MesConstWords.SAP_TRANS_JOB_LOCK_TAG + ":" + groupName + ":" + organizeCode + destBeanNameList + destBeanNameNotList;
//添加redis锁半小时失效
if (redisMes.getObject(redisKey) != null) {
LOGGER.error("数据正在处理中不能并发处理RedisKey: {}", redisKey);
// 直接返回
return;
}
LOGGER.info("WmsSAPDbAdapter.syncData organizeCode:{},start...", organizeCode);
// 存放错误信息
StringBuilder errorMessage = new StringBuilder();
try {
redisMes.putObject(redisKey, "starting...", redisTime);
// 一次性拿到数据源连接,处理完成后再统一关闭
// 不需要在这里处理
//initConnection();
writer = buildWriter(groupName, sapDataSourceProxy, mesDataSourceProxy);
writer.setSrcConn(this.srcConn);
writer.setDestConn(this.destConn);
reader = buildReader(groupName, sapDataSourceProxy, mesDataSourceProxy);
reader.setSrcConn(this.srcConn);
// 映射关系始终从 WMS 表获取
dbDataMapper = new MesSAPDbDataMapper(mesDataSourceProxy);
dbDataMapper.setSrcConn(mesConn);
translator = new WmsSAPDbTranslator(wmsSAPDbExpression);
List<MesInterfaceDataMapper> dataMappers = dbDataMapper.readDataMappersBySQL(groupName, null, organizeCode, destBeanNameList, destBeanNameNotList);
LOGGER.info("WmsSAPDbAdapter.foreach dataMapper ...");
// 遍历所有已配置的接口表
for (MesInterfaceDataMapper dataMapper : dataMappers) {
try {
// 检查同步周期是否达到预设值
if (!checkSyncTime(dataMapper)) {
// 未到达同步时间,继续判断下一个接口
continue;
}
} catch (Exception e) {
LOGGER.error("同步数据发生异常", e);
}
try {
// 设置本此发送的 SID
dataMapper.setSid(snowflakeIdMaker.nextId());
// 用当前配置信息初始化对象
reader.setDataMapper(dataMapper);
writer.setDataMapper(dataMapper);
translator.setDataMapper(dataMapper);
// 从来源表读取数据
LOGGER.info("WmsSAPDbAdapter.syncData softAdapter:{} read data", dataMapper.getSoftAdaptorCode());
List<Map<String, Object>> srcData = reader.readData();
// 来源表中没有数据,跳过当前循环,处理下一个表
if (srcData == null || srcData.size() == 0) {
continue;
}
LOGGER.info("WmsSAPDbAdapter.syncData softAdapter:{},size:{}", dataMapper.getSoftAdaptorCode(), srcData.size());
// 把来源表转换成目标表
LOGGER.info("WmsSAPDbAdapter.syncData softAdapter:{} start translateData", dataMapper.getSoftAdaptorCode());
DataSet dataSet = translator.translateData(srcData);
LOGGER.info("WmsSAPDbAdapter.syncData softAdapter:{} end translateData", dataMapper.getSoftAdaptorCode());
// 没有获取到转换后的数据,不执行写入操作,处理下一个表
if (dataSet == null || dataSet.size() == 0) {
continue;
}
LOGGER.info("WmsSAPDbAdapter.syncData.saveData softAdapter:{} start", dataMapper.getSoftAdaptorCode());
// 写入目标表信息并更新来源表标志字段
writer.saveData(srcData, dataSet, reader.getOriginReadData());
LOGGER.info("WmsSAPDbAdapter.syncData.saveData softAdapter:{} end", dataMapper.getSoftAdaptorCode());
String updateSql = String.format("update mes_interface_data_mapper set" +
" last_sync_time ='%s' where id =%s", TimeTool.getNowTime(true), dataMapper.getId());
mesDataSourceProxy.execute(mesConn, updateSql);
mesConn.setAutoCommit(false);
// 把当前时间写入 redis便于跟踪
redisMes.putObject(redisKey, getTime(), 1800);
dbDataMapper.updateWmsInterfaceDataMapperLastSyncTimeById(dataMapper.getId());
// 更新下次执行时间
dbDataMapper.updateNextSyncTime(dataMapper);
} catch (Exception e) {
LOGGER.error("接口同步错误! 接口对象:" + JSON.toJSONString(dataMapper) + "\n" + e.getMessage());
errorMessage.append("接口同步错误! 接口对象:" + JSON.toJSONString(dataMapper) + "\n");
errorMessage.append(e.getMessage() + ", " + e.getCause());
errorMessage.append("\n\n");
}
}
} catch (Exception e) {
LOGGER.error("WmsSAPDbAdapter: " + e.getStackTrace().toString());
throw e;
} finally {
// 解除REDIS执行锁这个要放到第一行否则执行有异常时可能导致 KEY 删不掉
redisMes.deleteKey(redisKey);
// 手工关闭连接
//closeConnection();
mesDataSourceProxy.closeConnectionWithoutPoll(this.srcConn);
mesDataSourceProxy.closeConnectionWithoutPoll(this.destConn);
mesDataSourceProxy.closeConnectionWithoutPoll(this.mesConn);
}
LOGGER.info("WmsSAPDbAdapter.syncData organizeCode:{} stop...", organizeCode);
// 执行过程中出现了异常,抛出异常
if (errorMessage.length() > 0) {
throw new RuntimeException(errorMessage.toString());
}
}
/**
* Rock.Yu 2019-07-26
* 2
* 2 MyCAT
*
*
* @throws Exception
*/
// private void initConnection() throws Exception {
// sapDataSourceProxy.setReadConnHold(sapDataSourceProxy.getWriteConnectionWithoutPool());
// sapDataSourceProxy.setWriteConnHold(sapDataSourceProxy.getWriteConnectionWithoutPool());
// mesDataSourceProxy.setReadConnHold(mesDataSourceProxy.getWriteConnectionWithoutPool());
// mesDataSourceProxy.setWriteConnHold(mesDataSourceProxy.getWriteConnectionWithoutPool());
// mesDataSourceProxy.setReadConnHold(mesDataSourceProxy.getWriteConnectionWithoutPool());
// mesDataSourceProxy.setWriteConnHold(mesDataSourceProxy.getWriteConnectionWithoutPool());
// swebDataSourceProxy.setReadConnHold(swebDataSourceProxy.getWriteConnectionWithoutPool());
// swebDataSourceProxy.setWriteConnHold(swebDataSourceProxy.getWriteConnectionWithoutPool());
// }
//
// private void closeConnection() throws Exception {
// try {
// sapDataSourceProxy.closeConnectionWithoutPoll(sapDataSourceProxy.getReadConnHold());
// sapDataSourceProxy.closeConnectionWithoutPoll(sapDataSourceProxy.getWriteConnHold());
// mesDataSourceProxy.closeConnectionWithoutPoll(mesDataSourceProxy.getReadConnHold());
// mesDataSourceProxy.closeConnectionWithoutPoll(mesDataSourceProxy.getWriteConnHold());
// mesDataSourceProxy.closeConnectionWithoutPoll(mesDataSourceProxy.getReadConnHold());
// mesDataSourceProxy.closeConnectionWithoutPoll(mesDataSourceProxy.getWriteConnHold());
// swebDataSourceProxy.closeConnectionWithoutPoll(swebDataSourceProxy.getReadConnHold());
// swebDataSourceProxy.closeConnectionWithoutPoll(swebDataSourceProxy.getWriteConnHold());
// } catch (Exception e) {
// LOGGER.error(e.getStackTrace().toString());
// }
// }
}

@ -0,0 +1,171 @@
package cn.estsh.i3plus.ext.mes.apiservice.dbinterface;
import cn.estsh.i3plus.ext.mes.pojo.util.CronUtil;
import cn.estsh.i3plus.ext.mes.pojo.util.OverwriteStringJoin;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.platform.plugin.datasource.DynamicDataSourceProxy;
import cn.estsh.i3plus.pojo.mes.dbinterface.MesInterfaceDataMapper;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @Description :
* @Reference :
* @Author : gsz
* @CreateDate : 2024-05-10 16:08
* @Modify:
**/
public class MesSAPDbDataMapper extends WmsSAPDbSyncBase {
public static final Logger LOGGER = LoggerFactory.getLogger(MesSAPDbDataMapper.class);
private DynamicDataSourceProxy mesDataSourceProxy;
@Getter
@Setter
private Connection srcConn;
public MesSAPDbDataMapper(DynamicDataSourceProxy mesDataSourceProxy) {
this.mesDataSourceProxy = mesDataSourceProxy;
}
/**
* SQL
* @return
* @throws Exception
*/
public List<MesInterfaceDataMapper> readDataMappersBySQL(String groupName, String id,String organizeCode,List<String> destBeanNameList,List<String> destBeanNameNotList) throws Exception {
String sqlString = "select * from mes_interface_data_mapper " +
"where is_deleted=2 and is_valid=1 and group_name='"
+ groupName + "' ";
// 如果 id 不为空,则按照单个 id 查询
if (id != null && !id.isEmpty()) {
// 带 id 调试时不考虑删除和有效2个字段
sqlString = sqlString.replace("is_deleted=2 and is_valid=1 and", " ");
sqlString = sqlString + " and id=" + id;
}
// 如果 organizeCode 不为空,则按照 organizeCode 查询
if (organizeCode != null && !organizeCode.isEmpty()) {
// 带 id 调试时不考虑删除和有效2个字段
sqlString = sqlString + " and organize_code= '" + organizeCode +"'";
}
// 按照目标表进行拆分参数不为空则in
if (!CollectionUtils.isEmpty(destBeanNameList)) {
sqlString = sqlString + " and dest_bean_name in ("+ OverwriteStringJoin.join(",",destBeanNameList)+")";
LOGGER.info("接口映射添加目标表参数sql为:{}",sqlString);
}
// 按照目标表进行拆分,参数不为空则 not in
if (!CollectionUtils.isEmpty(destBeanNameNotList)) {
sqlString = sqlString + " and dest_bean_name not in ("+ OverwriteStringJoin.join(",",destBeanNameNotList)+")";
LOGGER.info("接口映射不添加目标表参数sql为:{}",sqlString);
}
sqlString = sqlString + " order by seq";
List<Map<String, Object>> rows = mesDataSourceProxy.queryMapList(sqlString, srcConn);
if (rows == null || rows.size() == 0) {
LOGGER.error("not set data in talbe: mes_interface_data_mapper !");
throw new IllegalArgumentException("not set data in talbe: mes_interface_data_mapper !");
}
List<MesInterfaceDataMapper> dataMappers = new ArrayList<>();
for(Map<String, Object> row : rows) {
MesInterfaceDataMapper mapper = new MesInterfaceDataMapper();
mapper.setSeq(this.getSafetyInteger(row.get("seq")));
mapper.setOrganizeCode(this.getSafetyString(row.get("organize_code")));
mapper.setSrcGetLimit(this.getSafetyInteger(row.get("src_get_limit")));
mapper.setDataSource(this.getSafetyString(row.get("src_data_source")));
mapper.setSrcTableName(this.getSafetyString(row.get("src_table_name")));
mapper.setSrcOrderBy(this.getSafetyString(row.get("src_order_by")));
mapper.setSrcWhere(this.getSafetyString(row.get("src_where")));
mapper.setSrcGroupColumns(this.getSafetyString(row.get("src_group_columns")));
mapper.setSrcUpdateSync(this.getSafetyString(row.get("src_update_sync")));
mapper.setSrcPkColumns(this.getSafetyString(row.get("src_pk_columns")));
mapper.setCopyByOrgs(this.getSafetyString(row.get("copy_py_orgs")));
mapper.setDestBeanName(this.getSafetyString(row.get("dest_bean_name")));
mapper.setDestPkProperties(this.getSafetyString(row.get("dest_pk_properties")));
mapper.setDestColumnMapping(this.getSafetyString(row.get("dest_column_mapping")));
mapper.setBusiRoute(this.getSafetyString(row.get("busi_route")));
mapper.setId(this.getSafetyLong(row.get("id")));
mapper.setCopyByOrgs(this.getSafetyString(row.get("copy_by_orgs")));
mapper.setSyncCron(this.getSafetyString(row.get("sync_cron")));
mapper.setNextSyncTime(this.getSafetyString(row.get("next_sync_time")));
mapper.setSyncFrequency(this.getSafetyInteger(row.get("sync_frequency")));
mapper.setLastSyncTime(this.getSafetyString(row.get("last_sync_time")));
mapper.setSoftDataType(this.getSafetyInteger(row.get("soft_data_type")));
// 与软适配和脚本对接相关的属性
mapper.softAdaptorCode = this.getSafetyString(row.get("soft_adapator_code"));
mapper.scriptNo = this.getSafetyString(row.get("script_no"));
mapper.useScriptPull = this.getSafetyInteger(row.get("use_script_pull"));
mapper.useScriptPush = this.getSafetyInteger(row.get("use_script_push"));
mapper.useScriptMark = this.getSafetyInteger(row.get("use_script_mark"));
mapper.useScriptFilter = this.getSafetyInteger(row.get("use_script_filter"));
// 备份表名
mapper.setCutToTableName(this.getSafetyString(row.get("cut_to_table_name")));
dataMappers.add(mapper);
}
return dataMappers;
}
public void updateWmsInterfaceDataMapperLastSyncTimeById(Long id) throws SQLException {
StringBuffer sql = new StringBuffer("update mes_interface_data_mapper");
sql.append(" set last_sync_time='" + TimeTool.getNowTime(true) + "'");
sql.append(" where id=" + id);
mesDataSourceProxy.execute(sql.toString());
}
/**
*
* @param mapper
* @throws SQLException
*/
public void updateNextSyncTime(MesInterfaceDataMapper mapper) throws SQLException {
if (mapper != null && StringUtils.isNotEmpty(mapper.getSyncCron())
&& StringUtils.isNotEmpty(mapper.getNextSyncTime())) {
// 计算下次执行时间
String nextSyncTime = CronUtil.getRecentTriggerTime(mapper.getSyncCron());
String sqlString = String.format("update mes_interface_data_mapper set next_sync_time='%s' where id=%s",
nextSyncTime, mapper.getId());
mesDataSourceProxy.execute(sqlString);
LOGGER.debug("接口ID {} 名称 {} 下次执行时间更新为 {}", mapper.getId(), mapper.getInterfaceName(), nextSyncTime);
}
}
/**
*
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
/**
* hashCode
* @return
*/
@Override
public int hashCode() {
return super.hashCode();
}
}

@ -0,0 +1,21 @@
package cn.estsh.i3plus.ext.mes.apiservice.dbinterface;
/**
* @Description :
* @Reference :
* @Author : rock.yu
* @CreateDate : 2019-10-14 19:14
* @Modify:
* 1.
**/
public class WmsSAPDbConstWords {
// 脚本读取数据的方法名入参WmsInterfaceDataMapper 返回值: List<Map<String, Object>>
public static final String SCRIPT_PULL_FUN_NAME = "readData";
// 脚本写入目标数据的方法名入参WmsInterfaceDataMapperList<Map<String, Object>> 返回值void
public static final String SCRIPT_PUSH_FUN_NAME = "saveDestData";
// 脚本更新来源数据标志的方法名入参WmsInterfaceDataMapperList<Map<String, Object>> 返回值void
public static final String SCRIPT_MARK_FUN_NAME = "saveSrcData";
// 脚本过滤来源数据的方法名,入参: List<Map<String, Object>> 返回值List<Map<String, Object>>
public static final String SCRIPT_FILTER_FUN_NAME = "filterData";
}

@ -0,0 +1,121 @@
package cn.estsh.i3plus.ext.mes.apiservice.dbinterface;
import cn.estsh.i3plus.mes.apiservice.serviceimpl.engine.script.EngineScriptManager;
import cn.estsh.impp.framework.boot.util.SpringContextsUtil;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.sql.Connection;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @Description :
* @Reference :
* @Author : gsz
* @CreateDate : 2024-05-10 16:08
* @Modify:
**/
@Component
public class WmsSAPDbExpression {
/**
* ID
*/
@Autowired
private WmsSAPDbID wmsSAPDbID;
/**
*
*/
@Autowired
private EngineScriptManager engineScriptManager;
@Getter
@Setter
private Connection srcConn;
WmsSAPDbQuery wmsSAPDbQuery = null;
// 更新时不处理的特殊标志
public static final String NOT_TRANS = "NotTrans";
/**
*
* @param expString
* @param varMap
* @throws Exception
*/
public Object parse(String expString, Map<String, Object> varMap) {
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext ctx = new StandardEvaluationContext();
// 先设置基础变量
ctx.setVariables(getConstVarMap());
// 再设置临时变量
if (varMap != null) {
ctx.setVariables(varMap);
}
return parser.parseExpression(expString).getValue(ctx);
}
/**
*
* @param expString
* @return
* @throws Exception
*/
public Object parse(String expString) {
return parse(expString, null);
}
/**
*
*/
public Map<String, Object> getConstVarMap() {
if (wmsSAPDbQuery == null) {
wmsSAPDbQuery = new WmsSAPDbQuery();
// 初始化查询对象
wmsSAPDbQuery.setSrcConn(srcConn);
// new 的对象需要手工注入 bean
if (SpringContextsUtil.getApplicationContext() != null) {
SpringContextsUtil.getApplicationContext().
getAutowireCapableBeanFactory().autowireBean(wmsSAPDbQuery);
}
}
Map<String, Object> constVarMap = new HashMap<>();
constVarMap.put("date", getFormatDate("yyyy-MM-dd"));
constVarMap.put("time", getFormatDate("HH:mm:ss"));
constVarMap.put("sap_date", getFormatDate("yyyyMMdd"));
constVarMap.put("sap_time", getFormatDate("HHmmss"));
constVarMap.put("now", getFormatDate("yyyy-MM-dd HH:mm:ss"));
constVarMap.put("Q", wmsSAPDbQuery);
constVarMap.put("ID", wmsSAPDbID);
constVarMap.put("I", wmsSAPDbID);
constVarMap.put("S", engineScriptManager);
return constVarMap;
}
/**
*
* @param format
* @return
*/
public static String getFormatDate(String format) {
DateFormat df = new SimpleDateFormat(format);
return df.format(new Date());
}
}

@ -0,0 +1,39 @@
package cn.estsh.i3plus.ext.mes.apiservice.dbinterface;
import cn.estsh.i3plus.pojo.base.codemaker.SnowflakeIdMaker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.UUID;
/**
* @Description : IDGUID
* @Reference :
* @Author : gsz
* @CreateDate : 2024-05-10 16:08
* @Modify:
**/
@Component
public class WmsSAPDbID {
// 获取 IMPP ID
@Autowired
private SnowflakeIdMaker snowflakeIdMaker;
/**
* ID线
* @return
*/
public synchronized long nextId() {
return snowflakeIdMaker.nextId();
}
/**
* GUIDGlobals Unique Identifiers
* @return
*/
public synchronized String guid() {
return UUID.randomUUID().toString();
}
}

@ -0,0 +1,105 @@
package cn.estsh.i3plus.ext.mes.apiservice.dbinterface;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.platform.plugin.datasource.DynamicDataSourceProxy;
import cn.estsh.i3plus.pojo.base.codemaker.SnowflakeIdMaker;
import cn.estsh.impp.framework.boot.util.LocaleUtils;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.sql.Connection;
/**
* @Description :
* @Reference :
* @Author : gsz
* @CreateDate : 2024-05-10 16:08
* @Modify:
**/
@Component
public class WmsSAPDbQuery {
public static final Logger LOGGER = LoggerFactory.getLogger(WmsSAPDbQuery.class);
public static boolean needI18N = true;
// @Resource(name = "wmsDataSource")
// private DynamicDataSourceProxy wmsDataSourceProxy;
@Resource(name = "mesDataSource")
private DynamicDataSourceProxy mesDataSourceProxy;
@Autowired
private SnowflakeIdMaker snowflakeIdMaker;
@Getter
@Setter
private MesSAPDbDataMapper mesSAPDbDataMapper;
@Getter
@Setter
private Connection srcConn;
/**
*
*
* @param orderType
* @return
*/
private String getOrderTypeTable(String orderType,String organizeCode) {
String sqlTableName = "";
switch (orderType.trim().toUpperCase()) {
case "ASN":
sqlTableName = "wms_doc_asn_details_"+organizeCode;
break;
case "PO":
sqlTableName = "wms_doc_po_details";
break;
case "MOVE":
sqlTableName = "wms_doc_movement_details_"+organizeCode;
break;
case "CS":
sqlTableName = "wms_doc_cs_details_"+organizeCode;
break;
default:
break;
}
if (StringUtils.isEmpty(sqlTableName)) {
throw new RuntimeException("单据类型必须是 ASN/PO/MOVE/CS 中的一种!");
}
return sqlTableName;
}
/**
*
*
* @param value
* @param srcFormat
* @param destFormat
* @return
* @throws Exception
*/
public String strFormat(String value, String srcFormat, String destFormat) throws Exception {
return TimeTool.parseStringFormat(value, srcFormat, destFormat);
}
/**
*
*
* @param msg
* @param args String.format
* @return
*/
public static String lz(String msg, Object... args) {
if (!needI18N) {
return String.format(msg, args);
}
return String.format(LocaleUtils.getLocaleRes(msg), args);
}
}

@ -0,0 +1,256 @@
package cn.estsh.i3plus.ext.mes.apiservice.dbinterface;
import cn.estsh.i3plus.mes.apiservice.serviceimpl.engine.script.EngineScriptManager;
import cn.estsh.i3plus.mes.apiservice.util.datatable.DataTable;
import cn.estsh.i3plus.platform.plugin.datasource.DynamicDataSourceProxy;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.mes.dbinterface.MesInterfaceDataMapper;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
/**
* @Description :
* DAO
* @Reference :
* @Author : rock.yu
* @CreateDate : 2019-06-11 19:34
* @Modify: 1. 2019-10-14 19:13
* 1.
**/
@Component
@NoArgsConstructor
public class WmsSAPDbReader extends WmsSAPDbSyncBase {
public static final Logger LOGGER = LoggerFactory.getLogger(WmsSAPDbReader.class);
// 动态数据源,靠外部调用类传入此对象
private DynamicDataSourceProxy dataSourceProxy;
// 数据库读写用的数据源
@Getter
@Setter
private Connection srcConn;
/**
* 使
*/
@Getter
private List<Map<String, Object>> originReadData = null;
// 脚本引擎
@Autowired
private EngineScriptManager engineScriptManager;
public WmsSAPDbReader(DynamicDataSourceProxy dataSourceProxy) {
this.dataSourceProxy = dataSourceProxy;
}
public WmsSAPDbReader(MesInterfaceDataMapper dataMapper) {
super(dataMapper);
}
/**
*
* @return
* @throws Exception
*/
public List<Map<String, Object>> readData() throws Exception {
List<Map<String, Object>> resultList;
this.originReadData = null;
if (this.dataMapper == null) {
throw new IllegalArgumentException("not set data mapper!");
}
// 配置了使用脚本引擎获取数据
if (this.dataMapper.getUseScriptPull() == CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) {
resultList = getDataByScript();
} else {
resultList = getDataBySQL();
}
// 配置了使用脚本引擎过滤来源数据
if (this.dataMapper.getUseScriptFilter() == CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) {
// 保留原始数据集
this.originReadData = resultList;
resultList = getDataByFilter(resultList);
}
return resultList;
}
/**
* SQL
* @return
* @throws Exception
*/
private List<Map<String, Object>> getDataBySQL() throws Exception {
// 构建查询语句
String sqlString = buildQuerySQL(isMSSQL());
LOGGER.info("WmsSAPDbReader.getDataBySQL:{}", sqlString);
return dataSourceProxy.queryMapList(sqlString, srcConn);
}
/**
* SQL
* @param isMSSql MSSQL MSSQL MYSQL
* @return SQL
*/
public String buildQuerySQL(boolean isMSSql) {
String sqlString;
if (isMSSql) {
if (StringUtils.isEmpty(this.dataMapper.getSrcGroupColumns())) {
sqlString = "select top " + this.dataMapper.getSrcGetLimit()
+ " * from " + this.dataMapper.getSrcTableName() + " model "
+ " where " + this.dataMapper.getSrcWhere()
+ " order by " + this.dataMapper.getSrcOrderBy();
} else {
sqlString = "select * from " + this.dataMapper.getSrcTableName() + " model "
+ " where " + this.dataMapper.getSrcWhere()
+ " and " + this.dataMapper.getSrcGroupColumns() + " in ( "
+ " select top " + this.dataMapper.getSrcGetLimit() + " "
+ this.dataMapper.getSrcGroupColumns()
+ " from " + this.dataMapper.getSrcTableName()
+ " where " + this.dataMapper.getSrcWhere()
+ " group by " + this.dataMapper.getSrcGroupColumns()
+ " )" + " order by " + this.dataMapper.getSrcOrderBy();
}
} else {
if (StringUtils.isEmpty(this.dataMapper.getSrcGroupColumns())) {
sqlString = "select * from " + this.dataMapper.getSrcTableName() + " model "
+ " where " + this.dataMapper.getSrcWhere()
+ " order by " + this.dataMapper.getSrcOrderBy()
+ " limit " + this.dataMapper.getSrcGetLimit();
} else {
sqlString = "select * from " + this.dataMapper.getSrcTableName()
+ " where " + this.dataMapper.getSrcWhere()
+ " and " + this.dataMapper.getSrcGroupColumns() + " in ( "
+ " select * from ( "
+ " select " + this.dataMapper.getSrcGroupColumns()
+ " from " + this.dataMapper.getSrcTableName() + " model "
+ " where " + this.dataMapper.getSrcWhere()
+ " group by " + this.dataMapper.getSrcGroupColumns()
+ " order by " + this.dataMapper.getSrcOrderBy() + " limit "
+ this.dataMapper.getSrcGetLimit() + " ) as ds ) order by "+ this.dataMapper.getSrcOrderBy();
}
}
return sqlString;
}
/**
*
* @return
* @throws Exception
*/
private List<Map<String, Object>> getDataByScript() throws Exception {
String scriptNo = this.dataMapper.getScriptNo();
Object returnObj;
// 如果脚本编号配置的是 groovy 文件,就直接调用文件,便于运行中打断点调试
if (scriptNo.indexOf(".groovy") > 0) {
returnObj = engineScriptManager.invokeGroovyScript(
scriptNo,
WmsSAPDbConstWords.SCRIPT_PULL_FUN_NAME,
this.dataMapper);
} else {
returnObj = engineScriptManager.invokeFuncation(
this.dataMapper.getOrganizeCode(),
scriptNo,
WmsSAPDbConstWords.SCRIPT_PULL_FUN_NAME,
this.dataMapper);
}
if (!(returnObj instanceof List)) {
throw new RuntimeException("Script pull data result object type error !");
}
return (List<Map<String, Object>>)returnObj;
}
/**
*
* @param srcData
* @return
* @throws Exception
*/
private List<Map<String, Object>> getDataByFilter(List<Map<String, Object>> srcData) throws Exception {
String scriptNo = this.dataMapper.getScriptNo();
Object returnObj;
// 如果脚本编号配置的是 groovy 文件,就直接调用文件,便于运行中打断点调试
if (scriptNo.indexOf(".groovy") > 0) {
returnObj = engineScriptManager.invokeGroovyScript(
scriptNo,
WmsSAPDbConstWords.SCRIPT_FILTER_FUN_NAME,
this.dataMapper, srcData);
} else {
returnObj = engineScriptManager.invokeFuncation(
this.dataMapper.getOrganizeCode(),
this.dataMapper.getScriptNo(),
WmsSAPDbConstWords.SCRIPT_FILTER_FUN_NAME,
this.dataMapper, srcData);
}
if (!(returnObj instanceof List)) {
throw new RuntimeException("Script filter data result object type error !");
}
return (List<Map<String, Object>>)returnObj;
}
/**
* MSSQL
* @return
* @throws Exception
*/
private boolean isMSSQL() throws Exception {
return srcConn
.getMetaData().getURL().contains("sqlserver");
}
/**
* DataTable
* @return
*/
public DataTable readDataTable() {
DataTable dataTable = null;
try {
dataTable = new DataTable(this.dataMapper.getSrcTableName(), this.readData());
} catch (Exception e) {
e.printStackTrace();
}
return dataTable;
}
/**
*
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
/**
* hashCode
* @return
*/
@Override
public int hashCode() {
return super.hashCode();
}
}

@ -0,0 +1,246 @@
package cn.estsh.i3plus.ext.mes.apiservice.dbinterface;
import cn.estsh.i3plus.pojo.mes.dbinterface.MesInterfaceDataMapper;
import cn.estsh.i3plus.pojo.wms.dbinterface.MappingItem;
import cn.estsh.i3plus.pojo.wms.dbinterface.UpdateSyncItem;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import org.springframework.stereotype.Component;
import java.util.*;
/**
* @Description :
* @Reference :
* @Author : rock.yu
* @CreateDate : 2019-06-11 19:34
* @Modify:
* 1.
**/
@Data
@Component
public class WmsSAPDbSyncBase {
/**
*
*/
protected MesInterfaceDataMapper dataMapper;
/**
*
*/
protected List<String> scrOrderBy;
/**
*
*/
protected List<String> srcWhere;
/**
*
*/
protected List<UpdateSyncItem> srcUpdateSync;
/**
*
*/
protected List<String> srcPkColumn;
/**
*
*/
protected List<String> copyByOrg;
/**
*
*/
protected List<String> destBeanName;
/**
*
*/
protected List<String> destPkProperty;
/**
*
*/
protected List<MappingItem> mappingItem;
public WmsSAPDbSyncBase() { }
public WmsSAPDbSyncBase(MesInterfaceDataMapper dataMapper) {
setDataMapper(dataMapper);
}
public void setDataMapper(MesInterfaceDataMapper dataMapper) {
this.dataMapper = dataMapper;
this.setScrOrderBy(getSplitArray(dataMapper.srcOrderBy));
this.setSrcWhere(getSplitArray(dataMapper.srcWhere));
this.setSrcUpdateSync(getJSONItems(dataMapper.srcUpdateSync, UpdateSyncItem.class));
this.setSrcPkColumn(getSplitArray(dataMapper.srcPkColumns));
this.setCopyByOrg(getSplitArray(dataMapper.copyByOrgs));
this.setDestPkProperty(getSplitArray(dataMapper.destPkProperties));
this.setMappingItem(sortedMappingItem(getJSONItems(dataMapper.destColumnMapping, MappingItem.class)));
if (this.getMappingItem() == null) {
this.setMappingItem(new ArrayList<>());
}
// 依赖于 this.mappingItem 的值,赋值顺序不能变
this.setDestBeanName(this.getDistinctDestBeanName());
}
/**
*
* @param beanName
* @return
*/
public List<String> getDestPkByBeanName(String beanName) {
List<String> pkList = new ArrayList<>();
for (MappingItem item : this.getMappingItem()) {
if (item.getDestBeanName().equals(beanName) && isPk(item)) {
pkList.add(item.getDestName());
}
}
return pkList;
}
/**
*
* @param item
* @return
*/
private Boolean isPk(MappingItem item) {
return item.getDestPk() != null && item.getDestPk() == 1;
}
/**
*
* @return
*/
private List<String> getDistinctDestBeanName() {
Map<String, String> beanNamesMap = new HashMap<>();
for (MappingItem item : this.getMappingItem()) {
if (!beanNamesMap.containsKey(item.getDestBeanName())) {
beanNamesMap.put(item.getDestBeanName(), null);
}
}
return new ArrayList<String>(beanNamesMap.keySet());
}
/**
*
* @param text
* @return
*/
private List<String> getSplitArray(String text) {
if (text == null || text.isEmpty()) {
return null;
}
String[] items = text.split(",");
return Arrays.asList(items);
}
/**
*
* @param jsonString JSON
* @return
*/
public <T> List<T> getJSONItems(String jsonString, Class<T> objClass) {
if (jsonString == null || jsonString.isEmpty()) {
return null;
}
return JSONObject.parseArray(jsonString, objClass);
}
/**
* seq MappingItem
* @param mappingItems
* @return
*/
public List<MappingItem> sortedMappingItem(List<MappingItem> mappingItems) {
if (mappingItems == null) {
return null;
}
if (mappingItems.size() <= 1) {
return mappingItems;
}
Collections.sort(mappingItems);
return mappingItems;
}
/**
*
* @param obj
* @return
*/
public Integer getSafetyInteger(Object obj) {
if (obj == null) {
return 0;
}
return Integer.valueOf(String.valueOf(obj));
}
/**
*
*
* @param obj
* @return
*/
public Long getSafetyLong(Object obj) {
if (obj == null) {
return 0L;
}
return Long.valueOf(String.valueOf(obj));
}
/**
*
* @param obj
* @return
*/
public String getSafetyString(Object obj) {
if (obj == null) {
return "";
}
return String.valueOf(obj);
}
/**
*
* JSON
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj instanceof WmsSAPDbSyncBase) {
WmsSAPDbSyncBase newObj = (WmsSAPDbSyncBase)obj;
if (JSONObject.toJSONString(this).
equals(JSONObject.toJSONString(newObj))) {
return true;
}
}
return false;
}
/**
* hashCode key Hash
* JSON
* @return
*/
@Override
public int hashCode() {
return JSONObject.toJSONString(this).hashCode();
}
}

@ -0,0 +1,246 @@
package cn.estsh.i3plus.ext.mes.apiservice.dbinterface;
import cn.estsh.i3plus.mes.apiservice.util.datatable.DataRow;
import cn.estsh.i3plus.mes.apiservice.util.datatable.DataSet;
import cn.estsh.i3plus.mes.apiservice.util.datatable.DataTable;
import cn.estsh.i3plus.mes.apiservice.util.datatable.DataTypes;
import cn.estsh.i3plus.pojo.mes.dbinterface.MesInterfaceDataMapper;
import cn.estsh.i3plus.pojo.wms.dbinterface.MappingItem;
import com.alibaba.fastjson.JSONObject;
import lombok.Getter;
import lombok.Setter;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Description :
*
* @Reference :
* @Author : rock.yu
* @CreateDate : 2019-06-11 19:34
* @Modify:
* 1.
**/
@Component
public class WmsSAPDbTranslator extends WmsSAPDbSyncBase {
@Getter
@Setter
private WmsSAPDbExpression wmsSAPDbExpression;
public WmsSAPDbTranslator() { }
public WmsSAPDbTranslator(WmsSAPDbExpression wmsSAPDbExpression) {
this.wmsSAPDbExpression = wmsSAPDbExpression;
}
public WmsSAPDbTranslator(MesInterfaceDataMapper dataMapper) {
super(dataMapper);
}
/**
*
* @param originData
* @return
* @throws Exception
*/
public DataSet translateData(List<Map<String, Object>> originData) throws Exception {
if (this.dataMapper == null) {
throw new IllegalArgumentException("not set data mapper!");
}
// 原始数据表
DataTable originTable = new DataTable(this.dataMapper.srcTableName, originData);
// 构建目标数据集
DataSet destDataSet = buildDestDataSet(this.getDestBeanName(), this.getMappingItem());
for(DataRow row : originTable.getRows()) {
// 拆分数据行
Map<String, DataRow> destRowsMap = splitDataRow(destDataSet, row);
// 把拆分好的数据行放到目标数据表中
for(DataTable table : destDataSet.getDataTables()) {
if (destRowsMap.containsKey(table.getTableName())) {
table.addRow(destRowsMap.get(table.getTableName()));
}
}
}
return destDataSet;
}
/**
*
* @param dataSet
* @param originRow
* @return
* @throws Exception
*/
private Map<String, DataRow> splitDataRow(DataSet dataSet, DataRow originRow) throws Exception {
// 最终返回的 Map
Map<String, DataRow> rowsMap = new HashMap<>();
// 构建临时数据行对象
for (DataTable table : dataSet.getDataTables()) {
rowsMap.put(table.getTableName(), table.newRow());
}
// 遍历字段映射列表
for (MappingItem item : this.getMappingItem()) {
// 原始表中有这个字段
if (originRow.getColumns().contains(item.getSrcName())) {
// 把来源数据行的值放到对应的目标数据行中
rowsMap.get(item.getDestBeanName()).
setValue(item.getDestName(), originRow.getValue(item.getSrcName()));
} else {
// 原始表中没有这个字段,用预设的默认值填充此字段
rowsMap.get(item.getDestBeanName()).
setValue(item.getDestName(), item.getDefaultValue());
}
}
// 遍历第二遍,进行默认值的表达式计算,此时所有属性都已赋值,在配置字段映射关系就可以不用管属性的配置顺序
// 如果强制要求配置字段映射关系时把有表达式的属性放在后面,也可以不用再循环一遍,直接在上面的循环解析即可
for (MappingItem item : this.getMappingItem()) {
if (item.getDefaultValue() != null // 不是空对象
&& (item.getDefaultValue() instanceof String) // 字符串类型
&& !item.getDefaultValue().toString().isEmpty() // 字符串不为空
&& item.getDefaultValue().toString().indexOf("#") > -1) { // 包含表达式
// 取出当前字段的值
//Object valueObj = rowsMap.get(item.getDestBeanName()).getValue(item.getDestName());
// 把当前行的数据(原始数据行和目标数据行都参与计算)和表达式进行计算
Object valueObj = parseDefaultValue(
combineRowMap(originRow.getItemMap(), rowsMap.get(item.getDestBeanName()).getItemMap()),
item.getDefaultValue());
// 把计算后的值设置回数据行中
rowsMap.get(item.getDestBeanName()).setValue(item.getDestName(), valueObj);
}
}
return rowsMap;
}
/**
*
* _o ()
* @param originMap
* @param destMap
* @return Map
*/
private Map<String, Object> combineRowMap(Map<String, Object> originMap, Map<String, Object> destMap) {
Map<String, Object> combineMap = new HashMap<>();
// if (originMap != null && originMap.size() > 0) {
// for(Map.Entry<String, Object> entry : originMap.entrySet()) {
// // 来源表的字段名加上 _o 后缀,防止跟目标表的字段重名
// combineMap.put(entry.getKey() + "_o", entry.getValue());
// }
// }
if (originMap != null && originMap.size() > 0) {
combineMap.putAll(originMap);
}
if (destMap != null && destMap.size() > 0) {
combineMap.putAll(destMap);
}
return combineMap;
}
/**
*
* @param destBeanNames
* @param mappingItems
* @return
* @throws Exception
*/
private DataSet buildDestDataSet(List<String> destBeanNames, List<MappingItem> mappingItems) throws Exception {
// 目标数据集
DataSet destDataSet = new DataSet();
// 构建目标表
for(String tableName : destBeanNames) {
DataTable table = new DataTable(tableName);
// 构建目标表的结构
for(MappingItem item : mappingItems) {
// 当前字段属于这张表,并且目标字段不为空
if (item.getDestBeanName().equals(tableName) && item.destName != null && !item.destName.isEmpty()) {
// 加入字段
// 此处暂不进行表达式计算
table.addColumn(item.getDestName(), DataTypes.getDataType(item.getDefaultValue()));
}
}
// 把数据表加入数据集
destDataSet.add(table);
}
return destDataSet;
}
/**
*
* @param rowMap Map
* @param defaultValue
* @return
*/
private Object parseDefaultValue(Map<String, Object> rowMap, Object defaultValue) throws Exception {
if (defaultValue == null) {
return null;
}
// 不是字符串类型,直接返回
if (!(defaultValue instanceof String)) {
return defaultValue;
}
// 没有包含表达式,直接返回
if (defaultValue.toString().indexOf("#") == -1) {
return defaultValue;
}
Object objResult;
try {
objResult = wmsSAPDbExpression.parse(defaultValue.toString(), rowMap);
} catch (Exception e) {
e.printStackTrace();
throw new IllegalArgumentException("表达式计算异常,请检查表达式语法是否正确! exp: "
+ defaultValue.toString() + " Exception: "
+ e.getMessage() + " rowMap:"
+ JSONObject.toJSONString(rowMap));
}
// 计算后返回
return objResult;
}
/**
*
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
/**
* hashCode
* @return
*/
@Override
public int hashCode() {
return super.hashCode();
}
}

@ -0,0 +1,313 @@
package cn.estsh.i3plus.ext.mes.apiservice.dbinterface;
import cn.estsh.i3plus.icloud.softswitch.sdk.IBsSuitServiceCloud;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
import cn.estsh.i3plus.pojo.base.bean.BaseResultBean;
import cn.estsh.i3plus.pojo.base.enumutil.BlockSoftSwitchEnumUtil;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.softswitch.bean.BsSuitCase;
import cn.estsh.i3plus.pojo.softswitch.bean.BsSuitCaseParam;
import cn.estsh.i3plus.pojo.softswitch.bean.BsSuitDataDetail;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import cn.estsh.impp.framework.boot.util.ResultBean;
import lombok.NoArgsConstructor;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
@NoArgsConstructor
public class WmsSAPDbUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(WmsSAPDbUtil.class);
// 软适配微服调用代理对象
@Autowired
IBsSuitServiceCloud bsSuitServiceCloud;
/**
* XML
* @param xmlString XML
* @param tableList XML
* @return List<Map<String, Object>>
* @throws Exception XML
*/
public List<Map<String, Object>> convertXmlToList(String xmlString, List<String> tableList)
throws Exception {
Document document = DocumentHelper.parseText(xmlString);
Element rootElement = document.getRootElement();
List<Element> elements = rootElement.selectNodes("//*");
List<Map<String, Object>> rows = new ArrayList<>();
for (Element element : elements) {
if (tableList.get(0).equals(element.getName())) {
Map<String, Object> row = new HashMap<>();
parseElement(element, row, rows, tableList);
}
}
return rows;
}
/**
* XML
* @param xmlString XML
* @param tables
* @return List<Map<String, Object>>
* @throws Exception XML
*/
public List<Map<String, Object>> convertXmlToList(String xmlString, String tables)
throws Exception {
List<String> tableList = this.getListByString(tables);
if (tableList == null || tableList.size() == 0) {
return null;
}
return convertXmlToList(xmlString, tableList);
}
/**
* List<Map<String, Object> XML
* @param listData
* @param rootNodeName
* @param nodeName
* @param rootClassName
* @param nodeClassName
* @return XML
*/
public String convertListToXml(List<Map<String, Object>> listData, String rootNodeName, String nodeName,
String rootClassName, String nodeClassName) {
if (listData == null || listData.size() == 0) {
throw new RuntimeException("listData is null ! ");
}
StringBuilder sb = new StringBuilder();
if (rootNodeName != null && !rootNodeName.isEmpty()) {
sb.append(String.format("<%s class=\"%s\">\n", rootNodeName, rootClassName));
}
for(Map<String, Object> row : listData) {
sb.append(String.format("<%s class=\"%s\">\n", nodeName, nodeClassName));
for (Map.Entry<String, Object> entry : row.entrySet()) {
sb.append(String.format("<%s>%s</%s>\n", entry.getKey(), entry.getValue(), entry.getKey()));
}
sb.append(String.format("</%s>\n", nodeName));
}
if (rootNodeName != null && !rootNodeName.isEmpty()) {
sb.append(String.format("</%s>\n", rootNodeName));
}
return sb.toString();
}
/**
* ID SID
* @param listData
* @param sid ID
*/
public void packSID(List<Map<String, Object>> listData, Long sid) {
if (listData == null || listData.size() == 0) {
return;
}
for (Map<String, Object> row : listData) {
row.put("SID", sid);
}
}
/**
* List<String>
* @param strList
* @return List<String>
*/
public List<String> getListByString(String strList) {
if (strList == null || strList.isEmpty()) {
return null;
}
String[] arrList = strList.split(",");
return Arrays.asList(arrList);
}
/**
* XML
* @param element XML
* @param row
* @param rows
* @param tableList
*/
private void parseElement(Element element, Map<String, Object> row,
List<Map<String, Object>> rows, List<String> tableList) {
List<Element> childElements = element.elements();
if (childElements != null) {
// 先遍历没有子节点的属性,因为有属性值在子节点之后,所以必须先遍历一遍
for (Element eleData : childElements) {
if (eleData.elements() == null || eleData.elements().size() == 0) {
row.put(element.getName() + "_" + eleData.getName(), eleData.getStringValue().trim());
}
}
// 再遍历包含子节点的属性
for (Element ele : childElements) {
if (tableList.contains(ele.getName()) || ele.getName().startsWith("List")) {
parseElement(ele, row, rows, tableList);
}
}
// 末尾元素,开始新增行
if (element.getName().equals(tableList.get(tableList.size() - 1))) {
HashMap<String, Object> newRow = new HashMap<>();
newRow.putAll(row);
rows.add(newRow);
}
}
}
/**
*
* @param suitCaseCode
* @param packageCount
* @return
*/
public ResultBean readSoftSwitchPackage(String suitCaseCode, Integer packageCount) {
BaseResultBean<BsSuitDataDetail> resultBean =
bsSuitServiceCloud.findLastUnProcessBsSuitDataDetailBySuitCaseCode(suitCaseCode, packageCount);
if (resultBean.isSuccess()) {
List<BsSuitDataDetail> bsSuitDataDetailList = resultBean.getResultList();
return new ResultBean(true).setResultObject(bsSuitDataDetailList);
} else {
throw ImppExceptionBuilder.newInstance()
.setSystemID(CommonEnumUtil.SOFT_TYPE.WMS.getCode())
.setErrorCode(ImppExceptionEnum.CLOUD_CALL_EXCEPTION.getCode())
.setErrorDetail("微服调用失败: " + resultBean.getErrorMsg())
.build();
}
}
/**
*
* @param packageIds
* @return
*/
public boolean ackSoftSwitchPackage(Long[] packageIds) {
BaseResultBean<BsSuitDataDetail> resultBean =
bsSuitServiceCloud.updateBsSuitDataDetailProcessStateByIds(
packageIds, BlockSoftSwitchEnumUtil.SUIT_PROCESS_STATUS.PROCESS.getValue());
if (resultBean.isSuccess()) {
return true;
} else {
throw ImppExceptionBuilder.newInstance()
.setSystemID(CommonEnumUtil.SOFT_TYPE.WMS.getCode())
.setErrorCode(ImppExceptionEnum.CLOUD_CALL_EXCEPTION.getCode())
.setErrorDetail("微服调用失败: " + resultBean.getErrorMsg())
.build();
}
}
/**
*
* @param suitCaseCode
* @param xmlString XML
*/
public void sendSoftSwitchPackage(String suitCaseCode, String xmlString) {
LOGGER.info("WmsSAPDbUtil.sendSoftSwitchPackage input:suitCaseCode{} ;xmlString:{}",suitCaseCode,xmlString);
BsSuitCase bsSuitCase = new BsSuitCase();
// 设置适配器代码
bsSuitCase.setSuitCaseCode(suitCaseCode);
bsSuitCase.setBsSuitCaseParamList(new ArrayList<>());
bsSuitCase.setParamXml(xmlString);
BaseResultBean<BsSuitDataDetail> resultBean =
bsSuitServiceCloud.executeBsSuitCase(bsSuitCase);
LOGGER.info("bsSuitServiceCloud.executeBsSuitCase result:{}", resultBean);
if (!resultBean.isSuccess()) {
throw ImppExceptionBuilder.newInstance()
.setSystemID(CommonEnumUtil.SOFT_TYPE.WMS.getCode())
.setErrorCode(ImppExceptionEnum.CLOUD_CALL_EXCEPTION.getCode())
.setErrorDetail("bsSuitServiceCloud.executeBsSuitCase failed: %s; suitCaseCode:%s; xmlString:%s", resultBean.getErrorMsg(), suitCaseCode, xmlString)
.build();
}
}
/**
*
*
* @param suitCaseCode
* @param xmlString XML
*/
public void sendSoftSwitchPackageWithParams(String suitCaseCode, String xmlString) {
BsSuitCase bsSuitCase = new BsSuitCase();
// 设置适配器代码
bsSuitCase.setSuitCaseCode(suitCaseCode);
List<BsSuitCaseParam> bsSuitCaseParamList = new ArrayList<>();
BsSuitCaseParam bsSuitCaseParam = new BsSuitCaseParam();
bsSuitCaseParam.setParamName("params");
bsSuitCaseParam.setParamValue(xmlString);
bsSuitCaseParamList.add(bsSuitCaseParam);
bsSuitCase.setBsSuitCaseParamList(bsSuitCaseParamList); // 多个数据
BaseResultBean<BsSuitDataDetail> resultBean =
bsSuitServiceCloud.executeBsSuitCase(bsSuitCase);
LOGGER.info("bsSuitServiceCloud.executeBsSuitCase result:{}",resultBean);
if (!resultBean.isSuccess()) {
throw ImppExceptionBuilder.newInstance()
.setSystemID(CommonEnumUtil.SOFT_TYPE.WMS.getCode())
.setErrorCode(ImppExceptionEnum.CLOUD_CALL_EXCEPTION.getCode())
.setErrorDetail("bsSuitServiceCloud.executeBsSuitCase failed: %s; suitCaseCode:%s; xmlString:%s",resultBean.getErrorMsg(), suitCaseCode, xmlString)
.build();
}
}
/**
*
*
* @param suitCaseCode
* @param resultMap
*/
public void sendSoftSwitchPackageWithMap(String suitCaseCode, Map<String, Object> resultMap) {
BsSuitCase bsSuitCase = new BsSuitCase();
// 设置适配器代码
bsSuitCase.setSuitCaseCode(suitCaseCode);
List<BsSuitCaseParam> bsSuitCaseParamList = new ArrayList<>();
Iterator<String> iterator = resultMap.keySet().iterator();
while(iterator.hasNext()) {
String key = iterator.next();
BsSuitCaseParam bsSuitCaseParam = new BsSuitCaseParam();
bsSuitCaseParam.setParamName(key);
bsSuitCaseParam.setParamValue(resultMap.get(key));
bsSuitCaseParamList.add(bsSuitCaseParam);
}
bsSuitCase.setBsSuitCaseParamList(bsSuitCaseParamList); // 多个数据
BaseResultBean<BsSuitDataDetail> resultBean =
bsSuitServiceCloud.executeBsSuitCase(bsSuitCase);
LOGGER.info("bsSuitServiceCloud.executeBsSuitCase result:{}",resultBean);
if (!resultBean.isSuccess()) {
throw ImppExceptionBuilder.newInstance()
.setSystemID(CommonEnumUtil.SOFT_TYPE.WMS.getCode())
.setErrorCode(ImppExceptionEnum.CLOUD_CALL_EXCEPTION.getCode())
.setErrorDetail("bsSuitServiceCloud.executeBsSuitCase failed: %s; suitCaseCode:%s, data:%s", resultBean.getErrorMsg(), suitCaseCode, resultMap.toString())
.build();
}
}
}

@ -0,0 +1,533 @@
package cn.estsh.i3plus.ext.mes.apiservice.dbinterface;
import cn.estsh.i3plus.mes.apiservice.serviceimpl.engine.script.EngineScriptManager;
import cn.estsh.i3plus.mes.apiservice.util.datatable.DataRow;
import cn.estsh.i3plus.mes.apiservice.util.datatable.DataSet;
import cn.estsh.i3plus.mes.apiservice.util.datatable.DataTable;
import cn.estsh.i3plus.platform.plugin.datasource.DynamicDataSourceProxy;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.util.StringUtil;
import cn.estsh.i3plus.pojo.wms.dbinterface.UpdateSyncItem;
import cn.estsh.i3plus.pojo.wms.dbinterface.WmsInterfaceEnumUtil;
import cn.estsh.impp.framework.boot.util.ImppRedis;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Description :
*
* @Reference :
* @Author : rock.yu
* @CreateDate : 2019-06-11 19:34
* @Modify: 1. 2019-10-14 19:13
**/
@Component
@NoArgsConstructor
public class WmsSAPDbWriter extends WmsSAPDbSyncBase {
public static final Logger LOGGER = LoggerFactory.getLogger(WmsSAPDbWriter.class);
public static final int REQ_COUNT = 20;
@Getter
private DynamicDataSourceProxy srcDataSourceProxy;
@Getter
private DynamicDataSourceProxy destDataSourceProxy;
// 脚本引擎
@Autowired
private EngineScriptManager engineScriptManager;
@Resource(name = "redisMes")
private ImppRedis redisMes;
@Getter
@Setter
private WmsSAPDbExpression wmsSAPDbExpression;
// 数据库读写用的数据源
@Getter
@Setter
private Connection srcConn;
@Getter
@Setter
private Connection destConn;
public WmsSAPDbWriter(DynamicDataSourceProxy srcDataSourceProxy, DynamicDataSourceProxy destDataSourceProxy) {
this.srcDataSourceProxy = srcDataSourceProxy;
this.destDataSourceProxy = destDataSourceProxy;
}
/**
*
* originDataList 使
*/
public void saveData(List<Map<String, Object>> srcDataList, DataSet destDataSet, List<Map<String, Object>> originDataList) throws Exception {
// 先保存目标数据
// 配置了使用脚本引擎保存数据
try {
if (this.dataMapper.getUseScriptPush() == CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) {
callScript(destDataSet, WmsSAPDbConstWords.SCRIPT_PUSH_FUN_NAME);
} else {
saveDestData(destDataSet);
}
} catch (Exception e) {
//记录sap过来的数据 超过一定的请求次数放弃数据
if (WmsInterfaceEnumUtil.DIRECTION_TYPE.SAP2WMS.getName().equals(this.dataMapper.getGroupName())) {
if (!CollectionUtils.isEmpty(srcDataList)) {
String key = this.dataMapper.getSoftAdaptorCode() + ":" + srcDataList.get(0).get("SID");
if (redisMes.hasKey(key)) {
int reqCount = Integer.parseInt(String.valueOf(redisMes.getObject(key)));
if (reqCount + 1 > REQ_COUNT) {
if (this.dataMapper.getUseScriptMark() == CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) {
callScriptMark(srcDataList, originDataList);
} else {
callSqlMark(srcDataList, originDataList);
}
LOGGER.error("超过请求次数放弃数据 WmsSAPDbWriter.saveData SoftAdaptorCode:{}, SID:{}", this.dataMapper.getSoftAdaptorCode(), srcDataList.get(0).get("SID"));
return;
} else {
redisMes.incr(key, 1);
}
} else {
redisMes.incr(key, 1);
}
}
}
throw e;
}
// 再更新来源数据的同步标志
// 配置了使用脚本引擎标记来源数据
if (this.dataMapper.getUseScriptMark() == CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()) {
callScriptMark(srcDataList, originDataList);
} else {
callSqlMark(srcDataList, originDataList);
}
}
/**
* SQL
* @param srcDataList
* @param originDataList
* @throws Exception
*/
private void callSqlMark(List<Map<String, Object>> srcDataList, List<Map<String, Object>> originDataList)
throws Exception {
if (originDataList != null) {
saveSrcData(originDataList);
} else {
saveSrcData(srcDataList);
}
}
/**
*
* @param srcDataList
* @param originDataList
* @throws Exception
*/
private void callScriptMark(List<Map<String, Object>> srcDataList, List<Map<String, Object>> originDataList)
throws Exception {
if (originDataList != null) {
callScript(originDataList, WmsSAPDbConstWords.SCRIPT_MARK_FUN_NAME);
} else {
callScript(srcDataList, WmsSAPDbConstWords.SCRIPT_MARK_FUN_NAME);
}
}
/**
*
* @param data
* @param funName
* @throws Exception
*/
private void callScript(Object data, String funName) throws Exception {
// 调用脚本引擎写入目标数据
String scriptNo = this.dataMapper.getScriptNo();
// 如果脚本编号配置的是 groovy 文件,就直接调用文件,便于运行中打断点调试
if (scriptNo.indexOf(".groovy") > 0) {
engineScriptManager.invokeGroovyScript(
scriptNo,
funName,
this.dataMapper,
data);
} else {
engineScriptManager.invokeFuncation(
this.dataMapper.getOrganizeCode(),
scriptNo,
funName,
this.dataMapper,
data);
}
}
/**
*
*
* @param destDataSet
* @throws Exception
*/
public void saveDestData(DataSet destDataSet) throws Exception {
if (destDataSet == null || destDataSet.getDataTables().size() == 0) {
LOGGER.error("no data in dest dataset!");
throw new IllegalArgumentException("no data in dest dataset!");
}
List<String> sqlStringList = new ArrayList<>();
// 保存主键查询的 SQL 语句,用于判断表内数据行是否重复
Map<String, Integer> sqlCacheMap = new HashMap<>();
// 循环处理每一行目标表数据
for (DataTable table : destDataSet.getDataTables()) {
for (DataRow destRow : table.getRows()) {
// 生成 SQL 语句
sqlStringList.add(packRowSQL(destRow, sqlCacheMap));
}
}
try {
// 作为一个事务批量执行
destDataSourceProxy.executeAsBatch(sqlStringList, destConn);
for(String sql : sqlStringList) {
LOGGER.info(sql);
}
// LOGGER.info(sqlStringList.toString());
} catch (Exception e) {
// 包装异常信息,把 SQL 加进去,便于调试
throw new SQLException("执行SQL异常" + e.getMessage() + " "
+ getSqlStrings(sqlStringList));
}
}
/**
* SQL
*
* @param sqlStringList
* @return
*/
private String getSqlStrings(List<String> sqlStringList) {
if (sqlStringList == null) {
return null;
}
StringBuffer sb = new StringBuffer();
int index = 0;
for (String sql : sqlStringList) {
sb.append(String.valueOf(index) + " < ");
sb.append(sql);
sb.append("> ");
}
return sb.toString();
}
/**
*
*
* @param srcDataList
* @throws Exception
*/
private void saveSrcData(List<Map<String, Object>> srcDataList) throws Exception {
if (srcDataList == null || srcDataList.size() == 0) {
LOGGER.error("no data in src datalist!");
throw new IllegalArgumentException("no data in src datalist!");
}
List<String> sqlStringList = new ArrayList<>();
// 存放插入备份表的SQL语句列表
List<String> insertSqlStringList = new ArrayList<>();
// 存放删除来源表的SQL语句列表
List<String> deleteSqlStringList = new ArrayList<>();
List<String> saveAndRemoveList = new ArrayList<>();
String sqlString;
HashMap<String, Object> srcPkMap = new HashMap<>();
// 循环处理每一行数据
for (Map<String, Object> srcRow : srcDataList) {
// 先清空主键 Map
srcPkMap.clear();
if (StringUtil.isEmpty(this.getSrcPkColumn())) {
LOGGER.error("WmsSAPDbWriter.saveSrcData params srcPkColumn is null!");
throw new Exception("WmsSAPDbWriter.saveSrcData params srcPkColumn is null");
}
// 构建主键 Map
for (String column : this.getSrcPkColumn()) {
srcPkMap.put(column, srcRow.get(column));
}
// 把来源表的数据行放到表达式中,确保表达式可以引用
HashMap<String, Object> updateValueMap = getUpdateSyncMap(srcRow);
// 存在来源表不需要更新同步标志的情况
if (updateValueMap.size() > 0) {
// 拼接更新来源表同步标志的 SQL LIST
sqlString = srcDataSourceProxy.packUpdateSQL(this.dataMapper.getSrcTableName(), srcPkMap,
updateValueMap);
// 如果设置了分组处理,在回写来源表时就要加上原始的 Where 条件,以防止多更新数据
if (StringUtils.isNotBlank(this.dataMapper.getSrcGroupColumns())) {
// 先去掉原来拼接的分号
sqlString = sqlString.replace(";"," ") + " and (" + this.dataMapper.getSrcWhere() + "); ";
}
sqlStringList.add(sqlString);
}
// 添加处理完成的数据及时剪切到备份表的逻辑
if (!StringUtils.isBlank(this.dataMapper.getCutToTableName())) {
// 插入历史表的语句
sqlString = srcDataSourceProxy.packInsertSQL(this.dataMapper.getCutToTableName(), (HashMap<String, Object>)srcRow);
insertSqlStringList.add(sqlString);
// 删除来源表的语句
sqlString = srcDataSourceProxy.packDeleteSQL(this.dataMapper.getSrcTableName(), srcPkMap);
// // 如果设置了分组处理,在回写来源表时就要加上原始的 Where 条件,以防止多更新数据
// if (StringUtils.isNotBlank(this.dataMapper.getSrcGroupColumns())) {
// // 先去掉原来拼接的分号
// sqlString = sqlString.replace(";"," ") + " and (" + this.dataMapper.getSrcWhere() + "); ";
// }
deleteSqlStringList.add(sqlString);
}
}
try {
if (sqlStringList.size() > 0) {
// 去掉重复的 SQL
List<String> uniqeSqlList = sqlStringList.stream().distinct().collect(Collectors.toList());
// 批量更新来源表的同步标志
srcDataSourceProxy.executeAsBatch(uniqeSqlList, srcConn);
}
} catch (Exception e) {
// 包装异常信息,把 SQL 加进去,便于调试
throw new SQLException("执行SQL异常" + e.getMessage() + " "
+ getSqlStrings(sqlStringList));
}
try {
if (insertSqlStringList.size() > 0) {
saveAndRemoveList.addAll(insertSqlStringList);
}
if (deleteSqlStringList.size() > 0) {
saveAndRemoveList.addAll(deleteSqlStringList);
}
if (saveAndRemoveList.size() > 0) {
// 去掉重复的 SQL
LOGGER.info("执行迁移的sql脚本为:sqlString:"+getSqlStrings(saveAndRemoveList));
List<String> uniqeSqlList = saveAndRemoveList.stream().distinct().collect(Collectors.toList());
//插入备份表 & 删除来源表数据
srcDataSourceProxy.executeAsBatch(uniqeSqlList, srcConn);
}
} catch (Exception e) {
// 包装异常信息,把 SQL 加进去,便于调试
throw new SQLException("执行SQL异常" + e.getMessage() + " "
+ getSqlStrings(saveAndRemoveList));
}
}
/**
* Map
*
* @return
*/
private HashMap<String, Object> getUpdateSyncMap(Map<String, Object> srcRow) throws Exception {
HashMap<String, Object> updateSyncMap = new HashMap<>();
if (this.getSrcUpdateSync() == null) {
return updateSyncMap;
}
for (UpdateSyncItem item : this.getSrcUpdateSync()) {
Object updateValue = item.getUpdateValue();
// 如果包含表达式,则计算后赋值
if (item.getUpdateValue().indexOf("#") != -1) {
updateValue = wmsSAPDbExpression.parse(item.getUpdateValue(), srcRow);
}
updateSyncMap.put(item.getColumnName(), updateValue);
}
return updateSyncMap;
}
/**
* SQL
*
* @param row
* @throws Exception
*/
private String packRowSQL(DataRow row, Map<String, Integer> sqlCacheMap) throws Exception {
if (row == null || row.getColumns().size() == 0) {
LOGGER.error("no column in row!");
throw new IllegalArgumentException("no column in row!");
}
// 获取主键列表
List<String> destPks = getPkList(row);
// 获取主键查询 SQL & KeyMap
SqlAndKeyMap sqlAndKeyMap = new SqlAndKeyMap(row, destPks).invoke();
String sqlString = sqlAndKeyMap.getSqlString();
Map<String, Object> pkMap = sqlAndKeyMap.getPkMap();
// 按照主键从业务表查询数据
List<Map<String, Object>> resutlMap = destDataSourceProxy.queryMapList(sqlString, destConn);
// 判断按主键查询的 SQL 有没有出现过
Boolean dataDupInBatch = sqlCacheMap.containsKey(sqlString);
// 没出现过,加入缓存中
if (!dataDupInBatch) {
sqlCacheMap.put(sqlString, 1);
}
// 最终要生成的插入或更新SQL
String sqlResult;
// 目标数据存在或者在本次处理的数据中重复则更新,不存在则新增
if ((resutlMap != null && resutlMap.size() > 0) || dataDupInBatch) {
HashMap<String, Object> rowMap = (HashMap<String, Object>) row.getItemMap();
// id 不用更新
if (rowMap.containsKey("id")) {
rowMap.remove("id");
}
// 过滤标记为 NotTrans 数据项,这些数据不更新到数据库
Iterator<Map.Entry<String, Object>> iterator = rowMap.entrySet().iterator();
Object value;
while (iterator.hasNext()) {
value = iterator.next().getValue();
if (value != null && value.toString().endsWith(WmsSAPDbExpression.NOT_TRANS)) {
iterator.remove();
}
}
sqlResult = destDataSourceProxy.packUpdateSQL(row.getTable().getTableName(), (HashMap<String, Object>) pkMap,rowMap);
} else {
HashMap<String, Object> rowMap = (HashMap<String, Object>) row.getItemMap();
// 带 NotTrans 的数据先把 :NotTrans 或者 NotTrans 标记去掉
for (Map.Entry<String, Object> entry : rowMap.entrySet()) {
if (entry.getValue() != null && entry.getValue().toString().endsWith(WmsSAPDbExpression.NOT_TRANS)) {
String transValue = entry.getValue().toString();
transValue = transValue.replace(":" + WmsSAPDbExpression.NOT_TRANS, "");
transValue = transValue.replace(WmsSAPDbExpression.NOT_TRANS, "");
LOGGER.debug("NotTrans Item: {} Insert before: {} after: {}", entry.getKey(), entry.getValue(), transValue);
rowMap.put(entry.getKey(), transValue);
}
}
sqlResult = destDataSourceProxy.packInsertSQL(row.getTable().getTableName(),
(HashMap<String, Object>) row.getItemMap());
}
return sqlResult;
}
/**
*
*
* @param row
* @return
*/
private List<String> getPkList(DataRow row) {
// 先查找外面配置的主键
List<String> destPks = this.getDestPkProperty();
// 一表对多表,主键设置在字段对照表里
if (destPks == null || destPks.isEmpty()) {
destPks = this.getDestPkByBeanName(row.getTable().getTableName());
}
// 没有找到主键时抛出异常
if (destPks == null || destPks.isEmpty()) {
LOGGER.error("no pk in table: " + row.getTable().getTableName());
throw new IllegalArgumentException("no pk in table: " + row.getTable().getTableName());
}
return destPks;
}
/**
* SQL & KeyMap
*/
private class SqlAndKeyMap {
private DataRow row;
private List<String> destPks;
private String sqlString;
private Map<String, Object> pkMap;
public SqlAndKeyMap(DataRow row, List<String> destPks) {
this.row = row;
this.destPks = destPks;
}
public String getSqlString() {
return sqlString;
}
public Map<String, Object> getPkMap() {
return pkMap;
}
public SqlAndKeyMap invoke() {
sqlString = "select 1 from " + row.getTable().getTableName()
+ " where 1=1 ";
// 目标表的主键列表
pkMap = new HashMap<>();
for (String column : destPks) {
String value = WmsSAPDbWriter.this.getSafetyString(row.getValue(column));
// 处理掉 NotTrans 字段
if (value != null && value.contains(WmsSAPDbExpression.NOT_TRANS)) {
value = value.replace(":" + WmsSAPDbExpression.NOT_TRANS, "");
value = value.replace(WmsSAPDbExpression.NOT_TRANS, "");
}
sqlString += "and " + column + "='" + value + "' ";
pkMap.put(column, row.getValue(column));
}
return this;
}
}
/**
*
*
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
/**
* hashCode
*
* @return
*/
@Override
public int hashCode() {
return super.hashCode();
}
}

@ -0,0 +1,103 @@
package cn.estsh.i3plus.ext.mes.apiservice.schedulejob;
import cn.estsh.i3plus.ext.mes.apiservice.dbinterface.MesSAPDbAdapter;
import cn.estsh.i3plus.mes.apiservice.schedulejob.BaseMesScheduleJob;
import cn.estsh.i3plus.platform.common.tool.JsonUtilTool;
import cn.estsh.i3plus.pojo.mes.dbinterface.MesInterfaceEnumUtil;
import cn.estsh.i3plus.pojo.model.wms.WmsJobParamModel;
import cn.estsh.impp.framework.boot.init.ApplicationProperties;
import cn.estsh.impp.framework.boot.util.SpringContextsUtil;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import java.util.List;
/**
* @Description : SAP MES +
* @Reference :
* @Author : gsz
* @CreateDate : 2024-05-10 11:03
* @Modify:
**/
// 禁止 JOB 并发执行
@DisallowConcurrentExecution
@ApiOperation("SAP接口表数据同步作业按工厂划分")
public class MesSAPDbTransByWorksJob extends BaseMesScheduleJob {
public static final Logger LOGGER = LoggerFactory.getLogger(MesSAPDbTransByWorksJob.class);
private static final long serialVersionUID = 9072058154235836696L;
@Value("${server.port}")
private String serverPort;
@Value("${impp.server.ip}")
private String ip;
public MesSAPDbTransByWorksJob() {
super(MesSAPDbTransByWorksJob.class, "SAP接口表数据同步作业按工厂划分");
this.setMultiInstance(true);
}
@Override
public void executeMesJob(JobExecutionContext context, ApplicationProperties applicationProperties) {
try {
String jobParam = this.getJobParam();
if (StringUtils.isBlank(jobParam)) {
throw new IllegalArgumentException("jobc参数为空请检查参数");
}
//参数: [{ "organizeCodeList" : [ "3610",2752","2751"],"groupName" : "SAP2MES"}]
//参数: [{ "organizeCodeList" : [ "3610",2752","2751"],"groupName" : "WMS2SAP"}]
List<WmsJobParamModel> wmsJobParamModelList = JsonUtilTool.toList(jobParam, WmsJobParamModel.class);
if (!CollectionUtils.isEmpty(wmsJobParamModelList)) {
//正常应该一个工厂一个分组JOB。所以一个【jobParam】就有一个解析对象。
WmsJobParamModel wmsJobParamModel = wmsJobParamModelList.get(0);
//解析job参数
List<String> organizeCodeList = wmsJobParamModel.getOrganizeCodeList();
List<String> destBeanNameList = wmsJobParamModel.getDestBeanNameList();
List<String> destBeanNameNotList = wmsJobParamModel.getDestBeanNameNotList();
String groupName = wmsJobParamModel.getGroupName();
// 判断作业参数是否支持
if (MesInterfaceEnumUtil.DIRECTION_TYPE.nameOf(groupName) == -1) {
throw new IllegalArgumentException("不支持的作业参数:" + groupName);
}
LOGGER.info("SAP接口表数据同步作业按工厂划分开始 -----start");
// 开始同步数据
// 一定要 new 对象,不然会有并发问题
MesSAPDbAdapter mesSAPDbAdapter;
for (String organizeCode : organizeCodeList) {
mesSAPDbAdapter = new MesSAPDbAdapter();
// new 的对象需要手工注入 bean
if (SpringContextsUtil.getApplicationContext() != null) {
SpringContextsUtil.getApplicationContext().
getAutowireCapableBeanFactory().autowireBean(mesSAPDbAdapter);
}
mesSAPDbAdapter.syncDataByOrganizeCode(groupName, organizeCode,destBeanNameList,destBeanNameNotList);
}
// LOGGER.info("SAP接口表数据同步作业按工厂划分开始结束 ----- projectName{}, port:{}",
// applicationProperties.getApplicationName(), applicationProperties.getServerPort());
LOGGER.info("SAP接口表数据同步作业按工厂划分开始结束 ----- end");
}
} catch (Exception e) {
LOGGER.error("SAP接口表数据同步作业任务结束e:{}",e.toString());
//sendErrorMessage(e.toString());
}
}
}

@ -16,7 +16,23 @@ impp.mes.datasource.password=estsh123
#\u6570\u636E\u6E90\u7684\u522B\u540D
impp.yfas.datasource.alias=yfasDataSource
impp.yfas.datasource.driver-class-name=com.mysql.jdbc.Driver
impp.yfas.datasource.jdbc-url=jdbc:mysql://10.195.88.71:3306/impp_i3_mes?autoReconnect=true&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
impp.yfas.datasource.jdbc-url=jdbc:mysql://10.195.88.71:3306/impp_i3_wms_sap_if?autoReconnect=true&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
#impp.yfas.datasource.jdbc-url=jdbc:sqlserver://139.224.200.147:20037;DatabaseName=impp_i3_mes;
impp.yfas.datasource.username=root
impp.yfas.datasource.password=estsh123
#\u6570\u636E\u6E90\u7684\u522B\u540D
#impp.wms.datasource.isopen=true
#impp.wms.datasource.alias=wmsDataSource
#impp.wms.datasource.driver-class-name=com.mysql.jdbc.Driver
#impp.wms.datasource.jdbc-url=jdbc:mysql://dbmaster:3306/impp_i3_wms?autoReconnect=true&useSSL=false&characterEncoding=utf-8
#impp.wms.datasource.username=root
#impp.wms.datasource.password=estsh123
#
##SWEB??????????
#impp.sweb.datasource.isopen=true
#impp.sweb.datasource.alias=swebDataSource
#impp.sweb.datasource.driver-class-name=com.mysql.jdbc.Driver
#impp.sweb.datasource.jdbc-url=jdbc:mysql://dbmaster:3306/impp_i3_wms?autoReconnect=true&useSSL=false&characterEncoding=utf-8
#impp.sweb.datasource.username=root
#impp.sweb.datasource.password=estsh123

@ -1,5 +1,5 @@
#\u9879\u76EE\u540D\u79F0
spring.application.name=mes-zxw
spring.application.name=mes
#\u4F7F\u7528\u914D\u7F6E
spring.profiles.active=71,cus-71
######### \u81EA\u5B9A\u4E49\u53C2\u6570 #########

@ -19,7 +19,10 @@
<version>1.0.0-yfai</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
</dependencies>

@ -0,0 +1,42 @@
package cn.estsh.i3plus.ext.mes.pojo.util;
import org.quartz.TriggerUtils;
import org.quartz.impl.triggers.CronTriggerImpl;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* @Description :CronUtil
* @Reference :
* @Author : gsz
* @CreateDate : 2024-05-10 16:08
* @Modify:
**/
public class CronUtil {
public static String getRecentTriggerTime(String cron) {
String newTime = "";
try {
CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();
cronTriggerImpl.setCronExpression(cron);
//下次执行时间 增加一秒
Date cronTime = new Date();
cronTime.setTime(new Date().getTime()+1000);
cronTriggerImpl.setStartTime(cronTime);
// 这个是重点,一行代码搞定
List<Date> dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null,5 );
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
newTime = dateFormat.format(dates.get(0));
} catch (ParseException e) {
e.printStackTrace();
}
return newTime;
}
}

@ -0,0 +1,35 @@
package cn.estsh.i3plus.ext.mes.pojo.util;
import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;
/**
* @Description :OverwriteStringJoin
* @Reference :
* @Author : gsz
* @CreateDate : 2024-05-10 16:08
* @Modify:
**/
public class OverwriteStringJoin {
public static String join(CharSequence delimiter, CharSequence... elements) {
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
StringJoiner joiner = new StringJoiner(delimiter);
for (CharSequence cs: elements) {
joiner.add("'" + cs + "'");
}
return joiner.toString();
}
public static String join(CharSequence delimiter, List<String> elements) {
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
StringJoiner joiner = new StringJoiner(delimiter);
for (String cs: elements) {
joiner.add("'" + cs + "'");
}
return joiner.toString();
}
}
Loading…
Cancel
Save