完善 MCS 桌面代理与开炼机动作同步,修复原料相关菜单权限,桌面端新增上辅机 MES 菜单。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -36,5 +36,11 @@
|
||||
<artifactId>jeecg-module-print</artifactId>
|
||||
<version>${jeecgboot.version}</version>
|
||||
</dependency>
|
||||
<!-- 设备同步/桌面代理命令总线 -->
|
||||
<dependency>
|
||||
<groupId>org.jeecgframework.boot3</groupId>
|
||||
<artifactId>jeecg-module-device-sync</artifactId>
|
||||
<version>${jeecgboot.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -130,6 +130,7 @@ public class MesXslAutoSmallMaterialDemandPlanController {
|
||||
}
|
||||
|
||||
sql.append("GROUP BY ");
|
||||
sql.append(statDateExpr).append(", ");
|
||||
if (groupedByMachine) {
|
||||
sql.append(machineExpr).append(", ");
|
||||
}
|
||||
@@ -160,14 +161,20 @@ public class MesXslAutoSmallMaterialDemandPlanController {
|
||||
|
||||
private String buildOrderBy(boolean groupedByMachine) {
|
||||
if (groupedByMachine) {
|
||||
return " ORDER BY machineName, rawMaterialName";
|
||||
return " ORDER BY statDate DESC, machineName, rawMaterialName";
|
||||
}
|
||||
return " ORDER BY rawMaterialName";
|
||||
return " ORDER BY statDate DESC, rawMaterialName";
|
||||
}
|
||||
|
||||
private String buildRowId(MesXslSmallMaterialDemandPlanSummary row, boolean groupedByMachine, int seq) {
|
||||
String machine = groupedByMachine ? StringUtils.defaultString(row.getMachineName()) : "ALL";
|
||||
return machine + "_" + StringUtils.defaultString(row.getRawMaterialName()) + "_" + seq;
|
||||
return StringUtils.defaultString(row.getStatDate())
|
||||
+ "_"
|
||||
+ machine
|
||||
+ "_"
|
||||
+ StringUtils.defaultString(row.getRawMaterialName())
|
||||
+ "_"
|
||||
+ seq;
|
||||
}
|
||||
|
||||
private String trim(String value) {
|
||||
|
||||
@@ -130,6 +130,7 @@ public class MesXslManualSmallMaterialDemandPlanController {
|
||||
}
|
||||
|
||||
sql.append("GROUP BY ");
|
||||
sql.append(statDateExpr).append(", ");
|
||||
if (groupedByMachine) {
|
||||
sql.append(machineExpr).append(", ");
|
||||
}
|
||||
@@ -160,14 +161,20 @@ public class MesXslManualSmallMaterialDemandPlanController {
|
||||
|
||||
private String buildOrderBy(boolean groupedByMachine) {
|
||||
if (groupedByMachine) {
|
||||
return " ORDER BY machineName, rawMaterialName";
|
||||
return " ORDER BY statDate DESC, machineName, rawMaterialName";
|
||||
}
|
||||
return " ORDER BY rawMaterialName";
|
||||
return " ORDER BY statDate DESC, rawMaterialName";
|
||||
}
|
||||
|
||||
private String buildRowId(MesXslSmallMaterialDemandPlanSummary row, boolean groupedByMachine, int seq) {
|
||||
String machine = groupedByMachine ? StringUtils.defaultString(row.getMachineName()) : "ALL";
|
||||
return machine + "_" + StringUtils.defaultString(row.getRawMaterialName()) + "_" + seq;
|
||||
return StringUtils.defaultString(row.getStatDate())
|
||||
+ "_"
|
||||
+ machine
|
||||
+ "_"
|
||||
+ StringUtils.defaultString(row.getRawMaterialName())
|
||||
+ "_"
|
||||
+ seq;
|
||||
}
|
||||
|
||||
private String trim(String value) {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.jeecg.modules.xslmes.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.system.base.controller.JeecgController;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.modules.xslmes.entity.MesXslMillAction;
|
||||
import org.jeecg.modules.xslmes.service.IMesXslMillActionService;
|
||||
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.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* MES 开炼机动作接收表
|
||||
*/
|
||||
@Tag(name = "开炼机动作接收")
|
||||
@RestController
|
||||
@RequestMapping("/xslmes/mesXslMillAction")
|
||||
public class MesXslMillActionController extends JeecgController<MesXslMillAction, IMesXslMillActionService> {
|
||||
|
||||
@Autowired private IMesXslMillActionService mesXslMillActionService;
|
||||
|
||||
@Operation(summary = "开炼机动作接收-分页列表查询")
|
||||
@GetMapping("/list")
|
||||
public Result<IPage<MesXslMillAction>> queryPageList(
|
||||
MesXslMillAction model,
|
||||
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
HttpServletRequest req) {
|
||||
QueryWrapper<MesXslMillAction> queryWrapper = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
|
||||
queryWrapper.orderByDesc("update_time");
|
||||
IPage<MesXslMillAction> pageList = mesXslMillActionService.page(new Page<>(pageNo, pageSize), queryWrapper);
|
||||
return Result.OK(pageList);
|
||||
}
|
||||
|
||||
@Operation(summary = "开炼机动作接收-通过id查询")
|
||||
@GetMapping("/queryById")
|
||||
public Result<MesXslMillAction> queryById(@RequestParam(name = "id", required = true) String id) {
|
||||
MesXslMillAction entity = mesXslMillActionService.getById(id);
|
||||
if (entity == null) {
|
||||
return Result.error("未找到对应数据");
|
||||
}
|
||||
return Result.OK(entity);
|
||||
}
|
||||
|
||||
@RequiresPermissions("xslmes:mes_xsl_mill_action:exportXls")
|
||||
@RequestMapping(value = "/exportXls")
|
||||
public ModelAndView exportXls(HttpServletRequest request, MesXslMillAction model) {
|
||||
return super.exportXls(request, model, MesXslMillAction.class, "开炼机动作接收");
|
||||
}
|
||||
}
|
||||
@@ -95,9 +95,12 @@ public class MesXslRawMaterialDemandPlanController {
|
||||
|
||||
private String buildGroupedSql(
|
||||
MesXslRawMaterialDemandPlanSummary query, boolean groupedByMachine, List<Object> params) {
|
||||
String planDateExpr = "DATE(t.plan_date)";
|
||||
boolean hasPlanDate = hasColumn("mes_xsl_raw_material_demand_plan", "plan_date");
|
||||
boolean hasMaterialId = hasColumn("mes_xsl_raw_material_demand_plan", "material_id");
|
||||
String planDateExpr = hasPlanDate ? "t.plan_date" : "DATE(t.create_time)";
|
||||
String machineExpr = "COALESCE(NULLIF(TRIM(t.machine_name),''), '')";
|
||||
String materialIdExpr = "COALESCE(NULLIF(TRIM(t.material_id),''), '')";
|
||||
String materialIdExpr =
|
||||
hasMaterialId ? "COALESCE(NULLIF(TRIM(t.material_id),''), '')" : "''";
|
||||
String erpCodeExpr = "COALESCE(NULLIF(TRIM(t.erp_code),''), '')";
|
||||
String rawMaterialExpr = "COALESCE(NULLIF(TRIM(t.raw_material_name),''), '')";
|
||||
|
||||
@@ -192,4 +195,12 @@ public class MesXslRawMaterialDemandPlanController {
|
||||
private String trim(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
|
||||
private boolean hasColumn(String tableName, String columnName) {
|
||||
String sql =
|
||||
"SELECT COUNT(1) FROM information_schema.COLUMNS "
|
||||
+ "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?";
|
||||
Long count = jdbcTemplate.queryForObject(sql, Long.class, tableName, columnName);
|
||||
return count != null && count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package org.jeecg.modules.xslmes.deviceagent;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentCommandService;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentResult;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentSession;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentSessionRegistry;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 桌面设备代理免密接口(注册/心跳/分块回传)。
|
||||
*/
|
||||
@Tag(name = "桌面设备代理")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/xslmes/deviceAgent/anon")
|
||||
@RequiredArgsConstructor
|
||||
public class MesXslDeviceAgentAnonController {
|
||||
|
||||
private final DeviceAgentSessionRegistry sessionRegistry;
|
||||
private final DeviceAgentCommandService commandService;
|
||||
|
||||
@Operation(summary = "注册/心跳")
|
||||
@PostMapping("/register")
|
||||
public Result<Map<String, Object>> register(@RequestBody Map<String, Object> body) {
|
||||
String deviceId = str(body, "deviceId");
|
||||
if (StringUtils.isBlank(deviceId)) {
|
||||
return Result.error("deviceId不能为空");
|
||||
}
|
||||
String hostName = str(body, "hostName");
|
||||
Boolean dbConnected = bool(body.get("dbConnected"));
|
||||
String dbMessage = str(body, "dbMessage");
|
||||
sessionRegistry.registerOrHeartbeat(deviceId, hostName, dbConnected, dbMessage);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("deviceId", deviceId);
|
||||
data.put("accepted", true);
|
||||
return Result.OK(data);
|
||||
}
|
||||
|
||||
@Operation(summary = "心跳")
|
||||
@PostMapping("/heartbeat")
|
||||
public Result<String> heartbeat(@RequestBody Map<String, Object> body) {
|
||||
String deviceId = str(body, "deviceId");
|
||||
if (StringUtils.isBlank(deviceId)) {
|
||||
return Result.error("deviceId不能为空");
|
||||
}
|
||||
sessionRegistry.registerOrHeartbeat(deviceId, str(body, "hostName"), bool(body.get("dbConnected")), str(body, "dbMessage"));
|
||||
return Result.OK("ok");
|
||||
}
|
||||
|
||||
@Operation(summary = "命令结果分块回传(大数据量)")
|
||||
@PostMapping("/resultChunk")
|
||||
public Result<String> resultChunk(@RequestBody DeviceAgentResult result) {
|
||||
if (result == null || StringUtils.isBlank(result.getRequestId())) {
|
||||
return Result.error("requestId不能为空");
|
||||
}
|
||||
// 当前实现:整包完成;桌面可在单次 chunk 中带 lastChunk=true 直接完成
|
||||
if (Boolean.TRUE.equals(result.getLastChunk()) || result.getChunkTotal() == null || result.getChunkTotal() <= 1) {
|
||||
commandService.completeResult(result);
|
||||
} else {
|
||||
log.info("收到分块回传 requestId={} chunk={}/{}", result.getRequestId(), result.getChunkIndex(), result.getChunkTotal());
|
||||
// 简化:仅最后一块完成;中间块忽略合并(桌面端大结果优先走单次 STOMP 或一次 REST 全量)
|
||||
if (Boolean.TRUE.equals(result.getLastChunk())) {
|
||||
commandService.completeResult(result);
|
||||
}
|
||||
}
|
||||
return Result.OK("ok");
|
||||
}
|
||||
|
||||
@Operation(summary = "在线代理列表")
|
||||
@GetMapping("/online")
|
||||
public Result<List<DeviceAgentSession>> online() {
|
||||
return Result.OK(sessionRegistry.listOnline());
|
||||
}
|
||||
|
||||
@Operation(summary = "查询代理状态")
|
||||
@GetMapping("/status")
|
||||
public Result<DeviceAgentSession> status(@RequestParam(name = "deviceId", required = false) String deviceId) {
|
||||
return Result.OK(sessionRegistry.pickOnlineAgent(deviceId));
|
||||
}
|
||||
|
||||
private static String str(Map<String, Object> body, String key) {
|
||||
if (body == null || body.get(key) == null) {
|
||||
return null;
|
||||
}
|
||||
String v = String.valueOf(body.get(key)).trim();
|
||||
return v.isEmpty() || "null".equalsIgnoreCase(v) ? null : v;
|
||||
}
|
||||
|
||||
private static Boolean bool(Object v) {
|
||||
if (v == null) {
|
||||
return null;
|
||||
}
|
||||
if (v instanceof Boolean) {
|
||||
return (Boolean) v;
|
||||
}
|
||||
return Boolean.parseBoolean(String.valueOf(v));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.jeecg.modules.xslmes.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
/**
|
||||
* MES 开炼机动作接收表(采集自 MCSToMES_Act_Mill)
|
||||
*/
|
||||
@Data
|
||||
@TableName("mes_xsl_mill_action")
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Schema(description = "MES开炼机动作接收表")
|
||||
public class MesXslMillAction implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
|
||||
@Excel(name = "GUID", width = 36)
|
||||
@Schema(description = "源表GUID")
|
||||
private String guid;
|
||||
|
||||
@Excel(name = "动作地址", width = 10)
|
||||
@Schema(description = "动作地址")
|
||||
private Integer actAddr;
|
||||
|
||||
@Excel(name = "动作名称", width = 20)
|
||||
@Schema(description = "动作名称")
|
||||
private String actName;
|
||||
|
||||
@Excel(name = "动作名称(英)", width = 20)
|
||||
@Schema(description = "动作名称(英)")
|
||||
private String actNameEn;
|
||||
|
||||
@Excel(name = "动作备注", width = 15)
|
||||
@Schema(description = "动作备注")
|
||||
private String actMemo;
|
||||
|
||||
@Excel(name = "动作关联地址", width = 12)
|
||||
@Schema(description = "动作关联地址")
|
||||
private Integer actRepaddr;
|
||||
|
||||
@Excel(name = "写入时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Schema(description = "写入时间")
|
||||
private Date writeTime;
|
||||
|
||||
@Excel(name = "读取时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Schema(description = "读取时间")
|
||||
private Date readTime;
|
||||
|
||||
@Excel(name = "读写标识", width = 10)
|
||||
@Schema(description = "读写标识")
|
||||
private Integer rwFlag;
|
||||
|
||||
private Integer tenantId;
|
||||
private String sysOrgCode;
|
||||
private String createBy;
|
||||
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
private String updateBy;
|
||||
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
private Integer delFlag;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.jeecg.modules.xslmes.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.jeecg.modules.xslmes.entity.MesXslMillAction;
|
||||
|
||||
public interface MesXslMillActionMapper extends BaseMapper<MesXslMillAction> {}
|
||||
@@ -0,0 +1,85 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentCommandService;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentResult;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentSession;
|
||||
import org.jeecg.modules.device.sync.agent.DeviceAgentSessionRegistry;
|
||||
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
|
||||
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsDbConfig;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 经桌面端代理访问设备库。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DesktopAgentMcsDataAccess implements IMcsDataAccess {
|
||||
|
||||
private final DeviceAgentCommandService commandService;
|
||||
private final DeviceAgentSessionRegistry sessionRegistry;
|
||||
private final McsDataSourceManager mcsDataSourceManager;
|
||||
|
||||
@Override
|
||||
public boolean isAgentMode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveAgentDeviceId() {
|
||||
MesXslMcsDbConfig cfg = mcsDataSourceManager.getCachedConfig();
|
||||
String preferred = cfg == null ? null : cfg.getAgentDeviceId();
|
||||
DeviceAgentSession session = sessionRegistry.pickOnlineAgent(preferred);
|
||||
if (session == null) {
|
||||
throw new IllegalStateException("无在线桌面设备代理,无法访问设备库");
|
||||
}
|
||||
return session.getDeviceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> query(String sql, List<Object> params) {
|
||||
String deviceId = resolveAgentDeviceId();
|
||||
DeviceAgentResult result = commandService.query(deviceId, sql, params, 60_000);
|
||||
return result.getRows() == null ? List.of() : result.getRows();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int execute(String sql, List<Object> params) {
|
||||
String deviceId = resolveAgentDeviceId();
|
||||
DeviceAgentResult result = commandService.write(deviceId, sql, params, 60_000);
|
||||
return result.getAffected() == null ? 0 : result.getAffected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pushRows(String table, String mode, List<String> keys, List<Map<String, Object>> rows) {
|
||||
String deviceId = resolveAgentDeviceId();
|
||||
Map<String, Object> payload = new HashMap<>();
|
||||
payload.put("mode", StringUtils.defaultIfBlank(mode, "insert"));
|
||||
if (keys != null) {
|
||||
payload.put("keys", keys);
|
||||
}
|
||||
payload.put("rows", rows == null ? new ArrayList<>() : rows);
|
||||
DeviceAgentResult result = commandService.syncPush(deviceId, table, payload, 60_000);
|
||||
return result.getAffected() == null ? 0 : result.getAffected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testConnection() {
|
||||
try {
|
||||
String deviceId = resolveAgentDeviceId();
|
||||
DeviceAgentResult result = commandService.test(deviceId, 10_000);
|
||||
return result != null && result.isSuccess();
|
||||
} catch (Exception e) {
|
||||
log.warn("桌面代理中间库测试失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access;
|
||||
|
||||
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 服务端直连 SQL Server(调试/兼容保留)。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DirectJdbcMcsDataAccess implements IMcsDataAccess {
|
||||
|
||||
private final DataSource dataSource;
|
||||
private final McsDataSourceManager mcsDataSourceManager;
|
||||
|
||||
@Override
|
||||
public boolean isAgentMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveAgentDeviceId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> query(String sql, List<Object> params) {
|
||||
JdbcTemplate jt = new JdbcTemplate(requireDs());
|
||||
if (params == null || params.isEmpty()) {
|
||||
return jt.queryForList(sql);
|
||||
}
|
||||
return jt.queryForList(sql, params.toArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int execute(String sql, List<Object> params) {
|
||||
JdbcTemplate jt = new JdbcTemplate(requireDs());
|
||||
if (params == null || params.isEmpty()) {
|
||||
return jt.update(sql);
|
||||
}
|
||||
return jt.update(sql, params.toArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pushRows(String table, String mode, List<String> keys, List<Map<String, Object>> rows) {
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
int affected = 0;
|
||||
for (Map<String, Object> row : rows) {
|
||||
if ("update".equalsIgnoreCase(mode) || "upsert".equalsIgnoreCase(mode)) {
|
||||
int u = updateByKeys(table, keys, row);
|
||||
if (u > 0) {
|
||||
affected += u;
|
||||
continue;
|
||||
}
|
||||
if ("update".equalsIgnoreCase(mode)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
affected += insertRow(table, row);
|
||||
}
|
||||
return affected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testConnection() {
|
||||
try {
|
||||
query("SELECT 1", null);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.warn("直连中间库测试失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private int insertRow(String table, Map<String, Object> row) {
|
||||
List<String> cols = new ArrayList<>(row.keySet());
|
||||
StringBuilder sql = new StringBuilder("INSERT INTO [").append(table).append("] (");
|
||||
StringBuilder values = new StringBuilder(" VALUES (");
|
||||
List<Object> params = new ArrayList<>();
|
||||
for (int i = 0; i < cols.size(); i++) {
|
||||
if (i > 0) {
|
||||
sql.append(',');
|
||||
values.append(',');
|
||||
}
|
||||
sql.append('[').append(cols.get(i)).append(']');
|
||||
values.append('?');
|
||||
params.add(row.get(cols.get(i)));
|
||||
}
|
||||
sql.append(')').append(values).append(')');
|
||||
return execute(sql.toString(), params);
|
||||
}
|
||||
|
||||
private int updateByKeys(String table, List<String> keys, Map<String, Object> row) {
|
||||
if (keys == null || keys.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
List<String> setCols = new ArrayList<>();
|
||||
for (String c : row.keySet()) {
|
||||
boolean isKey = keys.stream().anyMatch(k -> k.equalsIgnoreCase(c));
|
||||
if (!isKey) {
|
||||
setCols.add(c);
|
||||
}
|
||||
}
|
||||
if (setCols.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
StringBuilder sql = new StringBuilder("UPDATE [").append(table).append("] SET ");
|
||||
List<Object> params = new ArrayList<>();
|
||||
for (int i = 0; i < setCols.size(); i++) {
|
||||
if (i > 0) {
|
||||
sql.append(',');
|
||||
}
|
||||
sql.append('[').append(setCols.get(i)).append("]=?");
|
||||
params.add(getIgnoreCase(row, setCols.get(i)));
|
||||
}
|
||||
sql.append(" WHERE ");
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
if (i > 0) {
|
||||
sql.append(" AND ");
|
||||
}
|
||||
sql.append('[').append(keys.get(i)).append("]=?");
|
||||
params.add(getIgnoreCase(row, keys.get(i)));
|
||||
}
|
||||
return execute(sql.toString(), params);
|
||||
}
|
||||
|
||||
private Object getIgnoreCase(Map<String, Object> row, String key) {
|
||||
if (row.containsKey(key)) {
|
||||
return row.get(key);
|
||||
}
|
||||
for (Map.Entry<String, Object> e : row.entrySet()) {
|
||||
if (e.getKey() != null && e.getKey().equalsIgnoreCase(key)) {
|
||||
return e.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DataSource requireDs() {
|
||||
DynamicRoutingDataSource routing = (DynamicRoutingDataSource) dataSource;
|
||||
DataSource src = routing.getDataSources().get(McsDataSourceManager.DS_KEY);
|
||||
if (src == null) {
|
||||
throw new IllegalStateException("中间库数据源 " + McsDataSourceManager.DS_KEY + " 未注册");
|
||||
}
|
||||
return src;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MCS 中间库访问抽象:直连 JDBC 或经桌面代理。
|
||||
*/
|
||||
public interface IMcsDataAccess {
|
||||
|
||||
boolean isAgentMode();
|
||||
|
||||
String resolveAgentDeviceId();
|
||||
|
||||
List<Map<String, Object>> query(String sql, List<Object> params);
|
||||
|
||||
int execute(String sql, List<Object> params);
|
||||
|
||||
/**
|
||||
* 批量写入中间表(EQ_SYNC_PUSH)。
|
||||
*
|
||||
* @param table 白名单表名
|
||||
* @param mode insert / update / upsert
|
||||
* @param keys 匹配键(update/upsert)
|
||||
* @param rows 行数据
|
||||
* @return 影响行数
|
||||
*/
|
||||
int pushRows(String table, String mode, List<String> keys, List<Map<String, Object>> rows);
|
||||
|
||||
boolean testConnection();
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
|
||||
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsDbConfig;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 按配置在「桌面代理 / 直连」之间切换。
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class McsDataAccessFacade implements IMcsDataAccess {
|
||||
|
||||
public static final String MODE_DESKTOP_AGENT = "DESKTOP_AGENT";
|
||||
public static final String MODE_DIRECT = "DIRECT";
|
||||
|
||||
private final McsDataSourceManager mcsDataSourceManager;
|
||||
private final DesktopAgentMcsDataAccess desktopAgentMcsDataAccess;
|
||||
private final DirectJdbcMcsDataAccess directJdbcMcsDataAccess;
|
||||
|
||||
public IMcsDataAccess current() {
|
||||
return isAgentMode() ? desktopAgentMcsDataAccess : directJdbcMcsDataAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAgentMode() {
|
||||
MesXslMcsDbConfig cfg = mcsDataSourceManager.getCachedConfig();
|
||||
if (cfg == null) {
|
||||
// 默认优先桌面代理
|
||||
return true;
|
||||
}
|
||||
String mode = StringUtils.defaultIfBlank(cfg.getAccessMode(), MODE_DESKTOP_AGENT).trim().toUpperCase();
|
||||
return MODE_DESKTOP_AGENT.equals(mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolveAgentDeviceId() {
|
||||
return current().resolveAgentDeviceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> query(String sql, List<Object> params) {
|
||||
return current().query(sql, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int execute(String sql, List<Object> params) {
|
||||
return current().execute(sql, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pushRows(String table, String mode, List<String> keys, List<Map<String, Object>> rows) {
|
||||
return current().pushRows(table, mode, keys, rows);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testConnection() {
|
||||
return current().testConnection();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MES → MCS 经桌面代理下发(EQ_SYNC_PUSH)。
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MesToMcsPushService {
|
||||
|
||||
private final McsDataAccessFacade mcsDataAccessFacade;
|
||||
|
||||
public int push(String table, String mode, List<String> keys, List<Map<String, Object>> rows) {
|
||||
if (StringUtils.isBlank(table)) {
|
||||
throw new IllegalArgumentException("table 不能为空");
|
||||
}
|
||||
int affected = mcsDataAccessFacade.pushRows(table, mode, keys, rows);
|
||||
log.info("MES→MCS 下发完成 table={} mode={} rows={} affected={}",
|
||||
table, mode, rows == null ? 0 : rows.size(), affected);
|
||||
return affected;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access.proxy;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.access.IMcsDataAccess;
|
||||
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.NClob;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLClientInfoException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Savepoint;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Struct;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class AgentProxyConnection implements Connection {
|
||||
|
||||
private final IMcsDataAccess dataAccess;
|
||||
private boolean closed;
|
||||
|
||||
public AgentProxyConnection(IMcsDataAccess dataAccess) {
|
||||
this.dataAccess = dataAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement createStatement() {
|
||||
return new AgentProxyStatement(dataAccess, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql) {
|
||||
return new AgentProxyPreparedStatement(dataAccess, sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatement prepareCall(String sql) throws SQLException {
|
||||
throw new SQLException("CallableStatement not supported by agent proxy");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String nativeSQL(String sql) {
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutoCommit(boolean autoCommit) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAutoCommit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatabaseMetaData getMetaData() throws SQLException {
|
||||
throw new SQLException("DatabaseMetaData not supported by agent proxy");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCatalog(String catalog) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCatalog() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransactionIsolation(int level) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTransactionIsolation() {
|
||||
return Connection.TRANSACTION_READ_COMMITTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLWarning getWarnings() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWarnings() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency) {
|
||||
return createStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) {
|
||||
return prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
|
||||
throw new SQLException("CallableStatement not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Class<?>> getTypeMap() {
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTypeMap(Map<String, Class<?>> map) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHoldability(int holdability) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHoldability() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Savepoint setSavepoint() throws SQLException {
|
||||
throw new SQLException("Savepoint not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Savepoint setSavepoint(String name) throws SQLException {
|
||||
throw new SQLException("Savepoint not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback(Savepoint savepoint) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseSavepoint(Savepoint savepoint) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) {
|
||||
return createStatement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) {
|
||||
return prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
|
||||
throw new SQLException("CallableStatement not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) {
|
||||
return prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) {
|
||||
return prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, String[] columnNames) {
|
||||
return prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clob createClob() throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Blob createBlob() throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public NClob createNClob() throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLXML createSQLXML() throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(int timeout) {
|
||||
return !closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientInfo(String name, String value) throws SQLClientInfoException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientInfo(Properties properties) throws SQLClientInfoException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientInfo(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getClientInfo() {
|
||||
return new Properties();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSchema(String schema) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSchema() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort(Executor executor) {
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNetworkTimeout(Executor executor, int milliseconds) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNetworkTimeout() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
if (iface.isInstance(this)) {
|
||||
return iface.cast(this);
|
||||
}
|
||||
throw new SQLException("Not a wrapper");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) {
|
||||
return iface.isInstance(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access.proxy;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.access.IMcsDataAccess;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 将 JDBC 调用转发到桌面设备代理的 DataSource,供 @DS("sqlserver_mcs") 复用。
|
||||
*/
|
||||
public class AgentProxyDataSource implements DataSource {
|
||||
|
||||
private final IMcsDataAccess dataAccess;
|
||||
|
||||
public AgentProxyDataSource(IMcsDataAccess dataAccess) {
|
||||
this.dataAccess = dataAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return new AgentProxyConnection(dataAccess);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection(String username, String password) {
|
||||
return getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
if (iface.isInstance(this)) {
|
||||
return iface.cast(this);
|
||||
}
|
||||
throw new SQLException("Not a wrapper for " + iface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) {
|
||||
return iface.isInstance(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter getLogWriter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogWriter(PrintWriter out) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoginTimeout(int seconds) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoginTimeout() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||
throw new SQLFeatureNotSupportedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,565 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access.proxy;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.access.IMcsDataAccess;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URL;
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Date;
|
||||
import java.sql.NClob;
|
||||
import java.sql.ParameterMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.Ref;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.RowId;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AgentProxyPreparedStatement implements PreparedStatement {
|
||||
|
||||
private final IMcsDataAccess dataAccess;
|
||||
private final String sql;
|
||||
private final List<Object> params = new ArrayList<>();
|
||||
private ResultSet currentRs;
|
||||
private int updateCount = -1;
|
||||
|
||||
public AgentProxyPreparedStatement(IMcsDataAccess dataAccess, String sql) {
|
||||
this.dataAccess = dataAccess;
|
||||
this.sql = sql;
|
||||
ensureCapacity(16);
|
||||
}
|
||||
|
||||
private void ensureCapacity(int index1Based) {
|
||||
while (params.size() < index1Based) {
|
||||
params.add(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void setParam(int parameterIndex, Object value) {
|
||||
ensureCapacity(parameterIndex);
|
||||
params.set(parameterIndex - 1, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet executeQuery() throws SQLException {
|
||||
try {
|
||||
List<Map<String, Object>> rows = dataAccess.query(sql, new ArrayList<>(params));
|
||||
currentRs = new MapListResultSet(rows);
|
||||
updateCount = -1;
|
||||
return currentRs;
|
||||
} catch (Exception e) {
|
||||
throw new SQLException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate() throws SQLException {
|
||||
try {
|
||||
updateCount = dataAccess.execute(sql, new ArrayList<>(params));
|
||||
currentRs = null;
|
||||
return updateCount;
|
||||
} catch (Exception e) {
|
||||
throw new SQLException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute() throws SQLException {
|
||||
String trimmed = sql == null ? "" : sql.trim();
|
||||
if (trimmed.regionMatches(true, 0, "SELECT", 0, 6)) {
|
||||
executeQuery();
|
||||
return true;
|
||||
}
|
||||
executeUpdate();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNull(int parameterIndex, int sqlType) {
|
||||
setParam(parameterIndex, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBoolean(int parameterIndex, boolean x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setByte(int parameterIndex, byte x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShort(int parameterIndex, short x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInt(int parameterIndex, int x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLong(int parameterIndex, long x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloat(int parameterIndex, float x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDouble(int parameterIndex, double x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBigDecimal(int parameterIndex, BigDecimal x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setString(int parameterIndex, String x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBytes(int parameterIndex, byte[] x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(int parameterIndex, Date x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTime(int parameterIndex, Time x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(int parameterIndex, Timestamp x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
throw new SQLException("setAsciiStream not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearParameters() {
|
||||
params.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(int parameterIndex, Object x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBatch() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRef(int parameterIndex, Ref x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlob(int parameterIndex, Blob x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClob(int parameterIndex, Clob x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setArray(int parameterIndex, Array x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSetMetaData getMetaData() {
|
||||
return currentRs == null ? null : safeMeta();
|
||||
}
|
||||
|
||||
private ResultSetMetaData safeMeta() {
|
||||
try {
|
||||
return currentRs.getMetaData();
|
||||
} catch (SQLException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(int parameterIndex, Date x, Calendar cal) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTime(int parameterIndex, Time x, Calendar cal) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNull(int parameterIndex, int sqlType, String typeName) {
|
||||
setParam(parameterIndex, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setURL(int parameterIndex, URL x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterMetaData getParameterMetaData() throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRowId(int parameterIndex, RowId x) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNString(int parameterIndex, String value) {
|
||||
setParam(parameterIndex, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNClob(int parameterIndex, NClob value) {
|
||||
setParam(parameterIndex, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSQLXML(int parameterIndex, SQLXML xmlObject) {
|
||||
setParam(parameterIndex, xmlObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) {
|
||||
setParam(parameterIndex, x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClob(int parameterIndex, Reader reader) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNClob(int parameterIndex, Reader reader) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
// Statement methods
|
||||
@Override
|
||||
public ResultSet executeQuery(String sql) throws SQLException {
|
||||
throw new SQLException("use executeQuery()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql) throws SQLException {
|
||||
throw new SQLException("use executeUpdate()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
currentRs = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxFieldSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxFieldSize(int max) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxRows() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxRows(int max) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEscapeProcessing(boolean enable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getQueryTimeout() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQueryTimeout(int seconds) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLWarning getWarnings() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWarnings() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursorName(String name) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql) throws SQLException {
|
||||
throw new SQLException("use execute()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getResultSet() {
|
||||
return currentRs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateCount() {
|
||||
return updateCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchDirection(int direction) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFetchDirection() {
|
||||
return ResultSet.FETCH_FORWARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchSize(int rows) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFetchSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetConcurrency() {
|
||||
return ResultSet.CONCUR_READ_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetType() {
|
||||
return ResultSet.TYPE_FORWARD_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBatch(String sql) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearBatch() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] executeBatch() {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults(int current) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getGeneratedKeys() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, String[] columnNames) throws SQLException {
|
||||
throw new SQLException("not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetHoldability() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPoolable(boolean poolable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPoolable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOnCompletion() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCloseOnCompletion() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
throw new SQLException("not a wrapper");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
package org.jeecg.modules.xslmes.mcs.access.proxy;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.access.IMcsDataAccess;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AgentProxyStatement implements Statement {
|
||||
|
||||
private final IMcsDataAccess dataAccess;
|
||||
private ResultSet currentRs;
|
||||
private int updateCount = -1;
|
||||
|
||||
public AgentProxyStatement(IMcsDataAccess dataAccess, String ignored) {
|
||||
this.dataAccess = dataAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet executeQuery(String sql) throws SQLException {
|
||||
try {
|
||||
List<Map<String, Object>> rows = dataAccess.query(sql, new ArrayList<>());
|
||||
currentRs = new MapListResultSet(rows);
|
||||
updateCount = -1;
|
||||
return currentRs;
|
||||
} catch (Exception e) {
|
||||
throw new SQLException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql) throws SQLException {
|
||||
try {
|
||||
updateCount = dataAccess.execute(sql, new ArrayList<>());
|
||||
currentRs = null;
|
||||
return updateCount;
|
||||
} catch (Exception e) {
|
||||
throw new SQLException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
currentRs = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxFieldSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxFieldSize(int max) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxRows() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxRows(int max) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEscapeProcessing(boolean enable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getQueryTimeout() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQueryTimeout(int seconds) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLWarning getWarnings() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWarnings() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCursorName(String name) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql) throws SQLException {
|
||||
String trimmed = sql == null ? "" : sql.trim();
|
||||
if (trimmed.regionMatches(true, 0, "SELECT", 0, 6)) {
|
||||
executeQuery(sql);
|
||||
return true;
|
||||
}
|
||||
executeUpdate(sql);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getResultSet() {
|
||||
return currentRs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateCount() {
|
||||
return updateCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchDirection(int direction) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFetchDirection() {
|
||||
return ResultSet.FETCH_FORWARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchSize(int rows) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFetchSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetConcurrency() {
|
||||
return ResultSet.CONCUR_READ_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetType() {
|
||||
return ResultSet.TYPE_FORWARD_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBatch(String sql) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearBatch() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] executeBatch() {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults(int current) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getGeneratedKeys() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
return executeUpdate(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
|
||||
return executeUpdate(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
|
||||
return executeUpdate(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
|
||||
return execute(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
|
||||
return execute(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, String[] columnNames) throws SQLException {
|
||||
return execute(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetHoldability() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPoolable(boolean poolable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPoolable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOnCompletion() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCloseOnCompletion() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
throw new SQLException("not a wrapper");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
package org.jeecg.modules.xslmes.mcs.controller;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.modules.xslmes.mcs.util.McsQueryHelper;
|
||||
import org.jeecg.modules.xslmes.mcs.entity.McsToMesActMill;
|
||||
import org.jeecg.modules.xslmes.mcs.service.IMcsToMesActMillService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.common.system.base.controller.JeecgController;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
|
||||
/**
|
||||
* 开炼机动作(中间库 MCSToMES_Act_Mill)
|
||||
*/
|
||||
@Tag(name = "开炼机动作(中间库)")
|
||||
@RestController
|
||||
@RequestMapping("/xslmes/mcs/mcsToMesActMill")
|
||||
@Slf4j
|
||||
public class McsToMesActMillController extends JeecgController<McsToMesActMill, IMcsToMesActMillService> {
|
||||
|
||||
@Autowired
|
||||
private IMcsToMesActMillService mcsToMesActMillService;
|
||||
|
||||
@Operation(summary = "开炼机动作(中间库)-分页列表查询")
|
||||
@GetMapping(value = "/list")
|
||||
public Result<IPage<McsToMesActMill>> queryPageList(McsToMesActMill mcsToMesActMill,
|
||||
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
HttpServletRequest req) {
|
||||
QueryWrapper<McsToMesActMill> queryWrapper = McsQueryHelper.buildWrapper(mcsToMesActMill, req.getParameterMap());
|
||||
Page<McsToMesActMill> page = new Page<>(pageNo, pageSize);
|
||||
IPage<McsToMesActMill> pageList = mcsToMesActMillService.page(page, queryWrapper);
|
||||
return Result.OK(pageList);
|
||||
}
|
||||
|
||||
@Operation(summary = "开炼机动作(中间库)-通过id查询")
|
||||
@GetMapping(value = "/queryById")
|
||||
public Result<McsToMesActMill> queryById(@RequestParam(name = "id", required = true) String id) {
|
||||
McsToMesActMill entity = mcsToMesActMillService.getById(id);
|
||||
if (entity == null) {
|
||||
return Result.error("未找到对应数据");
|
||||
}
|
||||
return Result.OK(entity);
|
||||
}
|
||||
|
||||
@RequiresPermissions("xslmes:mcsToMesActMill:exportXls")
|
||||
@RequestMapping(value = "/exportXls")
|
||||
public ModelAndView exportXls(HttpServletRequest request, McsToMesActMill mcsToMesActMill) {
|
||||
return super.exportXls(request, mcsToMesActMill, McsToMesActMill.class, "开炼机动作(中间库)");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.jeecg.modules.xslmes.mcs.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.modules.xslmes.mcs.access.MesToMcsPushService;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MES → MCS 经桌面代理下发。
|
||||
*/
|
||||
@Tag(name = "MES上辅机下发")
|
||||
@RestController
|
||||
@RequestMapping("/xslmes/mcs/push")
|
||||
@RequiredArgsConstructor
|
||||
public class MesToMcsPushController {
|
||||
|
||||
private final MesToMcsPushService mesToMcsPushService;
|
||||
|
||||
@Operation(summary = "经桌面代理写入中间表")
|
||||
@PostMapping("/rows")
|
||||
@SuppressWarnings("unchecked")
|
||||
public Result<Map<String, Object>> pushRows(@RequestBody Map<String, Object> body) {
|
||||
String table = body == null ? null : String.valueOf(body.getOrDefault("table", ""));
|
||||
String mode = body == null ? "insert" : String.valueOf(body.getOrDefault("mode", "insert"));
|
||||
List<String> keys = body == null ? null : (List<String>) body.get("keys");
|
||||
List<Map<String, Object>> rows = body == null ? null : (List<Map<String, Object>>) body.get("rows");
|
||||
int affected = mesToMcsPushService.push(table, mode, keys, rows);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("affected", affected);
|
||||
return Result.OK(data);
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,9 @@ public class MesXslMcsDbConfigController {
|
||||
@Autowired
|
||||
private McsDataSourceManager mcsDataSourceManager;
|
||||
|
||||
@Autowired
|
||||
private org.jeecg.modules.device.sync.agent.DeviceAgentSessionRegistry agentSessionRegistry;
|
||||
|
||||
private Integer resolveTenantId(Integer tenantId) {
|
||||
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
|
||||
if (tenantId == null) {
|
||||
@@ -75,11 +78,21 @@ public class MesXslMcsDbConfigController {
|
||||
data.put("dbConfigActive", mcsDataSourceManager.isDbConfigActive());
|
||||
data.put("readEnabled", mcsDataSourceManager.isReadEnabled());
|
||||
data.put("writeEnabled", mcsDataSourceManager.isWriteEnabled());
|
||||
boolean agentMode = mcsDataSourceManager.isDesktopAgentMode();
|
||||
data.put("accessMode", agentMode ? "DESKTOP_AGENT" : "DIRECT");
|
||||
data.put("agentMode", agentMode);
|
||||
if (cfg != null) {
|
||||
data.put("serverHost", cfg.getServerHost());
|
||||
data.put("serverPort", cfg.getServerPort());
|
||||
data.put("dbName", cfg.getDbName());
|
||||
data.put("agentDeviceId", cfg.getAgentDeviceId());
|
||||
}
|
||||
var agent = agentSessionRegistry.pickOnlineAgent(cfg == null ? null : cfg.getAgentDeviceId());
|
||||
data.put("agentOnline", agent != null && agent.isOnline());
|
||||
data.put("agentDbConnected", agent != null && agent.isDbConnected());
|
||||
data.put("agentHostName", agent == null ? null : agent.getHostName());
|
||||
data.put("agentDbMessage", agent == null ? null : agent.getDbMessage());
|
||||
data.put("agentLastSeenAt", agent == null ? null : agent.getLastSeenAt());
|
||||
return Result.OK(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,11 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jeecg.common.util.dynamic.db.DataSourceCachePool;
|
||||
import org.jeecg.modules.system.util.SecurityUtil;
|
||||
import org.jeecg.modules.xslmes.mcs.access.DesktopAgentMcsDataAccess;
|
||||
import org.jeecg.modules.xslmes.mcs.access.McsDataAccessFacade;
|
||||
import org.jeecg.modules.xslmes.mcs.access.proxy.AgentProxyDataSource;
|
||||
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsDbConfig;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -37,6 +41,9 @@ public class McsDataSourceManager {
|
||||
@Autowired
|
||||
private DruidDataSourceCreator dataSourceCreator;
|
||||
|
||||
@Autowired
|
||||
private ObjectProvider<DesktopAgentMcsDataAccess> desktopAgentMcsDataAccessProvider;
|
||||
|
||||
@Value("${spring.datasource.dynamic.datasource.sqlserver_mcs.url:}")
|
||||
private String ymlUrl;
|
||||
|
||||
@@ -98,6 +105,17 @@ public class McsDataSourceManager {
|
||||
}
|
||||
if (Integer.valueOf(1).equals(config.getStatus())) {
|
||||
try {
|
||||
if (isDesktopAgentMode(config)) {
|
||||
DesktopAgentMcsDataAccess agent = desktopAgentMcsDataAccessProvider.getIfAvailable();
|
||||
if (agent == null) {
|
||||
throw new IllegalStateException("桌面代理访问组件未就绪");
|
||||
}
|
||||
routing.addDataSource(DS_KEY, new AgentProxyDataSource(agent));
|
||||
cachedConfig.set(config);
|
||||
log.info("[MCS中间库] 已切换为桌面代理模式 sqlserver_mcs -> AgentProxy, deviceId={}",
|
||||
config.getAgentDeviceId());
|
||||
return;
|
||||
}
|
||||
String plainPassword = decryptPassword(config.getDbPassword());
|
||||
DataSourceProperty property = buildDataSourceProperty(config, plainPassword);
|
||||
DataSource mcsDs = dataSourceCreator.createDataSource(property);
|
||||
@@ -117,6 +135,21 @@ public class McsDataSourceManager {
|
||||
log.info("[MCS中间库] 连接未启用,读写开关仍按页面配置生效");
|
||||
}
|
||||
|
||||
public boolean isDesktopAgentMode(MesXslMcsDbConfig config) {
|
||||
MesXslMcsDbConfig cfg = config != null ? config : cachedConfig.get();
|
||||
if (cfg == null) {
|
||||
return true;
|
||||
}
|
||||
String mode = StringUtils.isBlank(cfg.getAccessMode())
|
||||
? McsDataAccessFacade.MODE_DESKTOP_AGENT
|
||||
: cfg.getAccessMode().trim().toUpperCase();
|
||||
return McsDataAccessFacade.MODE_DESKTOP_AGENT.equals(mode);
|
||||
}
|
||||
|
||||
public boolean isDesktopAgentMode() {
|
||||
return isDesktopAgentMode(null);
|
||||
}
|
||||
|
||||
private void closeAndRemoveDataSource(DynamicRoutingDataSource routing) {
|
||||
if (!routing.getDataSources().containsKey(DS_KEY)) {
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package org.jeecg.modules.xslmes.mcs.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.jeecgframework.poi.excel.annotation.Excel;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 开炼机动作(中间库 MCSToMES_Act_Mill)
|
||||
*/
|
||||
@Data
|
||||
@TableName("MCSToMES_Act_Mill")
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Schema(description = "开炼机动作(中间库)")
|
||||
public class McsToMesActMill implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "GUID", type = IdType.INPUT)
|
||||
@Schema(description = "GUID")
|
||||
@Excel(name = "GUID", width = 36)
|
||||
private String guid;
|
||||
|
||||
@Excel(name = "动作地址", width = 10)
|
||||
@Schema(description = "动作地址")
|
||||
@TableField("act_addr")
|
||||
private Integer actAddr;
|
||||
|
||||
@Excel(name = "动作名称", width = 20)
|
||||
@Schema(description = "动作名称")
|
||||
@TableField("act_name")
|
||||
private String actName;
|
||||
|
||||
@Excel(name = "动作名称(英)", width = 20)
|
||||
@Schema(description = "动作名称(英)")
|
||||
@TableField("act_name_en")
|
||||
private String actNameEn;
|
||||
|
||||
@Excel(name = "动作备注", width = 15)
|
||||
@Schema(description = "动作备注")
|
||||
@TableField("act_memo")
|
||||
private String actMemo;
|
||||
|
||||
@Excel(name = "动作关联地址", width = 12)
|
||||
@Schema(description = "动作关联地址")
|
||||
@TableField("act_Repaddr")
|
||||
private Integer actRepaddr;
|
||||
|
||||
@Excel(name = "写入时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Schema(description = "写入时间")
|
||||
@TableField("WriteTime")
|
||||
private Date writeTime;
|
||||
|
||||
@Excel(name = "读取时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Schema(description = "读取时间")
|
||||
@TableField("ReadTime")
|
||||
private Date readTime;
|
||||
|
||||
@Excel(name = "读写标识", width = 10)
|
||||
@Schema(description = "读写标识")
|
||||
@TableField("RW_Flag")
|
||||
private Integer rwFlag;
|
||||
}
|
||||
@@ -66,6 +66,14 @@ public class MesXslMcsDbConfig implements Serializable {
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
//update-begin---author:cursor ---date:2026-07-20 for:【设备库桥接】访问模式与绑定桌面代理-----------
|
||||
@Schema(description = "访问模式:DESKTOP_AGENT=桌面代理,DIRECT=服务端直连")
|
||||
private String accessMode;
|
||||
|
||||
@Schema(description = "绑定的桌面代理 deviceId")
|
||||
private String agentDeviceId;
|
||||
//update-end---author:cursor ---date:2026-07-20 for:【设备库桥接】访问模式与绑定桌面代理-----------
|
||||
|
||||
private String createBy;
|
||||
|
||||
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.jeecg.modules.xslmes.mcs.mapper;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.entity.McsToMesActMill;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* 开炼机动作(中间库)
|
||||
*/
|
||||
public interface McsToMesActMillMapper extends BaseMapper<McsToMesActMill> {
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.jeecg.modules.xslmes.mcs.service;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.entity.McsToMesActMill;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* 开炼机动作(中间库)
|
||||
*/
|
||||
public interface IMcsToMesActMillService extends IService<McsToMesActMill> {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.jeecg.modules.xslmes.mcs.service.impl;
|
||||
|
||||
import org.jeecg.modules.xslmes.mcs.entity.McsToMesActMill;
|
||||
import org.jeecg.modules.xslmes.mcs.mapper.McsToMesActMillMapper;
|
||||
import org.jeecg.modules.xslmes.mcs.service.IMcsToMesActMillService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
|
||||
/**
|
||||
* 开炼机动作(中间库)
|
||||
*/
|
||||
@Service
|
||||
@DS("sqlserver_mcs")
|
||||
public class McsToMesActMillServiceImpl extends ServiceImpl<McsToMesActMillMapper, McsToMesActMill> implements IMcsToMesActMillService {
|
||||
}
|
||||
@@ -30,6 +30,9 @@ public class MesXslMcsDbConfigServiceImpl extends ServiceImpl<MesXslMcsDbConfigM
|
||||
@Autowired
|
||||
private McsDataSourceManager mcsDataSourceManager;
|
||||
|
||||
@Autowired
|
||||
private org.jeecg.modules.xslmes.mcs.access.McsDataAccessFacade mcsDataAccessFacade;
|
||||
|
||||
@Override
|
||||
public MesXslMcsDbConfig getCurrentConfig(Integer tenantId) {
|
||||
int tid = tenantId != null ? tenantId : 0;
|
||||
@@ -61,10 +64,14 @@ public class MesXslMcsDbConfigServiceImpl extends ServiceImpl<MesXslMcsDbConfigM
|
||||
if (config == null) {
|
||||
return Result.error("配置不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(config.getServerHost())) {
|
||||
if (StringUtils.isBlank(config.getAccessMode())) {
|
||||
config.setAccessMode("DESKTOP_AGENT");
|
||||
}
|
||||
boolean agentMode = "DESKTOP_AGENT".equalsIgnoreCase(config.getAccessMode().trim());
|
||||
if (!agentMode && StringUtils.isBlank(config.getServerHost())) {
|
||||
return Result.error("服务器地址不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(config.getDbUsername())) {
|
||||
if (!agentMode && StringUtils.isBlank(config.getDbUsername())) {
|
||||
return Result.error("用户名不能为空");
|
||||
}
|
||||
if (config.getTenantId() == null) {
|
||||
@@ -93,13 +100,20 @@ public class MesXslMcsDbConfigServiceImpl extends ServiceImpl<MesXslMcsDbConfigM
|
||||
}
|
||||
|
||||
String plainPassword = resolvePlainPassword(config);
|
||||
if (StringUtils.isBlank(plainPassword)) {
|
||||
if (!agentMode && StringUtils.isBlank(plainPassword)) {
|
||||
return Result.error("密码不能为空");
|
||||
}
|
||||
|
||||
String err = mcsDataSourceManager.testConnection(config, plainPassword);
|
||||
if (err != null && Integer.valueOf(1).equals(config.getStatus())) {
|
||||
return Result.error("连接测试失败:" + err);
|
||||
if (agentMode && StringUtils.isBlank(config.getServerHost())) {
|
||||
config.setServerHost("desktop-agent");
|
||||
}
|
||||
if (agentMode && StringUtils.isBlank(config.getDbUsername())) {
|
||||
config.setDbUsername("desktop-agent");
|
||||
}
|
||||
if (!agentMode) {
|
||||
String err = mcsDataSourceManager.testConnection(config, plainPassword);
|
||||
if (err != null && Integer.valueOf(1).equals(config.getStatus())) {
|
||||
return Result.error("连接测试失败:" + err);
|
||||
}
|
||||
}
|
||||
|
||||
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
@@ -111,12 +125,16 @@ public class MesXslMcsDbConfigServiceImpl extends ServiceImpl<MesXslMcsDbConfigM
|
||||
if (old == null) {
|
||||
return Result.error("配置不存在");
|
||||
}
|
||||
config.setDbPassword(mcsDataSourceManager.encryptPassword(plainPassword));
|
||||
if (StringUtils.isNotBlank(plainPassword)) {
|
||||
config.setDbPassword(mcsDataSourceManager.encryptPassword(plainPassword));
|
||||
} else {
|
||||
config.setDbPassword(old.getDbPassword());
|
||||
}
|
||||
config.setUpdateBy(username);
|
||||
config.setUpdateTime(now);
|
||||
updateById(config);
|
||||
} else {
|
||||
config.setDbPassword(mcsDataSourceManager.encryptPassword(plainPassword));
|
||||
config.setDbPassword(mcsDataSourceManager.encryptPassword(StringUtils.defaultString(plainPassword)));
|
||||
config.setCreateBy(username);
|
||||
config.setCreateTime(now);
|
||||
config.setUpdateBy(username);
|
||||
@@ -151,6 +169,14 @@ public class MesXslMcsDbConfigServiceImpl extends ServiceImpl<MesXslMcsDbConfigM
|
||||
if (config == null) {
|
||||
return Result.error("尚未配置中间库连接");
|
||||
}
|
||||
if (mcsDataSourceManager.isDesktopAgentMode(config)) {
|
||||
try {
|
||||
boolean ok = mcsDataAccessFacade.testConnection();
|
||||
return ok ? Result.OK("桌面代理设备库连接成功") : Result.error("桌面代理设备库连接失败(代理离线或库不可达)");
|
||||
} catch (Exception e) {
|
||||
return Result.error("桌面代理探测失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
String plainPassword = mcsDataSourceManager.decryptPassword(config.getDbPassword());
|
||||
String err = mcsDataSourceManager.testConnection(config, plainPassword);
|
||||
if (err == null) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package org.jeecg.modules.xslmes.mcs.sync;
|
||||
|
||||
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jeecg.modules.xslmes.mcs.access.McsDataAccessFacade;
|
||||
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
|
||||
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncConfig;
|
||||
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncField;
|
||||
@@ -69,6 +69,9 @@ public class GenericMcsSyncEngine {
|
||||
@Autowired
|
||||
private org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager mcsDataSourceManager;
|
||||
|
||||
@Autowired
|
||||
private McsDataAccessFacade mcsDataAccessFacade;
|
||||
|
||||
//update-begin---author:GHT ---date:20260617 for:【MES上辅机】采集模式 全量/时间/增量-----------
|
||||
public String sync(MesXslMcsSyncConfig cfg, List<MesXslMcsSyncField> fields) {
|
||||
String sourceTable = trim(cfg.getSourceTable());
|
||||
@@ -91,7 +94,6 @@ public class GenericMcsSyncEngine {
|
||||
}
|
||||
|
||||
String mode = StringUtils.isBlank(cfg.getSyncMode()) ? MODE_FULL : cfg.getSyncMode().trim().toUpperCase();
|
||||
JdbcTemplate sourceJt = new JdbcTemplate(getSourceDataSource());
|
||||
JdbcTemplate targetJt = new JdbcTemplate(dataSource);
|
||||
|
||||
// 目标表标准字段探测 + 自动填充列
|
||||
@@ -134,7 +136,7 @@ public class GenericMcsSyncEngine {
|
||||
String predicate = flagPredicate(flagCol, cfg.getFlagCondition(), cfg.getFlagMatchValue());
|
||||
String sql = "SELECT TOP " + limit + " " + colList(srcCols) + " FROM [" + sourceTable + "]"
|
||||
+ " WHERE (" + predicate + ")";
|
||||
rows = sourceJt.queryForList(sql);
|
||||
rows = mcsDataAccessFacade.query(sql, null);
|
||||
if (rows.isEmpty()) {
|
||||
return "增量采集:无待采集数据";
|
||||
}
|
||||
@@ -149,10 +151,10 @@ public class GenericMcsSyncEngine {
|
||||
sql.append(" AND [").append(incrCol).append("] < ?");
|
||||
args.add(window[1]);
|
||||
}
|
||||
rows = sourceJt.queryForList(sql.toString(), args.toArray());
|
||||
rows = mcsDataAccessFacade.query(sql.toString(), args);
|
||||
} else {
|
||||
// FULL
|
||||
rows = sourceJt.queryForList("SELECT " + colList(srcCols) + " FROM [" + sourceTable + "]");
|
||||
rows = mcsDataAccessFacade.query("SELECT " + colList(srcCols) + " FROM [" + sourceTable + "]", null);
|
||||
}
|
||||
|
||||
if (rows.isEmpty()) {
|
||||
@@ -209,7 +211,7 @@ public class GenericMcsSyncEngine {
|
||||
// INCR(标记回写):对本批所有源行回写标记值,下轮不再采集
|
||||
if (flagMode) {
|
||||
String writeValue = StringUtils.isBlank(cfg.getFlagWriteValue()) ? FLAG_SYNCED : cfg.getFlagWriteValue();
|
||||
int marked = writeBackFlag(sourceJt, sourceTable, flagCol, cfg.getFlagCondition(), cfg.getFlagMatchValue(), writeValue, keyMaps, rows);
|
||||
int marked = writeBackFlag(sourceTable, flagCol, cfg.getFlagCondition(), cfg.getFlagMatchValue(), writeValue, keyMaps, rows);
|
||||
return String.format("增量采集:新增%d,更新%d,未变%d,回写标记%d,源%d条",
|
||||
ins, upd, unchanged, marked, rows.size());
|
||||
}
|
||||
@@ -252,14 +254,14 @@ public class GenericMcsSyncEngine {
|
||||
* 避免误标在本轮 SELECT 之后才进入中间库、尚未采集的新数据;
|
||||
* 并以采集条件谓词做守卫,避开本轮已被其他进程改动的行。</p>
|
||||
*/
|
||||
private int writeBackFlag(JdbcTemplate sourceJt, String sourceTable, String flagCol, String condition,
|
||||
private int writeBackFlag(String sourceTable, String flagCol, String condition,
|
||||
String matchValue, String writeValue, List<MesXslMcsSyncField> keyMaps, List<Map<String, Object>> rows) {
|
||||
validateIdent(flagCol);
|
||||
StringBuilder sql = new StringBuilder("UPDATE [").append(sourceTable).append("] SET [")
|
||||
.append(flagCol).append("] = ? WHERE ");
|
||||
sql.append(keyMaps.stream().map(k -> "[" + k.getSourceField() + "] = ?").collect(Collectors.joining(" AND ")));
|
||||
sql.append(" AND (").append(flagPredicate(flagCol, condition, matchValue)).append(")");
|
||||
List<Object[]> argsList = new ArrayList<>();
|
||||
int total = 0;
|
||||
Set<String> handled = new HashSet<>();
|
||||
for (Map<String, Object> row : rows) {
|
||||
Map<String, Object> rci = ci(row);
|
||||
@@ -272,9 +274,9 @@ public class GenericMcsSyncEngine {
|
||||
for (MesXslMcsSyncField k : keyMaps) {
|
||||
args.add(rci.get(k.getSourceField()));
|
||||
}
|
||||
argsList.add(args.toArray());
|
||||
total += mcsDataAccessFacade.execute(sql.toString(), args);
|
||||
}
|
||||
return batch(sourceJt, sql.toString(), argsList);
|
||||
return total;
|
||||
}
|
||||
//update-end---author:GHT ---date:20260617 for:【MES上辅机】增量匹配改为标记位回写-----------
|
||||
|
||||
@@ -502,15 +504,6 @@ public class GenericMcsSyncEngine {
|
||||
return maps.stream().anyMatch(m -> m.getTargetField() != null && m.getTargetField().equalsIgnoreCase(targetCol));
|
||||
}
|
||||
|
||||
private DataSource getSourceDataSource() {
|
||||
DynamicRoutingDataSource routing = (DynamicRoutingDataSource) dataSource;
|
||||
DataSource src = routing.getDataSources().get(McsDataSourceManager.DS_KEY);
|
||||
if (src == null) {
|
||||
throw new IllegalStateException("中间库数据源 " + McsDataSourceManager.DS_KEY + " 未注册");
|
||||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
private void validateIdent(String name) {
|
||||
if (name == null || !IDENT.matcher(name).matches()) {
|
||||
throw new IllegalArgumentException("非法的表名或字段名: " + name);
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.jeecg.modules.xslmes.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.jeecg.modules.xslmes.entity.MesXslMillAction;
|
||||
|
||||
public interface IMesXslMillActionService extends IService<MesXslMillAction> {}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.jeecg.modules.xslmes.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.jeecg.modules.xslmes.entity.MesXslMillAction;
|
||||
import org.jeecg.modules.xslmes.mapper.MesXslMillActionMapper;
|
||||
import org.jeecg.modules.xslmes.service.IMesXslMillActionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class MesXslMillActionServiceImpl extends ServiceImpl<MesXslMillActionMapper, MesXslMillAction> implements IMesXslMillActionService {}
|
||||
@@ -103,6 +103,8 @@ public class MesXslMixingProductionPlanServiceImpl
|
||||
|
||||
private void rebuildRawMaterialDemandPlan(List<MesXslMixingProductionPlan> savedPlans) {
|
||||
jdbcTemplate.update("DELETE FROM mes_xsl_raw_material_demand_plan");
|
||||
jdbcTemplate.update("DELETE FROM mes_xsl_auto_small_material_demand_plan");
|
||||
jdbcTemplate.update("DELETE FROM mes_xsl_manual_small_material_demand_plan");
|
||||
if (CollectionUtils.isEmpty(savedPlans)) {
|
||||
return;
|
||||
}
|
||||
@@ -184,6 +186,8 @@ public class MesXslMixingProductionPlanServiceImpl
|
||||
}
|
||||
|
||||
Map<String, RawDemandAggregate> aggregateMap = new HashMap<>();
|
||||
Map<String, SmallDemandAggregate> autoAggregateMap = new HashMap<>();
|
||||
Map<String, SmallDemandAggregate> manualAggregateMap = new HashMap<>();
|
||||
for (MesXslMixingProductionPlan plan : validPlans) {
|
||||
String specId = specIdByName.get(StringUtils.trimToEmpty(plan.getFormulaName()));
|
||||
if (StringUtils.isBlank(specId)) {
|
||||
@@ -241,19 +245,39 @@ public class MesXslMixingProductionPlanServiceImpl
|
||||
StringUtils.defaultString(erpCode),
|
||||
rawMaterialName));
|
||||
aggregate.demandWeight = aggregate.demandWeight.add(demandWeight);
|
||||
|
||||
String smallKey =
|
||||
String.join(
|
||||
"|",
|
||||
planDateKey,
|
||||
StringUtils.defaultString(plan.getMachineId()),
|
||||
StringUtils.defaultString(plan.getMachineName()),
|
||||
rawMaterialName);
|
||||
boolean isAutoKind = StringUtils.contains(StringUtils.trimToEmpty(detail.getMaterialKind()), "自动");
|
||||
Map<String, SmallDemandAggregate> targetSmallMap = isAutoKind ? autoAggregateMap : manualAggregateMap;
|
||||
SmallDemandAggregate smallAggregate =
|
||||
targetSmallMap.computeIfAbsent(
|
||||
smallKey,
|
||||
k ->
|
||||
new SmallDemandAggregate(
|
||||
plan.getPlanDate(),
|
||||
StringUtils.trimToNull(plan.getMachineId()),
|
||||
StringUtils.trimToNull(plan.getMachineName()),
|
||||
rawMaterialName));
|
||||
smallAggregate.demandWeight = smallAggregate.demandWeight.add(demandWeight);
|
||||
}
|
||||
}
|
||||
if (aggregateMap.isEmpty()) {
|
||||
if (aggregateMap.isEmpty() && autoAggregateMap.isEmpty() && manualAggregateMap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Object[]> batchArgs = new ArrayList<>();
|
||||
List<Object[]> rawBatchArgs = new ArrayList<>();
|
||||
Date now = new Date();
|
||||
for (RawDemandAggregate aggregate : aggregateMap.values()) {
|
||||
if (aggregate.demandWeight.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
continue;
|
||||
}
|
||||
batchArgs.add(
|
||||
rawBatchArgs.add(
|
||||
new Object[] {
|
||||
IdWorker.getIdStr(),
|
||||
aggregate.machineId,
|
||||
@@ -270,14 +294,53 @@ public class MesXslMixingProductionPlanServiceImpl
|
||||
CommonConstant.DEL_FLAG_0
|
||||
});
|
||||
}
|
||||
if (batchArgs.isEmpty()) {
|
||||
return;
|
||||
if (!rawBatchArgs.isEmpty()) {
|
||||
jdbcTemplate.batchUpdate(
|
||||
"INSERT INTO mes_xsl_raw_material_demand_plan "
|
||||
+ "(id, machine_id, machine_name, material_id, erp_code, raw_material_name, demand_weight, standard_weight, actual_weight, plan_date, create_time, update_time, del_flag) "
|
||||
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
rawBatchArgs);
|
||||
}
|
||||
jdbcTemplate.batchUpdate(
|
||||
"INSERT INTO mes_xsl_raw_material_demand_plan "
|
||||
+ "(id, machine_id, machine_name, material_id, erp_code, raw_material_name, demand_weight, standard_weight, actual_weight, plan_date, create_time, update_time, del_flag) "
|
||||
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
batchArgs);
|
||||
|
||||
List<Object[]> autoBatchArgs = buildSmallDemandBatchArgs(autoAggregateMap, now);
|
||||
if (!autoBatchArgs.isEmpty()) {
|
||||
jdbcTemplate.batchUpdate(
|
||||
"INSERT INTO mes_xsl_auto_small_material_demand_plan "
|
||||
+ "(id, stat_date, machine_id, machine_name, raw_material_name, demand_weight, create_time, update_time, del_flag) "
|
||||
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
autoBatchArgs);
|
||||
}
|
||||
List<Object[]> manualBatchArgs = buildSmallDemandBatchArgs(manualAggregateMap, now);
|
||||
if (!manualBatchArgs.isEmpty()) {
|
||||
jdbcTemplate.batchUpdate(
|
||||
"INSERT INTO mes_xsl_manual_small_material_demand_plan "
|
||||
+ "(id, stat_date, machine_id, machine_name, raw_material_name, demand_weight, create_time, update_time, del_flag) "
|
||||
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
manualBatchArgs);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Object[]> buildSmallDemandBatchArgs(
|
||||
Map<String, SmallDemandAggregate> aggregateMap, Date now) {
|
||||
List<Object[]> batchArgs = new ArrayList<>();
|
||||
for (SmallDemandAggregate aggregate : aggregateMap.values()) {
|
||||
if (aggregate.demandWeight.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
continue;
|
||||
}
|
||||
batchArgs.add(
|
||||
new Object[] {
|
||||
IdWorker.getIdStr(),
|
||||
aggregate.statDate,
|
||||
aggregate.machineId,
|
||||
aggregate.machineName,
|
||||
aggregate.rawMaterialName,
|
||||
aggregate.demandWeight,
|
||||
now,
|
||||
now,
|
||||
CommonConstant.DEL_FLAG_0
|
||||
});
|
||||
}
|
||||
return batchArgs;
|
||||
}
|
||||
|
||||
private static class RawDemandAggregate {
|
||||
@@ -305,6 +368,22 @@ public class MesXslMixingProductionPlanServiceImpl
|
||||
}
|
||||
}
|
||||
|
||||
private static class SmallDemandAggregate {
|
||||
private final Date statDate;
|
||||
private final String machineId;
|
||||
private final String machineName;
|
||||
private final String rawMaterialName;
|
||||
private BigDecimal demandWeight = BigDecimal.ZERO;
|
||||
|
||||
private SmallDemandAggregate(
|
||||
Date statDate, String machineId, String machineName, String rawMaterialName) {
|
||||
this.statDate = statDate;
|
||||
this.machineId = machineId;
|
||||
this.machineName = machineName;
|
||||
this.rawMaterialName = rawMaterialName;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasBusinessData(MesXslMixingProductionPlan row) {
|
||||
return StringUtils.isNotBlank(row.getMachineId())
|
||||
|| StringUtils.isNotBlank(row.getPlanId())
|
||||
|
||||
Reference in New Issue
Block a user