|
@@ -0,0 +1,276 @@
|
|
|
|
|
+package com.jeesite.modules.scheduling;
|
|
|
|
|
+
|
|
|
|
|
+import java.sql.Connection;
|
|
|
|
|
+import java.sql.PreparedStatement;
|
|
|
|
|
+import java.sql.Timestamp;
|
|
|
|
|
+import java.util.Calendar;
|
|
|
|
|
+import java.util.Date;
|
|
|
|
|
+import java.util.LinkedHashMap;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+
|
|
|
|
|
+import javax.sql.DataSource;
|
|
|
|
|
+
|
|
|
|
|
+import org.slf4j.Logger;
|
|
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
+import org.springframework.context.annotation.Configuration;
|
|
|
|
|
+import org.springframework.scheduling.annotation.EnableScheduling;
|
|
|
|
|
+import org.springframework.scheduling.annotation.Scheduled;
|
|
|
|
|
+
|
|
|
|
|
+import com.jeesite.common.lang.StringUtils;
|
|
|
|
|
+import com.jeesite.modules.tianHong.dao.MachineAttrHistoryDao;
|
|
|
|
|
+import com.jeesite.modules.tianHong.dao.MachineAttrStateDao;
|
|
|
|
|
+import com.jeesite.modules.tianHong.entity.MachineAttrHistory;
|
|
|
|
|
+import com.jeesite.modules.tianHong.entity.MachineAttrState;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 天虹浇筑历史备份:每10分钟整点(00/10/20/30/40/50)
|
|
|
|
|
+ * 备份上一完整窗口 [T-10min, T) 到主库 mes_cloud_ljr.tianhong_backup
|
|
|
|
|
+ * 曲线字段:秒级 600 槽,值用 # 分隔,缺秒留空
|
|
|
|
|
+ */
|
|
|
|
|
+@Configuration
|
|
|
|
|
+@EnableScheduling
|
|
|
|
|
+public class TianhongBackupScheduling {
|
|
|
|
|
+
|
|
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(TianhongBackupScheduling.class);
|
|
|
|
|
+
|
|
|
|
|
+ private static final int POINT_COUNT = 600;
|
|
|
|
|
+
|
|
|
|
|
+ private static final String UPSERT_SQL =
|
|
|
|
|
+ "INSERT INTO tianhong_backup ("
|
|
|
|
|
+ + "eqp_id, window_start, window_end,"
|
|
|
|
|
+ + "cru_temp, alu_temp, mould_info,"
|
|
|
|
|
+ + "theory_pressure, real_pressure, pressure_level, ele_consume,"
|
|
|
|
|
+ + "alu_val, pressurize_time, cooling_time, pre_pres, hold_pressure, mold_filling_pre,"
|
|
|
|
|
+ + "point_count, create_date, update_date"
|
|
|
|
|
+ + ") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW(),NOW()) "
|
|
|
|
|
+ + "ON DUPLICATE KEY UPDATE "
|
|
|
|
|
+ + "window_end=VALUES(window_end),"
|
|
|
|
|
+ + "cru_temp=VALUES(cru_temp), alu_temp=VALUES(alu_temp), mould_info=VALUES(mould_info),"
|
|
|
|
|
+ + "theory_pressure=VALUES(theory_pressure), real_pressure=VALUES(real_pressure),"
|
|
|
|
|
+ + "pressure_level=VALUES(pressure_level), ele_consume=VALUES(ele_consume),"
|
|
|
|
|
+ + "alu_val=VALUES(alu_val), pressurize_time=VALUES(pressurize_time),"
|
|
|
|
|
+ + "cooling_time=VALUES(cooling_time), pre_pres=VALUES(pre_pres),"
|
|
|
|
|
+ + "hold_pressure=VALUES(hold_pressure), mold_filling_pre=VALUES(mold_filling_pre),"
|
|
|
|
|
+ + "point_count=VALUES(point_count), update_date=NOW()";
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private MachineAttrHistoryDao machineAttrHistoryDao;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private MachineAttrStateDao machineAttrStateDao;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private DataSource dataSource;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 每10分钟整点执行:备份刚结束的窗口
|
|
|
|
|
+ * 例:14:10:00 执行时备份 [14:00:00, 14:10:00)
|
|
|
|
|
+ */
|
|
|
|
|
+ @Scheduled(cron = "0 0/10 * * * ?")
|
|
|
|
|
+ public void backupLastClosedWindow() {
|
|
|
|
|
+ Date end = floorTo10Minutes(new Date());
|
|
|
|
|
+ Date start = addMinutes(end, -10);
|
|
|
|
|
+ log.info("tianhong_backup start, window=[{}, {})", format(start), format(end));
|
|
|
|
|
+ List<MachineAttrState> devices;
|
|
|
|
|
+ try {
|
|
|
|
|
+ devices = machineAttrStateDao.findList(new MachineAttrState());
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("tianhong_backup list devices failed", e);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (devices == null || devices.isEmpty()) {
|
|
|
|
|
+ log.warn("tianhong_backup no devices");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ int ok = 0;
|
|
|
|
|
+ for (MachineAttrState device : devices) {
|
|
|
|
|
+ if (device == null || StringUtils.isBlank(device.getEqpId())) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ backupOne(device.getEqpId(), start, end);
|
|
|
|
|
+ ok++;
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("tianhong_backup failed eqpId={}", device.getEqpId(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("tianhong_backup done, devices={}, ok={}", devices.size(), ok);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void backupOne(String eqpId, Date start, Date end) throws Exception {
|
|
|
|
|
+ String cru = toSeries(machineAttrHistoryDao.findCruInRange(eqpId, start, end), start, "cru");
|
|
|
|
|
+ String alu = toSeries(machineAttrHistoryDao.findAluInRange(eqpId, start, end), start, "alu");
|
|
|
|
|
+ String mould = toMouldSeries(machineAttrHistoryDao.findMouldInRange(eqpId, start, end), start);
|
|
|
|
|
+ List<MachineAttrHistory> pressureList = machineAttrHistoryDao.findPressureInRange(eqpId, start, end);
|
|
|
|
|
+ String theory = toSeries(pressureList, start, "theory");
|
|
|
|
|
+ String real = toSeries(pressureList, start, "real");
|
|
|
|
|
+ String level = toSeries(pressureList, start, "level");
|
|
|
|
|
+ String ele = toSeries(machineAttrHistoryDao.findEleInRange(eqpId, start, end), start, "ele");
|
|
|
|
|
+
|
|
|
|
|
+ String aluVal = toAttrSeries(eqpId, "alu_val", start, end);
|
|
|
|
|
+ String pressurize = toAttrSeries(eqpId, "pressurizeTime", start, end);
|
|
|
|
|
+ String cooling = toAttrSeries(eqpId, "coolingTime", start, end);
|
|
|
|
|
+ String prePres = toAttrSeries(eqpId, "PrePres", start, end);
|
|
|
|
|
+ String hold = toAttrSeries(eqpId, "HoldPressure", start, end);
|
|
|
|
|
+ String moldPre = toAttrSeries(eqpId, "moldFillingPre", start, end);
|
|
|
|
|
+
|
|
|
|
|
+ try (Connection conn = dataSource.getConnection()) {
|
|
|
|
|
+ conn.setAutoCommit(true);
|
|
|
|
|
+ try (PreparedStatement ps = conn.prepareStatement(UPSERT_SQL)) {
|
|
|
|
|
+ int i = 1;
|
|
|
|
|
+ ps.setString(i++, eqpId);
|
|
|
|
|
+ ps.setTimestamp(i++, new Timestamp(start.getTime()));
|
|
|
|
|
+ ps.setTimestamp(i++, new Timestamp(end.getTime()));
|
|
|
|
|
+ ps.setString(i++, cru);
|
|
|
|
|
+ ps.setString(i++, alu);
|
|
|
|
|
+ ps.setString(i++, mould);
|
|
|
|
|
+ ps.setString(i++, theory);
|
|
|
|
|
+ ps.setString(i++, real);
|
|
|
|
|
+ ps.setString(i++, level);
|
|
|
|
|
+ ps.setString(i++, ele);
|
|
|
|
|
+ ps.setString(i++, aluVal);
|
|
|
|
|
+ ps.setString(i++, pressurize);
|
|
|
|
|
+ ps.setString(i++, cooling);
|
|
|
|
|
+ ps.setString(i++, prePres);
|
|
|
|
|
+ ps.setString(i++, hold);
|
|
|
|
|
+ ps.setString(i++, moldPre);
|
|
|
|
|
+ ps.setInt(i++, POINT_COUNT);
|
|
|
|
|
+ ps.executeUpdate();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String toAttrSeries(String eqpId, String attr, Date start, Date end) {
|
|
|
|
|
+ return toSeries(machineAttrHistoryDao.findAttrInRange(eqpId, attr, start, end), start, "attr");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String toSeries(List<MachineAttrHistory> list, Date windowStart, String type) {
|
|
|
|
|
+ String[] slots = emptySlots();
|
|
|
|
|
+ if (list == null || list.isEmpty()) {
|
|
|
|
|
+ return join(slots);
|
|
|
|
|
+ }
|
|
|
|
|
+ for (MachineAttrHistory row : list) {
|
|
|
|
|
+ if (row == null || row.getEventTime() == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ int idx = secIndex(row.getEventTime(), windowStart);
|
|
|
|
|
+ if (idx < 0 || idx >= POINT_COUNT) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ String val;
|
|
|
|
|
+ if ("cru".equals(type)) {
|
|
|
|
|
+ val = row.getCruTemp();
|
|
|
|
|
+ } else if ("alu".equals(type)) {
|
|
|
|
|
+ val = row.getAluTemp();
|
|
|
|
|
+ } else if ("ele".equals(type)) {
|
|
|
|
|
+ val = row.getEleConsume();
|
|
|
|
|
+ } else if ("theory".equals(type)) {
|
|
|
|
|
+ val = row.getTheoryPressure();
|
|
|
|
|
+ } else if ("real".equals(type)) {
|
|
|
|
|
+ val = row.getRealPressure();
|
|
|
|
|
+ } else if ("level".equals(type)) {
|
|
|
|
|
+ val = row.getPressureLevel();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ val = row.getVal();
|
|
|
|
|
+ }
|
|
|
|
|
+ slots[idx] = val == null ? "" : String.valueOf(val);
|
|
|
|
|
+ }
|
|
|
|
|
+ return join(slots);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String toMouldSeries(List<MachineAttrHistory> list, Date windowStart) {
|
|
|
|
|
+ String[] slots = emptySlots();
|
|
|
|
|
+ if (list == null || list.isEmpty()) {
|
|
|
|
|
+ return join(slots);
|
|
|
|
|
+ }
|
|
|
|
|
+ Map<Integer, LinkedHashMap<String, String>> bySec = new LinkedHashMap<>();
|
|
|
|
|
+ for (MachineAttrHistory row : list) {
|
|
|
|
|
+ if (row == null || row.getEventTime() == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ int idx = secIndex(row.getEventTime(), windowStart);
|
|
|
|
|
+ if (idx < 0 || idx >= POINT_COUNT) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ LinkedHashMap<String, String> parts = bySec.get(idx);
|
|
|
|
|
+ if (parts == null) {
|
|
|
|
|
+ parts = new LinkedHashMap<>();
|
|
|
|
|
+ bySec.put(idx, parts);
|
|
|
|
|
+ }
|
|
|
|
|
+ String mouldId = row.getMouldInfo();
|
|
|
|
|
+ if (StringUtils.isBlank(mouldId)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ parts.put(mouldId, row.getVal() == null ? "" : String.valueOf(row.getVal()));
|
|
|
|
|
+ }
|
|
|
|
|
+ for (Map.Entry<Integer, LinkedHashMap<String, String>> e : bySec.entrySet()) {
|
|
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
|
|
+ for (Map.Entry<String, String> p : e.getValue().entrySet()) {
|
|
|
|
|
+ if (sb.length() > 0) {
|
|
|
|
|
+ sb.append(',');
|
|
|
|
|
+ }
|
|
|
|
|
+ sb.append(p.getKey()).append(':').append(p.getValue());
|
|
|
|
|
+ }
|
|
|
|
|
+ slots[e.getKey()] = sb.toString();
|
|
|
|
|
+ }
|
|
|
|
|
+ return join(slots);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static String[] emptySlots() {
|
|
|
|
|
+ String[] slots = new String[POINT_COUNT];
|
|
|
|
|
+ for (int i = 0; i < POINT_COUNT; i++) {
|
|
|
|
|
+ slots[i] = "";
|
|
|
|
|
+ }
|
|
|
|
|
+ return slots;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static String join(String[] slots) {
|
|
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
|
|
+ for (int i = 0; i < slots.length; i++) {
|
|
|
|
|
+ if (i > 0) {
|
|
|
|
|
+ sb.append('#');
|
|
|
|
|
+ }
|
|
|
|
|
+ sb.append(slots[i] == null ? "" : slots[i]);
|
|
|
|
|
+ }
|
|
|
|
|
+ return sb.toString();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static int secIndex(Date eventTime, Date windowStart) {
|
|
|
|
|
+ long ms = eventTime.getTime() - windowStart.getTime();
|
|
|
|
|
+ if (ms < 0) {
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ return (int) (ms / 1000L);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static Date floorTo10Minutes(Date date) {
|
|
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
|
|
+ cal.setTime(date);
|
|
|
|
|
+ cal.set(Calendar.SECOND, 0);
|
|
|
|
|
+ cal.set(Calendar.MILLISECOND, 0);
|
|
|
|
|
+ int minute = cal.get(Calendar.MINUTE);
|
|
|
|
|
+ cal.set(Calendar.MINUTE, minute - (minute % 10));
|
|
|
|
|
+ return cal.getTime();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static Date addMinutes(Date date, int minutes) {
|
|
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
|
|
+ cal.setTime(date);
|
|
|
|
|
+ cal.add(Calendar.MINUTE, minutes);
|
|
|
|
|
+ return cal.getTime();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static String format(Date date) {
|
|
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
|
|
+ cal.setTime(date);
|
|
|
|
|
+ return String.format("%04d-%02d-%02d %02d:%02d:%02d",
|
|
|
|
|
+ cal.get(Calendar.YEAR),
|
|
|
|
|
+ cal.get(Calendar.MONTH) + 1,
|
|
|
|
|
+ cal.get(Calendar.DAY_OF_MONTH),
|
|
|
|
|
+ cal.get(Calendar.HOUR_OF_DAY),
|
|
|
|
|
+ cal.get(Calendar.MINUTE),
|
|
|
|
|
+ cal.get(Calendar.SECOND));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|