供应商管理数据同步, tms系统产品,服务渠道,产品渠道关系数据同步
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
package com.bms.masterdata.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 线路产品镜像对象 srv_line_product(Oracle WEISHI_USER.TAB_LINE_PRODUCT)
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-12
|
||||
*/
|
||||
@Data
|
||||
public class LineProduct
|
||||
{
|
||||
/** 源主键 ID */
|
||||
private String id;
|
||||
|
||||
/** 产品(线路)编码 */
|
||||
private String lineCode;
|
||||
|
||||
/** 产品(线路)名称 */
|
||||
private String lineName;
|
||||
|
||||
private String productType;
|
||||
private String lineType;
|
||||
|
||||
/** 是否可收货(1是 0否) */
|
||||
private String blCargo;
|
||||
|
||||
private String cargoName;
|
||||
|
||||
private String productStorage;
|
||||
private String productFirst;
|
||||
private String productClearance;
|
||||
private String productStorageCode;
|
||||
private String productFirstCode;
|
||||
private String productClearanceCode;
|
||||
|
||||
/** 是否启用(1启用 0停用) */
|
||||
private String blOpen;
|
||||
|
||||
/** 是否分段(1是 0否) */
|
||||
private String blSection;
|
||||
|
||||
private String dispCode;
|
||||
private String dispName;
|
||||
private String feeClass;
|
||||
private String shipperId;
|
||||
|
||||
/** 发货规则 */
|
||||
private String shipmentRule;
|
||||
|
||||
/** 限重(kg) */
|
||||
private BigDecimal weight;
|
||||
|
||||
private String cargoType;
|
||||
private String productCategory;
|
||||
|
||||
/** 体积基数(抛货系数) */
|
||||
private BigDecimal volumeBasis;
|
||||
|
||||
private String weightType;
|
||||
private String serviceType;
|
||||
private String shipmentType;
|
||||
|
||||
private BigDecimal taxAmount;
|
||||
private String taxCurrency;
|
||||
private String batteryType;
|
||||
private String remark;
|
||||
|
||||
private String createName;
|
||||
private String createManCode;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date createDate;
|
||||
private String modifier;
|
||||
private String modifierCode;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date modifyDate;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date gmtCreate;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date gmtModified;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.bms.masterdata.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 产品-渠道关系镜像对象 srv_product_channel(Oracle WEISHI_USER.TAB_PRODUCT_CHANNEL)
|
||||
* 注意:源端 (productId, channelCode) 不唯一(同产品同渠道按国家/重量区间多行),主键为源 GUID。
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-12
|
||||
*/
|
||||
@Data
|
||||
public class ProductChannel
|
||||
{
|
||||
/** 源主键 GUID */
|
||||
private String guid;
|
||||
|
||||
/** 产品ID(srv_line_product.id) */
|
||||
private String productId;
|
||||
|
||||
/** 渠道编码(srv_service_channel.channel_code) */
|
||||
private String channelCode;
|
||||
|
||||
private String channelName;
|
||||
|
||||
/** 优先级(数字越小越优先) */
|
||||
private Integer priority;
|
||||
|
||||
/** 是否启用(1启用 0停用) */
|
||||
private String isEnabled;
|
||||
|
||||
private String lineCode;
|
||||
private String lineName;
|
||||
private String countryCode;
|
||||
|
||||
private BigDecimal startWeight;
|
||||
private BigDecimal endWeight;
|
||||
|
||||
/** 下单量 */
|
||||
private Long orderCount;
|
||||
|
||||
/** 下单量占比 */
|
||||
private BigDecimal orderCountRatio;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.bms.masterdata.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 服务渠道镜像对象 srv_service_channel(Oracle WEISHI_USER.TAB_SERVICE_CHANNEL)
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-12
|
||||
*/
|
||||
@Data
|
||||
public class ServiceChannel
|
||||
{
|
||||
/** 源主键 ID */
|
||||
private String id;
|
||||
|
||||
/** 渠道编码 */
|
||||
private String channelCode;
|
||||
|
||||
/** 渠道名称 */
|
||||
private String channelName;
|
||||
|
||||
/** 所属服务商编码 */
|
||||
private String serviceCode;
|
||||
|
||||
/** 所属服务商名称 */
|
||||
private String serviceName;
|
||||
|
||||
/** 是否启用(1启用 0停用) */
|
||||
private String blOpen;
|
||||
|
||||
/** 是否支持多票(1是 0否) */
|
||||
private String blMultiple;
|
||||
|
||||
private String cargoType;
|
||||
private String payType;
|
||||
private String shipperName;
|
||||
private String shipperId;
|
||||
private String queryType;
|
||||
private String trajectoryCode;
|
||||
private String finalServiceName;
|
||||
private String desPort;
|
||||
|
||||
/** 重量类型 */
|
||||
private String weightType;
|
||||
|
||||
/** 体积除数(抛货系数) */
|
||||
private Long dimDivisor;
|
||||
|
||||
private String weightRule;
|
||||
private String shipmentType;
|
||||
private String dataFrom;
|
||||
private String remarks;
|
||||
|
||||
private String createName;
|
||||
private String createManCode;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date createDate;
|
||||
private String modifier;
|
||||
private String modifierCode;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date modifyDate;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date gmtCreate;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date gmtModified;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.bms.masterdata.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.bms.masterdata.domain.LineProduct;
|
||||
import com.bms.masterdata.domain.ProductChannel;
|
||||
import com.bms.masterdata.domain.ServiceChannel;
|
||||
|
||||
/**
|
||||
* 渠道/产品 镜像表写库(MASTER 数据源,按源主键 upsert)
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-12
|
||||
*/
|
||||
public interface ChannelMasterSyncMapper
|
||||
{
|
||||
/** 按源 ID 批量 upsert 服务渠道 */
|
||||
int upsertServiceChannel(@Param("list") List<ServiceChannel> list);
|
||||
|
||||
/** 按源 ID 批量 upsert 线路产品 */
|
||||
int upsertLineProduct(@Param("list") List<LineProduct> list);
|
||||
|
||||
/** 按源 GUID 批量 upsert 产品-渠道关系 */
|
||||
int upsertProductChannel(@Param("list") List<ProductChannel> list);
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package com.bms.masterdata.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Oracle 渠道/产品 主数据只读查询(SLAVE 数据源,账号只读)
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-12
|
||||
*/
|
||||
public interface OracleChannelMasterMapper
|
||||
{
|
||||
/** 全量读取服务渠道 TAB_SERVICE_CHANNEL */
|
||||
List<Map<String, Object>> selectAllServiceChannel();
|
||||
|
||||
/** 全量读取线路产品 TAB_LINE_PRODUCT */
|
||||
List<Map<String, Object>> selectAllLineProduct();
|
||||
|
||||
/** 全量读取产品-渠道关系 TAB_PRODUCT_CHANNEL */
|
||||
List<Map<String, Object>> selectAllProductChannel();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.bms.masterdata.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import com.bms.masterdata.domain.ServiceChannel;
|
||||
|
||||
/**
|
||||
* 服务渠道镜像表查询(MASTER 数据源)
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-12
|
||||
*/
|
||||
public interface ServiceChannelMapper
|
||||
{
|
||||
/**
|
||||
* 查询服务渠道列表(支持渠道编码/名称/服务商编码/启用状态过滤,非分页)
|
||||
*/
|
||||
List<ServiceChannel> selectServiceChannelList(ServiceChannel query);
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.bms.masterdata.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.bms.masterdata.domain.ServiceChannel;
|
||||
|
||||
/**
|
||||
* 服务渠道镜像 服务层
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-12
|
||||
*/
|
||||
public interface IServiceChannelService
|
||||
{
|
||||
/**
|
||||
* 查询服务渠道列表(非分页,供供应商绑定渠道等下拉选择场景)
|
||||
*/
|
||||
List<ServiceChannel> selectServiceChannelList(ServiceChannel query);
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.bms.masterdata.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.bms.masterdata.domain.ServiceChannel;
|
||||
import com.bms.masterdata.mapper.ServiceChannelMapper;
|
||||
import com.bms.masterdata.service.IServiceChannelService;
|
||||
|
||||
/**
|
||||
* 服务渠道镜像 服务实现
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-12
|
||||
*/
|
||||
@Service
|
||||
public class ServiceChannelServiceImpl implements IServiceChannelService
|
||||
{
|
||||
@Autowired
|
||||
private ServiceChannelMapper serviceChannelMapper;
|
||||
|
||||
@Override
|
||||
public List<ServiceChannel> selectServiceChannelList(ServiceChannel query)
|
||||
{
|
||||
return serviceChannelMapper.selectServiceChannelList(query);
|
||||
}
|
||||
}
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
package com.bms.masterdata.sync;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.bms.masterdata.domain.LineProduct;
|
||||
import com.bms.masterdata.domain.ProductChannel;
|
||||
import com.bms.masterdata.domain.ServiceChannel;
|
||||
|
||||
/**
|
||||
* Oracle 渠道/产品 主数据同步编排:
|
||||
* 顺序 渠道 → 产品 → 产品渠道关系,按源主键幂等 upsert,可重复执行。
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-12
|
||||
*/
|
||||
@Service
|
||||
public class ChannelMasterSyncService
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(ChannelMasterSyncService.class);
|
||||
|
||||
@Autowired
|
||||
private OracleChannelMasterReader reader;
|
||||
|
||||
@Autowired
|
||||
private ChannelMasterSyncWriter writer;
|
||||
|
||||
/**
|
||||
* 全量同步三表,返回简要对账信息
|
||||
*/
|
||||
public String syncFromOracle()
|
||||
{
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
List<Map<String, Object>> channelRows = reader.readServiceChannels();
|
||||
List<ServiceChannel> channels = new ArrayList<>(channelRows.size());
|
||||
int skipChannel = 0;
|
||||
for (Map<String, Object> row : channelRows)
|
||||
{
|
||||
String id = str(row, "ID");
|
||||
if (id == null) { skipChannel++; continue; }
|
||||
ServiceChannel c = new ServiceChannel();
|
||||
c.setId(id);
|
||||
c.setChannelCode(str(row, "CHANNEL_CODE"));
|
||||
c.setChannelName(str(row, "CHANNEL_NAME"));
|
||||
c.setServiceCode(str(row, "SERVICE_CODE"));
|
||||
c.setServiceName(str(row, "SERVICE_NAME"));
|
||||
c.setBlOpen(flag(row, "BL_OPEN"));
|
||||
c.setBlMultiple(flag(row, "BL_MULTIPLE"));
|
||||
c.setCargoType(str(row, "CARGO_TYPE"));
|
||||
c.setPayType(str(row, "PAY_TYPE"));
|
||||
c.setShipperName(str(row, "SHIPPER_NAME"));
|
||||
c.setShipperId(str(row, "SHIPPER_ID"));
|
||||
c.setQueryType(str(row, "QUERY_TYPE"));
|
||||
c.setTrajectoryCode(str(row, "TRAJECTORY_CODE"));
|
||||
c.setFinalServiceName(str(row, "FINAL_SERVICE_NAME"));
|
||||
c.setDesPort(str(row, "DES_PORT"));
|
||||
c.setWeightType(flag(row, "WEIGHT_TYPE"));
|
||||
c.setDimDivisor(lo(row, "DIM_DIVISOR"));
|
||||
c.setWeightRule(str(row, "WEIGHT_RULE"));
|
||||
c.setShipmentType(str(row, "SHIPMENT_TYPE"));
|
||||
c.setDataFrom(str(row, "DATA_FROM"));
|
||||
c.setRemarks(str(row, "REMARKS"));
|
||||
c.setCreateName(str(row, "CREATE_NAME"));
|
||||
c.setCreateManCode(str(row, "CREATE_MAN_CODE"));
|
||||
c.setCreateDate(date(row, "CREATE_DATE"));
|
||||
c.setModifier(str(row, "MODIFIER"));
|
||||
c.setModifierCode(str(row, "MODIFIER_CODE"));
|
||||
c.setModifyDate(date(row, "MODIFY_DATE"));
|
||||
c.setGmtCreate(date(row, "GMT_CREATE"));
|
||||
c.setGmtModified(date(row, "GMT_MODIFIED"));
|
||||
channels.add(c);
|
||||
}
|
||||
int channelAffected = writer.writeServiceChannels(channels);
|
||||
|
||||
List<Map<String, Object>> productRows = reader.readLineProducts();
|
||||
List<LineProduct> products = new ArrayList<>(productRows.size());
|
||||
int skipProduct = 0;
|
||||
for (Map<String, Object> row : productRows)
|
||||
{
|
||||
String id = str(row, "ID");
|
||||
if (id == null) { skipProduct++; continue; }
|
||||
LineProduct p = new LineProduct();
|
||||
p.setId(id);
|
||||
p.setLineCode(str(row, "LINE_CODE"));
|
||||
p.setLineName(str(row, "LINE_NAME"));
|
||||
p.setProductType(str(row, "PRODUCT_TYPE"));
|
||||
p.setLineType(str(row, "LINE_TYPE"));
|
||||
p.setBlCargo(flag(row, "BL_CARGO"));
|
||||
p.setCargoName(str(row, "CARGO_NAME"));
|
||||
p.setProductStorage(str(row, "PRODUCT_STORAGE"));
|
||||
p.setProductFirst(str(row, "PRODUCT_FIRST"));
|
||||
p.setProductClearance(str(row, "PRODUCT_CLEARANCE"));
|
||||
p.setProductStorageCode(str(row, "PRODUCT_STORAGE_CODE"));
|
||||
p.setProductFirstCode(str(row, "PRODUCT_FIRST_CODE"));
|
||||
p.setProductClearanceCode(str(row, "PRODUCT_CLEARANCE_CODE"));
|
||||
p.setBlOpen(flag(row, "BL_OPEN"));
|
||||
p.setBlSection(flag(row, "BL_SECTION"));
|
||||
p.setDispCode(str(row, "DISP_CODE"));
|
||||
p.setDispName(str(row, "DISP_NAME"));
|
||||
p.setFeeClass(str(row, "FEE_CLASS"));
|
||||
p.setShipperId(str(row, "SHIPPER_ID"));
|
||||
p.setShipmentRule(flag(row, "SHIPMENT_RULE"));
|
||||
p.setWeight(decimal(row, "WEIGHT"));
|
||||
p.setCargoType(str(row, "CARGO_TYPE"));
|
||||
p.setProductCategory(str(row, "PRODUCT_CATEGORY"));
|
||||
p.setVolumeBasis(decimal(row, "VOLUME_BASIS"));
|
||||
p.setWeightType(flag(row, "WEIGHT_TYPE"));
|
||||
p.setServiceType(flag(row, "SERVICE_TYPE"));
|
||||
p.setShipmentType(str(row, "SHIPMENT_TYPE"));
|
||||
p.setTaxAmount(decimal(row, "TAX_AMOUNT"));
|
||||
p.setTaxCurrency(str(row, "TAX_CURRENCY"));
|
||||
p.setBatteryType(str(row, "BATTERY_TYPE"));
|
||||
p.setRemark(str(row, "REMARK"));
|
||||
p.setCreateName(str(row, "CREATE_NAME"));
|
||||
p.setCreateManCode(str(row, "CREATE_MAN_CODE"));
|
||||
p.setCreateDate(date(row, "CREATE_DATE"));
|
||||
p.setModifier(str(row, "MODIFIER"));
|
||||
p.setModifierCode(str(row, "MODIFIER_CODE"));
|
||||
p.setModifyDate(date(row, "MODIFY_DATE"));
|
||||
p.setGmtCreate(date(row, "GMT_CREATE"));
|
||||
p.setGmtModified(date(row, "GMT_MODIFIED"));
|
||||
products.add(p);
|
||||
}
|
||||
int productAffected = writer.writeLineProducts(products);
|
||||
|
||||
List<Map<String, Object>> relRows = reader.readProductChannels();
|
||||
List<ProductChannel> relations = new ArrayList<>(relRows.size());
|
||||
int skipRel = 0;
|
||||
for (Map<String, Object> row : relRows)
|
||||
{
|
||||
String guid = str(row, "GUID");
|
||||
if (guid == null) { skipRel++; continue; }
|
||||
ProductChannel pc = new ProductChannel();
|
||||
pc.setGuid(guid);
|
||||
pc.setProductId(str(row, "PRODUCT_ID"));
|
||||
pc.setChannelCode(str(row, "CHANNEL_CODE"));
|
||||
pc.setChannelName(str(row, "CHANNEL_NAME"));
|
||||
pc.setPriority(integer(row, "PRIORITY"));
|
||||
pc.setIsEnabled(flag(row, "IS_ENABLED"));
|
||||
pc.setLineName(str(row, "LINE_NAME"));
|
||||
pc.setLineCode(str(row, "LINE_CODE"));
|
||||
pc.setCountryCode(str(row, "COUNTRY_CODE"));
|
||||
pc.setStartWeight(decimal(row, "START_WEIGHT"));
|
||||
pc.setEndWeight(decimal(row, "END_WEIGHT"));
|
||||
pc.setOrderCount(lo(row, "ORDER_COUNT"));
|
||||
pc.setOrderCountRatio(decimal(row, "ORDER_COUNT_RATIO"));
|
||||
relations.add(pc);
|
||||
}
|
||||
int relAffected = writer.writeProductChannels(relations);
|
||||
|
||||
long cost = System.currentTimeMillis() - start;
|
||||
String summary = String.format(
|
||||
"渠道产品同步完成,耗时%dms。服务渠道:源%d行(跳过%d),写入影响%d行;"
|
||||
+ "线路产品:源%d行(跳过%d),写入影响%d行;产品渠道关系:源%d行(跳过%d),写入影响%d行",
|
||||
cost, channels.size(), skipChannel, channelAffected,
|
||||
products.size(), skipProduct, productAffected,
|
||||
relations.size(), skipRel, relAffected);
|
||||
log.info(summary);
|
||||
return summary;
|
||||
}
|
||||
|
||||
// ==================== Oracle Map 取值工具(列名忽略大小写) ====================
|
||||
|
||||
private static Object getIgnoreCase(Map<String, Object> row, String key)
|
||||
{
|
||||
Object v = row.get(key);
|
||||
if (v != null)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
for (Map.Entry<String, Object> e : row.entrySet())
|
||||
{
|
||||
if (e.getKey() != null && e.getKey().equalsIgnoreCase(key))
|
||||
{
|
||||
return e.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String str(Map<String, Object> row, String key)
|
||||
{
|
||||
Object v = getIgnoreCase(row, key);
|
||||
if (v == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
String s = v.toString().trim();
|
||||
return s.isEmpty() ? null : s;
|
||||
}
|
||||
|
||||
/** NUMBER(1) 等 0/1 标志位原样存为 "1"/"0" */
|
||||
private static String flag(Map<String, Object> row, String key)
|
||||
{
|
||||
Object v = getIgnoreCase(row, key);
|
||||
if (v == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (v instanceof BigDecimal)
|
||||
{
|
||||
return ((BigDecimal) v).signum() == 0 ? "0" : "1";
|
||||
}
|
||||
if (v instanceof Number)
|
||||
{
|
||||
return ((Number) v).intValue() == 0 ? "0" : "1";
|
||||
}
|
||||
String s = v.toString().trim();
|
||||
return s.isEmpty() ? null : s;
|
||||
}
|
||||
|
||||
private static BigDecimal decimal(Map<String, Object> row, String key)
|
||||
{
|
||||
Object v = getIgnoreCase(row, key);
|
||||
if (v == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (v instanceof BigDecimal)
|
||||
{
|
||||
return (BigDecimal) v;
|
||||
}
|
||||
if (v instanceof Number)
|
||||
{
|
||||
return new BigDecimal(v.toString());
|
||||
}
|
||||
String s = v.toString().trim();
|
||||
return s.isEmpty() ? null : new BigDecimal(s);
|
||||
}
|
||||
|
||||
private static Integer integer(Map<String, Object> row, String key)
|
||||
{
|
||||
BigDecimal d = decimal(row, key);
|
||||
return d == null ? null : d.intValue();
|
||||
}
|
||||
|
||||
private static Long lo(Map<String, Object> row, String key)
|
||||
{
|
||||
BigDecimal d = decimal(row, key);
|
||||
return d == null ? null : d.longValue();
|
||||
}
|
||||
|
||||
private static Date date(Map<String, Object> row, String key)
|
||||
{
|
||||
Object v = getIgnoreCase(row, key);
|
||||
if (v == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (v instanceof Date)
|
||||
{
|
||||
return (Date) v;
|
||||
}
|
||||
String s = v.toString().trim();
|
||||
return s.isEmpty() ? null : new Date(s);
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.bms.masterdata.sync;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.bms.masterdata.domain.LineProduct;
|
||||
import com.bms.masterdata.domain.ProductChannel;
|
||||
import com.bms.masterdata.domain.ServiceChannel;
|
||||
import com.bms.masterdata.mapper.ChannelMasterSyncMapper;
|
||||
|
||||
/**
|
||||
* 渠道/产品 镜像表写库器(MASTER 数据源,分批 upsert,单表一个事务)。
|
||||
* 独立 Bean:保证 @Transactional 经代理生效,且与 SLAVE 读连接隔离。
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-12
|
||||
*/
|
||||
@Service
|
||||
public class ChannelMasterSyncWriter
|
||||
{
|
||||
/** 单批行数,控制 SQL 包大小 */
|
||||
private static final int BATCH_SIZE = 200;
|
||||
|
||||
@Autowired
|
||||
private ChannelMasterSyncMapper mapper;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int writeServiceChannels(List<ServiceChannel> list)
|
||||
{
|
||||
int rows = 0;
|
||||
for (int from = 0; from < list.size(); from += BATCH_SIZE)
|
||||
{
|
||||
rows += mapper.upsertServiceChannel(list.subList(from, Math.min(from + BATCH_SIZE, list.size())));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int writeLineProducts(List<LineProduct> list)
|
||||
{
|
||||
int rows = 0;
|
||||
for (int from = 0; from < list.size(); from += BATCH_SIZE)
|
||||
{
|
||||
rows += mapper.upsertLineProduct(list.subList(from, Math.min(from + BATCH_SIZE, list.size())));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int writeProductChannels(List<ProductChannel> list)
|
||||
{
|
||||
int rows = 0;
|
||||
for (int from = 0; from < list.size(); from += BATCH_SIZE)
|
||||
{
|
||||
rows += mapper.upsertProductChannel(list.subList(from, Math.min(from + BATCH_SIZE, list.size())));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package com.bms.masterdata.sync;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.bms.common.annotation.DataSource;
|
||||
import com.bms.common.enums.DataSourceType;
|
||||
import com.bms.masterdata.mapper.OracleChannelMasterMapper;
|
||||
|
||||
/**
|
||||
* Oracle 渠道/产品 主数据读取器(SLAVE 只读账号数据源)。
|
||||
* 必须独立 Bean,否则 @DataSource 切面在同类自调用时不生效。
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-12
|
||||
*/
|
||||
@Service
|
||||
public class OracleChannelMasterReader
|
||||
{
|
||||
@Autowired
|
||||
private OracleChannelMasterMapper oracleChannelMasterMapper;
|
||||
|
||||
@DataSource(DataSourceType.SLAVE)
|
||||
public List<Map<String, Object>> readServiceChannels()
|
||||
{
|
||||
try
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
return oracleChannelMasterMapper.selectAllServiceChannel();
|
||||
}
|
||||
finally
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
}
|
||||
}
|
||||
|
||||
@DataSource(DataSourceType.SLAVE)
|
||||
public List<Map<String, Object>> readLineProducts()
|
||||
{
|
||||
try
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
return oracleChannelMasterMapper.selectAllLineProduct();
|
||||
}
|
||||
finally
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
}
|
||||
}
|
||||
|
||||
@DataSource(DataSourceType.SLAVE)
|
||||
public List<Map<String, Object>> readProductChannels()
|
||||
{
|
||||
try
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
return oracleChannelMasterMapper.selectAllProductChannel();
|
||||
}
|
||||
finally
|
||||
{
|
||||
PageHelper.clearPage();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.bms.masterdata.task;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.bms.common.utils.StringUtils;
|
||||
import com.bms.masterdata.sync.ChannelMasterSyncService;
|
||||
|
||||
/**
|
||||
* 老系统渠道/产品 主数据每日同步任务。
|
||||
* sys_job.invoke_target = channelMasterSyncTask.syncFromOracle()
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-12
|
||||
*/
|
||||
@Component("channelMasterSyncTask")
|
||||
public class ChannelMasterSyncTask
|
||||
{
|
||||
@Autowired
|
||||
private ChannelMasterSyncService channelMasterSyncService;
|
||||
|
||||
/**
|
||||
* 全量同步 Oracle TAB_SERVICE_CHANNEL / TAB_LINE_PRODUCT / TAB_PRODUCT_CHANNEL
|
||||
*/
|
||||
public void syncFromOracle()
|
||||
{
|
||||
String summary = channelMasterSyncService.syncFromOracle();
|
||||
if (StringUtils.isEmpty(summary))
|
||||
{
|
||||
throw new RuntimeException("老系统渠道产品同步未返回结果");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user