From edade7cc3c3840a47cdc03bac4c663b953b82f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9A=B4=E7=82=B3=E6=9E=97?= <15237758276@163.com> Date: Tue, 15 Apr 2025 14:38:27 +0800 Subject: [PATCH] no message --- .../youchain/rest/GeneratorController.java | 4 +- .../youchain/rest/GeneratorController.class | Bin 6315 -> 6149 bytes youchain-system/pom.xml | 5 + .../youchain/Netty/JamodReadModbusTCP.java | 666 ++++++++++++++++++ .../com/youchain/Netty/JdbcQueryExample.java | 31 + .../com/youchain/basicdata/domain/Box.java | 11 + .../youchain/basicdata/domain/PointItem.java | 89 +++ .../repository/PointItemRepository.java | 28 + .../basicdata/rest/PointItemController.java | 87 +++ .../basicdata/service/PointItemService.java | 83 +++ .../basicdata/service/dto/BoxDto.java | 5 +- .../basicdata/service/dto/PointItemDto.java | 67 ++ .../service/dto/PointItemQueryCriteria.java | 45 ++ .../service/impl/PointItemServiceImpl.java | 115 +++ .../service/mapstruct/PointItemMapper.java | 32 + .../youchain/dropdown/DropdownController.java | 49 ++ .../com/youchain/jamod/domain/ModbusInfo.java | 123 ++++ .../repository/ModbusInfoRepository.java | 28 + .../jamod/rest/ModbusInfoController.java | 89 +++ .../jamod/service/ModbusInfoService.java | 84 +++ .../jamod/service/dto/ModbusInfoDto.java | 85 +++ .../service/dto/ModbusInfoQueryCriteria.java | 36 + .../service/impl/ModbusInfoServiceImpl.java | 121 ++++ .../service/mapstruct/ModbusInfoMapper.java | 32 + .../main/resources/config/application-dev.yml | 8 +- 25 files changed, 1914 insertions(+), 9 deletions(-) create mode 100644 youchain-system/src/main/java/com/youchain/Netty/JamodReadModbusTCP.java create mode 100644 youchain-system/src/main/java/com/youchain/Netty/JdbcQueryExample.java create mode 100644 youchain-system/src/main/java/com/youchain/basicdata/domain/PointItem.java create mode 100644 youchain-system/src/main/java/com/youchain/basicdata/repository/PointItemRepository.java create mode 100644 youchain-system/src/main/java/com/youchain/basicdata/rest/PointItemController.java create mode 100644 youchain-system/src/main/java/com/youchain/basicdata/service/PointItemService.java create mode 100644 youchain-system/src/main/java/com/youchain/basicdata/service/dto/PointItemDto.java create mode 100644 youchain-system/src/main/java/com/youchain/basicdata/service/dto/PointItemQueryCriteria.java create mode 100644 youchain-system/src/main/java/com/youchain/basicdata/service/impl/PointItemServiceImpl.java create mode 100644 youchain-system/src/main/java/com/youchain/basicdata/service/mapstruct/PointItemMapper.java create mode 100644 youchain-system/src/main/java/com/youchain/dropdown/DropdownController.java create mode 100644 youchain-system/src/main/java/com/youchain/jamod/domain/ModbusInfo.java create mode 100644 youchain-system/src/main/java/com/youchain/jamod/repository/ModbusInfoRepository.java create mode 100644 youchain-system/src/main/java/com/youchain/jamod/rest/ModbusInfoController.java create mode 100644 youchain-system/src/main/java/com/youchain/jamod/service/ModbusInfoService.java create mode 100644 youchain-system/src/main/java/com/youchain/jamod/service/dto/ModbusInfoDto.java create mode 100644 youchain-system/src/main/java/com/youchain/jamod/service/dto/ModbusInfoQueryCriteria.java create mode 100644 youchain-system/src/main/java/com/youchain/jamod/service/impl/ModbusInfoServiceImpl.java create mode 100644 youchain-system/src/main/java/com/youchain/jamod/service/mapstruct/ModbusInfoMapper.java diff --git a/youchain-generator/src/main/java/com/youchain/rest/GeneratorController.java b/youchain-generator/src/main/java/com/youchain/rest/GeneratorController.java index 0f025c6..179be28 100644 --- a/youchain-generator/src/main/java/com/youchain/rest/GeneratorController.java +++ b/youchain-generator/src/main/java/com/youchain/rest/GeneratorController.java @@ -88,9 +88,9 @@ public class GeneratorController { @ApiOperation("生成代码") @PostMapping(value = "/{tableName}/{type}") public ResponseEntity generatorCode(@PathVariable String tableName, @PathVariable Integer type, HttpServletRequest request, HttpServletResponse response){ - if(!generatorEnabled && type == 0){ + /*if(!generatorEnabled && type == 0){ throw new BadRequestException("此环境不允许生成代码,请选择预览或者下载查看!"); - } + }*/ switch (type){ // 生成代码 case 0: generatorService.generator(genConfigService.find(tableName), generatorService.getColumns(tableName)); diff --git a/youchain-generator/target/classes/com/youchain/rest/GeneratorController.class b/youchain-generator/target/classes/com/youchain/rest/GeneratorController.class index fe413b2543138632aae62c0ac51c158965888017..55cd9b504bf557a68b94ad14cd8fd4bc771cea69 100644 GIT binary patch delta 1681 zcmaKs=~q=%7{-6+-it@>Jp|miq9ihi1B0Q3jZ|1-gQO)&A!VW=YDOhyqh1=U$OenL zWsyY#8J01Kh?F!>pZX(Ou3Yt{FMVjWT0MIoxZe2CS!=)h-S4!Y^Xzx;BTM!zj{o$} z$x}cTKe{}a&Kw?!@Gy_0^C)}5IP47*rz6Z`JZ>CM81ZC;eLQ6xPaDTG#@1e-gN19d267z)^!dI z{qA;z;)N8syzTK0JudHhyvO?+vCnT|V;YV~ie$tnJOan=5xTx3yN*@7lSot<~c*j(Tk3bC0}Y=DM8n z80QO*FZs&jYrgULmhZa$^eXeCrw4mZcX$3ee(;wQeP=p4&-9F%jlMVHhoRn#tl-ce zS>28k>nh65S<&DSTv*ybkq9Xe_d%lQ2c<>PMw$bZFi(8Wmmbl)Kx1J$rMObcC|62F z*U!;;b&C`*O*UA{`I4U1bEssoR!cMjTwu%OO1sc6Q>9?lYr<*gB54sqg~2ncB2w5r`krBD85>-GRRfdRfMQfPDW6nD9DtX#Ix*w z@KkX%*C?_$sQSw_YTH?HR=xJDdY#nkxxoT2&8bQOzFd^mTHu8Ogb1AkK9`jic!ZhM zaif5*lHYLVTUN_bBTJg2z)83_O@(`N3VmxVTGt`dz(tknS!*%DID#fAE2Oz!cK&;+ki0U|C zjqX>y4tuRQSeN7{k9^k4VwkE;qN=4y{G_5XmfK{xU2zctf8)Ar_)E=IBZCNQ(&YEs z9jS!HP2X;$S($#rZJLUAGj|%o1U*}`>9j<}ai;Z2(YME+ENQc)S8J>AJe~SA*-bJ%Qqs&TEg^V%s8l&fpFnfFqr*V+b2mcTW6f<3NgD&kx^>wo-*sN6xd)cDru$BF6o4h!21tyZTCMFut*jgrTPC`komi`1= zl^C)VyQCEs~b!2YcNyevpIj6#$DlWE^A^ZaDmm&?CCI*CHEWXK{= d!M(Q9eHQ5){pU`t+mr3Ei~FVTwr|k`{{l9o=DYv^ delta 1807 zcmaJ>Ygd$26n@?r;Dwn(Tw+8(R4$4F1{#!hvy|xuX?a0OQ$__x?a%a2USi*H)|5>N)2faNM!*4h8NUKLQ7gk&9`2%N<^9p?qQa6#Y@KGktiz>RJlJp#SxlNtR2moT7X zP~d)a3k+dcU<8*1MlmL5jSF1CgpN*u&u~@XbDVQc2%GH-3po{Jq*C%dn=9i1FLalNM6>mHsu-QuY|H96Wob*B2p*l}<7&~#Our~dqO+cEFi zT2F0*x2k4xxZXQH?rG_qYOcRARxQ{5Mqmk+>iAaRJ6sd^9zO{Dh@S+0#xEKoJ$a z%Va_jeLyx=aufG;z`(`h+8oq8}T@a zKf$=v%BweslKDH@N#ZgQBIOS5*JjH3AlFK&B z$)=cSvrGW#*~CgdCL3p&Y*$ReSislF0zAo})Qb!>>`(-D8U%=4R@-JR)3w_c?UZLj zsu7ELJVgzpF7{atcI=`W{v4!dH$8>Sv%>T@bRCYrIKfA17yZWR+A~+4y?B}vjnh@+ zBj=>YU{{QNQXVR`ieGuI+^Lsf8^pXOM5PZRs0pE?h%ShnKZKYG>F8q45t{tTa~VTh zL)*rACR%LT2;xkT|A<0Nd`uRY`Os|ei#z8e#GBFM7yeIlMNGg576!6{L1d96G77Dr z4*^5CrH4zKA+Jd)dkStV0y_~$y;f7Lt#DvF_M(z6RRfCA$nCbH#OZgB+_SQ~eaDd+ zV88Dkxlw`xsy%KTL@Do4Ar}coP~3t=@rfZy|A+u}JohtDLOVz^dhyKMUX=NILH#RG zuA0Hg8lL48V+5ja^A3$s`LngIr + + net.wimpi + jamod + 1.2 + com.intelligt.modbus diff --git a/youchain-system/src/main/java/com/youchain/Netty/JamodReadModbusTCP.java b/youchain-system/src/main/java/com/youchain/Netty/JamodReadModbusTCP.java new file mode 100644 index 0000000..c3cbe5b --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/Netty/JamodReadModbusTCP.java @@ -0,0 +1,666 @@ +package com.youchain.Netty; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.youchain.annotation.AnonymousAccess; +import com.youchain.exception.BadRequestException; +import com.youchain.exception.handler.ApiResult; +import io.swagger.annotations.Api; +import lombok.Data; +import net.wimpi.modbus.ModbusException; +import net.wimpi.modbus.ModbusIOException; +import net.wimpi.modbus.io.ModbusTCPTransaction; +import net.wimpi.modbus.msg.ReadMultipleRegistersRequest; +import net.wimpi.modbus.msg.ReadMultipleRegistersResponse; +import net.wimpi.modbus.msg.WriteMultipleRegistersRequest; +import net.wimpi.modbus.msg.WriteMultipleRegistersResponse; +import net.wimpi.modbus.net.TCPMasterConnection; +import net.wimpi.modbus.procimg.Register; +import net.wimpi.modbus.procimg.SimpleRegister; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +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.net.InetAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +// 自定义类来存储每个 IP 的配置信息和读取结果 +@Data +class ModbusWrite { + Long id; + int modbusConfigId; + int address; + int values; + public static List convertToModbusWriteList(List> queryResult) { + List modbusWriteList = new ArrayList<>(); + for (Map row : queryResult) { + ModbusWrite modbusWrite = new ModbusWrite(); + // 从 Map 中获取 id 并转换为 Long 类型 + Object idObj = row.get("id"); + if (idObj != null) { + modbusWrite.setId(Long.valueOf(idObj.toString())); + } + // 从 Map 中获取 modbusInfoId 并转换为 int 类型 + Object modbusConfigIdObj = row.get("modbusInfoId"); + if (modbusConfigIdObj != null) { + modbusWrite.setModbusConfigId(Integer.parseInt(modbusConfigIdObj.toString())); + } + // 从 Map 中获取 address 并转换为 int 类型 + Object addressObj = row.get("address"); + if (addressObj != null) { + modbusWrite.setAddress(Integer.parseInt(addressObj.toString())); + } + // 从 Map 中获取 value 并转换为 int 类型 + Object valuesObj = row.get("value"); + if (valuesObj != null) { + modbusWrite.setValues(Integer.parseInt(valuesObj.toString())); + } + modbusWriteList.add(modbusWrite); + } + return modbusWriteList; + } +} +@Data +class ModbusConfig { + Long id; + // 报错原因 + public String description; + // 设备的 IP 地址 + String ip; + // 设备的端口号 + int port; + // 起始寄存器地址 + int startAddress; + // 要读取的寄存器数量 + int numberOfRegisters; + // 连接失败时的最大重试次数 + int maxRetries; + // 存储读取到的寄存器值 + List dataValues; + // 数据的状态,normal 表示正常,abnormal 表示异常,warning 表示警告,maintenance 表示维护中 + String dataStatus="normal"; + // 用于存储要写入的值 + List modbusWriteList; + // 新增连接状态标记 + boolean isConnected = false; + + /** + * 构造函数,用于初始化 Modbus 设备的配置信息。 + * + * @param ip 设备的 IP 地址 + * @param port 设备的端口号 + * @param startAddress 起始寄存器地址 + * @param numberOfRegisters 要读取的寄存器数量 + * @param maxRetries 最大重试次数 + */ + public ModbusConfig(Long id,String ip, int port, int startAddress, int numberOfRegisters, int maxRetries, List dataValues) { + this.id = id; + this.ip = ip; + this.port = port; + this.startAddress = startAddress; + this.numberOfRegisters = numberOfRegisters; + this.maxRetries = maxRetries; + // 初始化存储寄存器值的列表 + this.dataValues =dataValues; + } + + public ModbusConfig() { + + } + + /** + * 清空当前存储的结果,以便存储新的读取数据。 + */ + public void clearData() { + dataValues.clear(); + } + /* 处理jdbc查询结果*/ + public static List convertToModbusConfigList(List> queryResult) { + List configList = new ArrayList<>(); + for (Map row : queryResult) { + Long id = Long.valueOf(row.get("id")+""); + String ip = (String) row.get("ip"); + Object portObj = row.get("port"); + int port = 0; + if (portObj instanceof Number) { + port = ((Number) portObj).intValue(); + } + Object startAddressObj = row.get("startAddress"); + int startAddress = 0; + if (startAddressObj instanceof Number) { + startAddress = ((Number) startAddressObj).intValue(); + } + Object numberOfRegistersObj = row.get("numberOfRegisters"); + int numberOfRegisters = 0; + if (numberOfRegistersObj instanceof Number) { + numberOfRegisters = ((Number) numberOfRegistersObj).intValue(); + } + Object maxRetriesObj = row.get("maxRetries"); + int maxRetries = 0; + if (maxRetriesObj instanceof Number) { + maxRetries = ((Number) maxRetriesObj).intValue(); + } + // 处理 dataValues 字段 + Object dataValuesObj = row.get("dataValues"); + List dataValues = new ArrayList<>(); + if (dataValuesObj != null && dataValuesObj instanceof String) { + String dataValuesStr = (String) dataValuesObj; + if (!dataValuesStr.isEmpty()) { + try { + // 使用 fastjson 解析 JSON 数组 + JSONArray jsonArray = JSON.parseArray(dataValuesStr); + for (int i = 0; i < jsonArray.size(); i++) { + dataValues.add(jsonArray.getInteger(i)); + } + } catch (Exception e) { + System.err.println("无法解析 dataValues 中的值: " + dataValuesStr); + } + } + } + ModbusConfig config = new ModbusConfig(id,ip, port, startAddress, numberOfRegisters, maxRetries,dataValues); + configList.add(config); + } + return configList; + } +} + +/** + * JamodReadModbusTCP 类用于通过 Modbus TCP 协议从多个设备读取寄存器数据。 + * 支持为每个设备配置不同的端口、起始地址、数据长度和重试次数, + * 并将读取到的数据存储在对应的 ModbusConfig 对象中。 + */ +@RestController +@RequestMapping("/api/jamod") +@Api(tags = "jamod测试") +public class JamodReadModbusTCP { + // 存储每个 Modbus 设备的配置信息 + private static List CONFIG_LIST = new ArrayList<>(); + @Autowired + private JdbcQueryExample jdbcQueryExample; + + // Modbus 从站 ID + private static final int SLAVE_ID = 1; + + // 存储所有 Modbus TCP 连接的线程安全列表 + private static CopyOnWriteArrayList connections = new CopyOnWriteArrayList<>(); + // 用于定时执行读取任务的调度执行器 + private static ScheduledExecutorService executorService; + // 用于同步连接操作的锁对象 + private final Object connectionLock = new Object(); + /** + * 向 Modbus TCP 服务写入值 + * @param connection 要使用的 TCPMasterConnection 对象 + * @param config 设备的配置信息 + * @param slaveId Modbus 从站 ID + */ + private void writeRegisters(TCPMasterConnection connection, ModbusConfig config, int slaveId) { + synchronized (connectionLock) { + if (!connection.isConnected()) { + try { + connectWithRetries(connection, config); + } catch (Exception e) { + System.err.println("重新连接到 " + config.ip + " 失败 - " + translateExceptionMessage(e.getMessage())); + return; + } + } + } + List modbusWriteList = config.modbusWriteList; + for (ModbusWrite modbusWrite : modbusWriteList){ + try { + /* 写入值*/ + List writeValues = Collections.singletonList(modbusWrite.getValues()); + /* 写入地址*/ + int writeAddress = modbusWrite.getAddress(); + if (writeValues == null || writeValues.isEmpty()) { + return; + } + + SimpleRegister[] registers = new SimpleRegister[writeValues.size()]; + for (int i = 0; i < writeValues.size(); i++) { + registers[i] = new SimpleRegister(writeValues.get(i)); + } + + WriteMultipleRegistersRequest request = new WriteMultipleRegistersRequest(writeAddress, registers); + request.setUnitID(slaveId); + + ModbusTCPTransaction transaction = new ModbusTCPTransaction(connection); + transaction.setRequest(request); + transaction.execute(); + + WriteMultipleRegistersResponse response = (WriteMultipleRegistersResponse) transaction.getResponse(); + if (response != null) { + String updateSql=" UPDATE modbus_write_log " + +" SET " + +" `status` = 'success',failure_reason='', " + +" execution_time = ROUND( " + +" (UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(write_time)), " + +" 3 " + +" ) " + +" WHERE id = "+modbusWrite.id+";"; + jdbcQueryExample.executeUpdate(updateSql); + System.out.println("成功向 " + config.ip + " 写入值"); + } + } catch (ModbusIOException e) { + synchronized (connectionLock) { + System.err.println("Modbus IO 异常,针对 " + config.ip + " - " + translateExceptionMessage(e.getMessage())); + } + } catch (ModbusException e) { + String updateSql=" UPDATE modbus_write_log " + +" SET " + +" `status` = 'retrying',retry_count = retry_count + 1 " + +" WHERE id ="+modbusWrite.id+";"; + jdbcQueryExample.executeUpdate(updateSql); + System.err.println("Modbus 事务异常,针对 " + config.ip + " - " + translateExceptionMessage(e.getMessage())); + } + } + } + + /** + * 启动定时任务 + */ + @PostMapping("/start") + @AnonymousAccess + public void startTask() { + // 初始化配置列表 + String sql = "SELECT id 'id',device_name, device_ip 'ip', device_port 'port', " + + "start_address 'startAddress', data_length 'numberOfRegisters', " + + "max_retries 'maxRetries', data_values 'dataValues' " + + "FROM modbus_info WHERE enabled = ?"; + List> queryResult = jdbcQueryExample.sqlQuery(sql, 1); + CONFIG_LIST = ModbusConfig.convertToModbusConfigList(queryResult); + // 初始化连接 + initializeConnections(); + + // 注册关闭钩子 + Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown)); + + // 启动定时任务 + executorService = Executors.newScheduledThreadPool(1); + executorService.scheduleAtFixedRate(() -> { + System.out.println("开始读取数据..."); + for (ModbusConfig config : CONFIG_LIST) { + TCPMasterConnection connection = getConnectionByIp(config.ip); + if (connection != null) { + config.clearData(); + ModbusConfig updatedConfig = readRegisters(connection, config, SLAVE_ID); + if (updatedConfig != null) { + // 处理数据更新逻辑(原有读取后的处理逻辑) + if ("warning".equals(updatedConfig.dataStatus)) { + String updateSql = "update modbus_info set data_status='warning',description='" + + updatedConfig.description + "',last_read_time=NOW() where id=" + + updatedConfig.id + ";"; + jdbcQueryExample.executeUpdate(updateSql); + } else if ("normal".equals(updatedConfig.dataStatus)) { + String updateSql = "update modbus_info set data_status='normal',data_values='" + + updatedConfig.dataValues + "',description='',last_read_time=NOW() where id=" + + updatedConfig.id + ";"; + jdbcQueryExample.executeUpdate(updateSql); + + // 读取成功后处理写入逻辑 + String sqlWrite = "select id,modbus_info_id 'modbusInfoId',register_address 'address',data_values 'value' " + + "from modbus_write_log where `status` in ('unprocessed','retrying') and modbus_info_id=?"; + List> queryWrite = jdbcQueryExample.sqlQuery(sqlWrite, updatedConfig.id); + List modbusWriteList = ModbusWrite.convertToModbusWriteList(queryWrite); + config.modbusWriteList = modbusWriteList; + writeRegisters(connection, config, SLAVE_ID); + } + } + } + } + }, 0, 1, TimeUnit.SECONDS); + } + + /** + * 关闭定时任务 + */ + @PostMapping("/stop") + @AnonymousAccess + public void stopTask() { + if (executorService != null && !executorService.isShutdown()) { + executorService.shutdown(); + try { + if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) { + executorService.shutdownNow(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + System.err.println("等待定时任务执行器终止时被中断。"); + } + } + + // 关闭所有连接 + for (TCPMasterConnection connection : connections) { + if (connection.isConnected()) { + try { + connection.close(); + System.out.println("已关闭 " + connection.getAddress() + " 的连接。"); + } catch (Exception e) { + System.err.println("关闭 " + connection.getAddress() + " 的连接时出错: " + translateExceptionMessage(e.getMessage())); + } + } + } + // 清空配置信息 + CONFIG_LIST.clear(); + } + + /** + * 根据 IP 地址从连接列表中查找对应的 TCPMasterConnection 对象。 + * + * @param ipAddress 要查找的 IP 地址 + * @return 对应的 TCPMasterConnection 对象,如果未找到则返回 null + */ + private static TCPMasterConnection getConnectionByIp(String ipAddress) { + for (TCPMasterConnection connection : connections) { + if (connection.getAddress().getHostAddress().equals(ipAddress)) { + return connection; + } + } + return null; + } + + /** + * 初始化与所有配置的 Modbus 设备的连接。 + * 遍历 CONFIG_LIST 中的每个设备配置信息,创建连接并尝试建立连接。 + */ + private void initializeConnections() { + for (ModbusConfig config : CONFIG_LIST) { + try { + InetAddress inetAddress = InetAddress.getByName(config.ip); + TCPMasterConnection connection = new TCPMasterConnection(inetAddress); + connection.setPort(config.port); + + // 尝试连接,成功则标记状态并添加连接 + connectWithRetries(connection, config); + + config.isConnected = true; + connections.add(connection); + } catch (Exception e) { + // 初始化连接失败,标记状态为未连接 + config.isConnected = false; + + String des="初始化连接失败,后续将重试 - IP: " + config.ip + ",错误: " + translateExceptionMessage(e.getMessage()); + System.err.println(des); + } + } + } + + /** + * 尝试连接到 Modbus 设备,若连接失败则进行重试,最多重试 maxRetries 次。 + * + * @param connection 要连接的 TCPMasterConnection 对象 + * @param config 设备的配置信息 + * @throws Exception 如果尝试 maxRetries 次后仍无法连接 + */ + private void connectWithRetries(TCPMasterConnection connection, ModbusConfig config) throws Exception { + int retries = 0; + while (retries < config.maxRetries) { + try { + // 尝试建立连接 + connection.connect(); + System.out.println("已连接到 " + config.ip); + /*连接成功修改状态*/ + String updateSql = "update modbus_info set is_connected=0 where id=" + + config.id + ";"; + jdbcQueryExample.executeUpdate(updateSql); + return; + } catch (Exception e) { + retries++; + System.err.println("第 " + retries + " 次尝试连接到 " + config.ip + " 失败: " + translateExceptionMessage(e.getMessage())); + if (retries == config.maxRetries) { + // 达到最大重试次数,抛出异常 + String updateSql = "update modbus_info set is_connected=1,data_values='" + + "',description='"+"尝试 " + config.maxRetries + " 次后仍无法连接到 " + config.ip + "。"+e.getMessage()+"' where id=" + + config.id + ";"; + jdbcQueryExample.executeUpdate(updateSql); + throw new Exception("尝试 " + config.maxRetries + " 次后仍无法连接到 " + config.ip + "。"); + } + try { + // 重试前暂停 1 秒 + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + System.err.println("连接重试期间睡眠被中断。"); + throw new Exception("连接重试被中断。"); + } + } + } + } + + /** + * 从指定的 Modbus 设备读取寄存器数据。 + * 如果连接断开,会尝试重新连接。 + * 读取到的数据会存储在对应的 ModbusConfig 对象中。 + * + * @param connection 要使用的 TCPMasterConnection 对象 + * @param config 设备的配置信息 + * @param slaveId Modbus 从站 ID + * @return 读取到的寄存器数据列表,如果读取失败则返回 null + */ + private ModbusConfig readRegisters(TCPMasterConnection connection, ModbusConfig config, int slaveId) { + // 同步操作,确保同一时间只有一个线程可以检查和修改连接状态 + synchronized (connectionLock) { + if (!connection.isConnected()) { + try { + // 尝试重新连接到设备 + connectWithRetries(connection, config); + } catch (Exception e) { + System.err.println("重新连接到 " + config.ip + " 失败 - " + translateExceptionMessage(e.getMessage())); + return null; + } + } + } + + try { + // 创建一个读取多个寄存器的请求 + ReadMultipleRegistersRequest request = new ReadMultipleRegistersRequest(config.startAddress, config.numberOfRegisters); + // 设置从站 ID + request.setUnitID(slaveId); + + // 创建一个 Modbus TCP 事务 + ModbusTCPTransaction transaction = new ModbusTCPTransaction(connection); + // 设置请求到事务中 + transaction.setRequest(request); + // 执行事务 + transaction.execute(); + + // 获取事务的响应 + ReadMultipleRegistersResponse response = (ReadMultipleRegistersResponse) transaction.getResponse(); + if (response != null) { + // 获取响应中的寄存器数组 + Register[] registers = response.getRegisters(); + // 用于临时存储读取到的寄存器值 + List values = new ArrayList<>(); + for (Register register : registers) { + // 将每个寄存器的值添加到临时列表中 + values.add(register.getValue()); + } + // 更新配置中的数据 + config.dataValues = values; + config.dataStatus="normal";// 数据正常 + } + } catch (ModbusIOException e) { + // 同步操作,确保同一时间只有一个线程可以处理连接异常 + synchronized (connectionLock) { + System.err.println("Modbus IO 异常,针对 " + config.ip + " - " + translateExceptionMessage(e.getMessage())); + try { + // 关闭当前连接 + connection.close(); + // 尝试重新连接到设备 + connectWithRetries(connection, config); + } catch (Exception re) { + System.err.println("重新连接到 " + config.ip + " 失败 - " + translateExceptionMessage(re.getMessage())); + } + } + } catch (ModbusException e) { + config.dataStatus="warning";// 数据报错 + config.description="Modbus 事务异常,针对 " + config.ip + " - " + translateExceptionMessage(e.getMessage()); +// System.err.println("Modbus 事务异常,针对 " + config.ip + " - " + translateExceptionMessage(e.getMessage())); + } + /* 修改表值*/ + + return config; + } + /** + * 程序关闭时的清理操作。 + * 关闭定时任务执行器和所有 Modbus TCP 连接。 + */ + private void shutdown() { + if (executorService != null && !executorService.isShutdown()) { + // 发起关闭定时任务执行器的请求 + executorService.shutdown(); + try { + // 等待执行器在 5 秒内正常关闭 + if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) { + // 若 5 秒内未关闭,则强制关闭 + executorService.shutdownNow(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + System.err.println("等待定时任务执行器终止时被中断。"); + } + } + + // 关闭所有连接 + for (TCPMasterConnection connection : connections) { + if (connection.isConnected()) { + try { + // 关闭连接 + connection.close(); + System.out.println("已关闭 " + connection.getAddress() + " 的连接。"); + } catch (Exception e) { + System.err.println("关闭 " + connection.getAddress() + " 的连接时出错: " + translateExceptionMessage(e.getMessage())); + } + } + } + } + + /** + * 将异常信息翻译成中文,目前只是简单返回原信息。 + * 可根据实际情况添加更多翻译规则。 + * + * @param message 原始异常信息 + * @return 翻译后的异常信息 + */ + private String translateExceptionMessage(String message) { + return message; + } + + /** + * 获取指定 IP 地址对应的设备的最新读取数据。 + * + * @param ipAddress 要获取数据的设备的 IP 地址 + * @return 存储最新读取数据的列表,如果 IP 地址对应的配置不存在则返回 null + */ + public List getLatestData(String ipAddress) { + // 遍历配置列表,查找对应 IP 的配置信息 + for (ModbusConfig config : CONFIG_LIST) { + if (config.ip.equals(ipAddress)) { + // 返回配置中存储的数据的副本 + return new ArrayList<>(config.dataValues); + } + } + return null; + } + // 添加新配置的方法 + @PostMapping("/addConFig") + @AnonymousAccess + public synchronized ResponseEntity addModbusConfig(@RequestBody Long id) { + String sql = "SELECT id 'id',device_name, device_ip 'ip', device_port 'port', " + + "start_address 'startAddress', data_length 'numberOfRegisters', " + + "max_retries 'maxRetries', data_values 'dataValues' " + + "FROM modbus_info WHERE id=?"; + List> queryResult = jdbcQueryExample.sqlQuery(sql, id); + if (queryResult.size()>0){ + ModbusConfig newConfig = ModbusConfig.convertToModbusConfigList(queryResult).get(0); + // 检查是否已存在相同配置(示例:根据IP和端口判断) + if (CONFIG_LIST.stream().anyMatch(c -> + c.getIp().equals(newConfig.getIp()) && + c.getPort() == newConfig.getPort())) { + System.err.println("配置已存在,跳过添加: " + newConfig.getIp() + ":" + newConfig.getPort()); +// return; + }else { + // 添加新配置 + CONFIG_LIST.add(newConfig); + } + if (getConnectionByIp(newConfig.ip)==null){ + // 初始化连接 + initializeConnection(newConfig); + } + }else {throw new BadRequestException("未查询到配置信息");} + ApiResult apiResult=new ApiResult(); + return new ResponseEntity<>(apiResult.success("添加成功"), HttpStatus.OK); + } + // 初始化单个配置的连接 + private void initializeConnection(ModbusConfig config) { + try { + // 创建连接对象 + TCPMasterConnection connection = new TCPMasterConnection( + InetAddress.getByName(config.getIp()) + ); + connection.setPort(config.getPort()); + + // 尝试连接 + connectWithRetries(connection, config); + + // 保存连接 + connections.add(connection); + config.setConnected(true); + System.out.println("成功连接新设备: " + config.getIp() + ":" + config.getPort()); + } catch (Exception e) { + config.setConnected(false); + throw new RuntimeException("异常: " + config.getIp() + ":" + config.getPort(), e); + } + } + + /** + * 添加写入操作 + * @param ip IP + * @param address 地址 + * @param values 数据 + */ + public synchronized void addWrite(String ip, int address, int values) { + String sql = "SELECT id " + + "FROM modbus_info WHERE device_ip= '"+ip+"'"; + List> modbusInfos = jdbcQueryExample.sqlQuery(sql); + if (modbusInfos.size()>0){ + Long modbus_info_id = Long.valueOf(modbusInfos.get(0).get("id").toString()); + // 如果已有任务,直接跳过 + String sqlWrite = "select id,modbus_info_id 'modbusInfoId',register_address 'address',data_values 'value' " + + "from modbus_write_log where `status` in ('unprocessed','retrying') " + + "and modbus_info_id=? " + + "and register_address=? " + + "and data_values=?"; + List> queryWrite = jdbcQueryExample.sqlQuery(sqlWrite, modbus_info_id,address,values); + if (queryWrite.size()<1) { + String insertSql = "INSERT INTO `wms`.`modbus_write_log` ( `modbus_info_id`, `register_address`, `data_values`, `write_time`, `status`,`failure_reason`) " + + "VALUES ( ?,? , ?, NOW(), 'unprocessed', '');"; + // 添加写入操作 + jdbcQueryExample.executeUpdate(insertSql, modbus_info_id, address, values); + } + } + } + public String getRead(String ip,int address) { + for (ModbusConfig config : CONFIG_LIST) { + if (config.getIp().equals(ip)) { + if (config.getDataValues() != null && config.getDataValues().size() >= (address-1)) { + return config.getDataValues().get(address)+""; // 索引从0开始 + } else { + System.err.println("dataValues 集合中没有足够的数据。"); + return "dataValues 集合中没有足够的数据。"; + } + } + } + System.err.println("未找到 IP 地址为 " + ip + " 的 ModbusConfig 配置。"); + return "未找到 IP 地址为 " + ip + " 的 ModbusConfig 配置。"; + } +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/Netty/JdbcQueryExample.java b/youchain-system/src/main/java/com/youchain/Netty/JdbcQueryExample.java new file mode 100644 index 0000000..6b4b628 --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/Netty/JdbcQueryExample.java @@ -0,0 +1,31 @@ +package com.youchain.Netty; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Component +@Service +public class JdbcQueryExample { + private final JdbcTemplate jdbcTemplate; + + @Autowired + public JdbcQueryExample(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List> sqlQuery(String sql, Object... params) { + return jdbcTemplate.queryForList(sql, params); + } + public List> sqlQuery(String sql) { + return jdbcTemplate.queryForList(sql); + } + public int executeUpdate(String sql, Object... params) { + return jdbcTemplate.update(sql, params); + } + +} diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/Box.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/Box.java index 877ebba..f6b2a6a 100644 --- a/youchain-system/src/main/java/com/youchain/basicdata/domain/Box.java +++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/Box.java @@ -16,6 +16,7 @@ package com.youchain.basicdata.domain; import com.youchain.base.BaseEntity; +import com.youchain.jamod.domain.ModbusInfo; import com.youchain.modules.system.domain.Dept; import lombok.Data; import cn.hutool.core.bean.BeanUtil; @@ -84,6 +85,16 @@ public class Box extends BaseEntity implements Serializable { @Column(name = "`sort`") @ApiModelProperty(value = "排序") private int sort=0; + @Column(name = "`work_code`") + @ApiModelProperty(value = "业务代码") + private String workCode; + @Column(name = "`work_type`") + @ApiModelProperty(value = "业务类型") + private String workType; + @OneToOne + @JoinColumn(name = "`modbus_id`") + @ApiModelProperty(value = "关联modbus") + private ModbusInfo modbusInfo; @Column(name = "`IP`") @ApiModelProperty(value = "IP") diff --git a/youchain-system/src/main/java/com/youchain/basicdata/domain/PointItem.java b/youchain-system/src/main/java/com/youchain/basicdata/domain/PointItem.java new file mode 100644 index 0000000..f59e35e --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/basicdata/domain/PointItem.java @@ -0,0 +1,89 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.basicdata.domain; + +import com.youchain.base.BaseEntity; +import com.youchain.modules.system.domain.Dept; +import lombok.Data; +import cn.hutool.core.bean.BeanUtil; +import io.swagger.annotations.ApiModelProperty; +import cn.hutool.core.bean.copier.CopyOptions; +import javax.persistence.*; +import javax.validation.constraints.*; +import java.sql.Timestamp; +import java.io.Serializable; + +/** +* @website https://eladmin.vip +* @description / +* @author admin +* @date 2025-04-11 +**/ +@Entity +@Data +@Table(name="base_point_item") +public class PointItem extends BaseEntity implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "`id`") + @ApiModelProperty(value = "ID") + private Long id; + + @Column(name = "`code`") + @ApiModelProperty(value = "编号") + private String code; + + @Column(name = "`name`") + @ApiModelProperty(value = "名称") + private String name; + + @OneToOne + @JoinColumn(name = "`item_id`",nullable = false) + @ApiModelProperty(value = "物料") + private Item item; + @OneToOne + @JoinColumn(name = "`point_id`",nullable = false) + @ApiModelProperty(value = "点位") + private Point point; + @Column(name = "`enabled`") + @ApiModelProperty(value = "状态:1启用、0禁用") + private Boolean enabled=true; + + @Column(name = "`order_Number`") + @ApiModelProperty(value = "工单号") + private String orderNumber; + + @Column(name = "`create_by`") + @ApiModelProperty(value = "创建人") + private String createBy; + + @Column(name = "`update_by`") + @ApiModelProperty(value = "修改人") + private String updateBy; + + @Column(name = "`create_time`") + @ApiModelProperty(value = "创建时间") + private Timestamp createTime; + + @Column(name = "`update_time`") + @ApiModelProperty(value = "修改时间") + private Timestamp updateTime; + + public void copy(PointItem source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } +} diff --git a/youchain-system/src/main/java/com/youchain/basicdata/repository/PointItemRepository.java b/youchain-system/src/main/java/com/youchain/basicdata/repository/PointItemRepository.java new file mode 100644 index 0000000..3a35583 --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/basicdata/repository/PointItemRepository.java @@ -0,0 +1,28 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.basicdata.repository; + +import com.youchain.basicdata.domain.PointItem; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @website https://eladmin.vip +* @author admin +* @date 2025-04-11 +**/ +public interface PointItemRepository extends JpaRepository, JpaSpecificationExecutor { +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/basicdata/rest/PointItemController.java b/youchain-system/src/main/java/com/youchain/basicdata/rest/PointItemController.java new file mode 100644 index 0000000..f6df000 --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/basicdata/rest/PointItemController.java @@ -0,0 +1,87 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.basicdata.rest; + +import com.youchain.annotation.Log; +import com.youchain.basicdata.domain.PointItem; +import com.youchain.basicdata.service.PointItemService; +import com.youchain.basicdata.service.dto.PointItemQueryCriteria; +import org.springframework.data.domain.Pageable; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import io.swagger.annotations.*; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; + +/** +* @website https://eladmin.vip +* @author admin +* @date 2025-04-11 +**/ +@RestController +@RequiredArgsConstructor +@Api(tags = "pointItem管理") +@RequestMapping("/api/pointItem") +public class PointItemController { + + private final PointItemService pointItemService; + + @Log("导出数据") + @ApiOperation("导出数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('pointItem:list')") + public void exportPointItem(HttpServletResponse response, PointItemQueryCriteria criteria) throws IOException { + pointItemService.download(pointItemService.queryAll(criteria), response); + } + + @GetMapping + @Log("查询pointItem") + @ApiOperation("查询pointItem") + @PreAuthorize("@el.check('pointItem:list')") + public ResponseEntity queryPointItem(PointItemQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(pointItemService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @PostMapping + @Log("新增pointItem") + @ApiOperation("新增pointItem") + @PreAuthorize("@el.check('pointItem:add')") + public ResponseEntity createPointItem(@Validated @RequestBody PointItem resources){ + return new ResponseEntity<>(pointItemService.create(resources),HttpStatus.CREATED); + } + + @PutMapping + @Log("修改pointItem") + @ApiOperation("修改pointItem") + @PreAuthorize("@el.check('pointItem:edit')") + public ResponseEntity updatePointItem(@Validated @RequestBody PointItem resources){ + pointItemService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @DeleteMapping + @Log("删除pointItem") + @ApiOperation("删除pointItem") + @PreAuthorize("@el.check('pointItem:del')") + public ResponseEntity deletePointItem(@RequestBody Long[] ids) { + pointItemService.deleteAll(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/basicdata/service/PointItemService.java b/youchain-system/src/main/java/com/youchain/basicdata/service/PointItemService.java new file mode 100644 index 0000000..2f243ed --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/basicdata/service/PointItemService.java @@ -0,0 +1,83 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.basicdata.service; + +import com.youchain.basicdata.domain.PointItem; +import com.youchain.basicdata.service.dto.PointItemDto; +import com.youchain.basicdata.service.dto.PointItemQueryCriteria; +import org.springframework.data.domain.Pageable; +import java.util.Map; +import java.util.List; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; + +/** +* @website https://eladmin.vip +* @description 服务接口 +* @author admin +* @date 2025-04-11 +**/ +public interface PointItemService { + + /** + * 查询数据分页 + * @param criteria 条件 + * @param pageable 分页参数 + * @return Map + */ + Map queryAll(PointItemQueryCriteria criteria, Pageable pageable); + + /** + * 查询所有数据不分页 + * @param criteria 条件参数 + * @return List + */ + List queryAll(PointItemQueryCriteria criteria); + + /** + * 根据ID查询 + * @param id ID + * @return PointItemDto + */ + PointItemDto findById(Long id); + + /** + * 创建 + * @param resources / + * @return PointItemDto + */ + PointItemDto create(PointItem resources); + + /** + * 编辑 + * @param resources / + */ + void update(PointItem resources); + + /** + * 多选删除 + * @param ids / + */ + void deleteAll(Long[] ids); + + /** + * 导出数据 + * @param all 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List all, HttpServletResponse response) throws IOException; +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/basicdata/service/dto/BoxDto.java b/youchain-system/src/main/java/com/youchain/basicdata/service/dto/BoxDto.java index 591ca7b..e881d6e 100644 --- a/youchain-system/src/main/java/com/youchain/basicdata/service/dto/BoxDto.java +++ b/youchain-system/src/main/java/com/youchain/basicdata/service/dto/BoxDto.java @@ -15,6 +15,7 @@ */ package com.youchain.basicdata.service.dto; +import com.youchain.jamod.domain.ModbusInfo; import com.youchain.modules.system.domain.Dept; import lombok.Data; import java.sql.Timestamp; @@ -53,7 +54,9 @@ public class BoxDto implements Serializable { /** 排序*/ private String sort; - + private String workCode; + private String workType; + private ModbusInfo modbusInfo; /** 仓库*/ private Dept dept; diff --git a/youchain-system/src/main/java/com/youchain/basicdata/service/dto/PointItemDto.java b/youchain-system/src/main/java/com/youchain/basicdata/service/dto/PointItemDto.java new file mode 100644 index 0000000..b347e27 --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/basicdata/service/dto/PointItemDto.java @@ -0,0 +1,67 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.basicdata.service.dto; + +import com.youchain.basicdata.domain.Item; +import com.youchain.basicdata.domain.Point; +import com.youchain.modules.system.domain.Dept; +import lombok.Data; +import java.sql.Timestamp; +import java.io.Serializable; + +/** +* @website https://eladmin.vip +* @description / +* @author admin +* @date 2025-04-11 +**/ +@Data +public class PointItemDto implements Serializable { + + /** ID */ + private Long id; + + /** 编号 */ + private String code; + + /** 名称 */ + private String name; + + /** 物料ID */ + private Item item; + + /** 点位ID */ + private Point point; + + + /** 状态:1启用、0禁用 */ + private Boolean enabled=true; + + /** 工单号 */ + private String orderNumber; + + /** 创建人 */ + private String createBy; + + /** 修改人 */ + private String updateBy; + + /** 创建时间 */ + private Timestamp createTime; + + /** 修改时间 */ + private Timestamp updateTime; +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/basicdata/service/dto/PointItemQueryCriteria.java b/youchain-system/src/main/java/com/youchain/basicdata/service/dto/PointItemQueryCriteria.java new file mode 100644 index 0000000..ba04f73 --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/basicdata/service/dto/PointItemQueryCriteria.java @@ -0,0 +1,45 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.basicdata.service.dto; + +import lombok.Data; +import java.util.List; +import com.youchain.annotation.Query; + +/** +* @website https://eladmin.vip +* @author admin +* @date 2025-04-11 +**/ +@Data +public class PointItemQueryCriteria{ + + /** 模糊 */ + @Query(type = Query.Type.INNER_LIKE) + private String code; + + /** 模糊 */ + @Query(type = Query.Type.INNER_LIKE) + private Long itemId; + + /** 模糊 */ + @Query(type = Query.Type.INNER_LIKE) + private Long pointId; + + /** 精确 */ + @Query + private Boolean enabled; +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/basicdata/service/impl/PointItemServiceImpl.java b/youchain-system/src/main/java/com/youchain/basicdata/service/impl/PointItemServiceImpl.java new file mode 100644 index 0000000..13f0b1e --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/basicdata/service/impl/PointItemServiceImpl.java @@ -0,0 +1,115 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.basicdata.service.impl; + +import com.youchain.basicdata.domain.PointItem; +import com.youchain.utils.FileUtil; +import com.youchain.utils.PageUtil; +import com.youchain.utils.QueryHelp; +import com.youchain.utils.ValidationUtil; +import lombok.RequiredArgsConstructor; +import com.youchain.basicdata.repository.PointItemRepository; +import com.youchain.basicdata.service.PointItemService; +import com.youchain.basicdata.service.dto.PointItemDto; +import com.youchain.basicdata.service.dto.PointItemQueryCriteria; +import com.youchain.basicdata.service.mapstruct.PointItemMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import java.util.List; +import java.util.Map; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.LinkedHashMap; + +/** +* @website https://eladmin.vip +* @description 服务实现 +* @author admin +* @date 2025-04-11 +**/ +@Service +@RequiredArgsConstructor +public class PointItemServiceImpl implements PointItemService { + + private final PointItemRepository pointItemRepository; + private final PointItemMapper pointItemMapper; + + @Override + public Map queryAll(PointItemQueryCriteria criteria, Pageable pageable){ + Page page = pointItemRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(pointItemMapper::toDto)); + } + + @Override + public List queryAll(PointItemQueryCriteria criteria){ + return pointItemMapper.toDto(pointItemRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder))); + } + + @Override + @Transactional + public PointItemDto findById(Long id) { + PointItem pointItem = pointItemRepository.findById(id).orElseGet(PointItem::new); + ValidationUtil.isNull(pointItem.getId(),"PointItem","id",id); + return pointItemMapper.toDto(pointItem); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public PointItemDto create(PointItem resources) { + resources.setCode(resources.getPoint().getCode()+":"+resources.getItem().getCode()); + resources.setEnabled(true); + return pointItemMapper.toDto(pointItemRepository.save(resources)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(PointItem resources) { + PointItem pointItem = pointItemRepository.findById(resources.getId()).orElseGet(PointItem::new); + ValidationUtil.isNull( pointItem.getId(),"PointItem","id",resources.getId()); + pointItem.copy(resources); + pointItemRepository.save(pointItem); + } + + @Override + public void deleteAll(Long[] ids) { + for (Long id : ids) { + pointItemRepository.deleteById(id); + } + } + + @Override + public void download(List all, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (PointItemDto pointItem : all) { + Map map = new LinkedHashMap<>(); + map.put("编号", pointItem.getCode()); + map.put("名称", pointItem.getName()); + map.put("物料ID", pointItem.getItem().getCode()); + map.put("点位ID", pointItem.getPoint().getCode()); + map.put("状态:1启用、0禁用", pointItem.getEnabled()); + map.put("工单号", pointItem.getOrderNumber()); + map.put("创建人", pointItem.getCreateBy()); + map.put("修改人", pointItem.getUpdateBy()); + map.put("创建时间", pointItem.getCreateTime()); + map.put("修改时间", pointItem.getUpdateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/basicdata/service/mapstruct/PointItemMapper.java b/youchain-system/src/main/java/com/youchain/basicdata/service/mapstruct/PointItemMapper.java new file mode 100644 index 0000000..7b485eb --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/basicdata/service/mapstruct/PointItemMapper.java @@ -0,0 +1,32 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.basicdata.service.mapstruct; + +import com.youchain.base.BaseMapper; +import com.youchain.basicdata.domain.PointItem; +import com.youchain.basicdata.service.dto.PointItemDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @website https://eladmin.vip +* @author admin +* @date 2025-04-11 +**/ +@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface PointItemMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/dropdown/DropdownController.java b/youchain-system/src/main/java/com/youchain/dropdown/DropdownController.java new file mode 100644 index 0000000..8a28f7b --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/dropdown/DropdownController.java @@ -0,0 +1,49 @@ +package com.youchain.dropdown; + +import com.youchain.annotation.AnonymousAccess; +import com.youchain.annotation.Log; +import com.youchain.basicdata.domain.Item; +import com.youchain.basicdata.domain.Point; +import com.youchain.basicdata.repository.ItemRepository; +import com.youchain.basicdata.repository.PointRepository; +import com.youchain.exception.handler.ApiResult; +import com.youchain.jamod.domain.ModbusInfo; +import com.youchain.jamod.service.ModbusInfoService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +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.List; + +@RestController +@RequiredArgsConstructor +@Api(tags = "下拉框加载") +@RequestMapping("/api/dropdown") +public class DropdownController { + private final PointRepository pointRepository; + private final ItemRepository itemRepository; + @PostMapping("/pointData") + @ApiOperation("全部点位") + @AnonymousAccess + public ResponseEntity pointData(){ + List pointList=pointRepository.findAll(); + ApiResult apiResult=ApiResult.fail(200,"成功",pointList); + return new ResponseEntity<>(apiResult,apiResult.getStatus()); + } + @PostMapping("/itemData") + @ApiOperation("全部物料") + @AnonymousAccess + public ResponseEntity itemData(){ + List itemList=itemRepository.findAll(); + ApiResult apiResult=ApiResult.fail(200,"成功",itemList); + return new ResponseEntity<>(apiResult,apiResult.getStatus()); + } +} diff --git a/youchain-system/src/main/java/com/youchain/jamod/domain/ModbusInfo.java b/youchain-system/src/main/java/com/youchain/jamod/domain/ModbusInfo.java new file mode 100644 index 0000000..b94567a --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/jamod/domain/ModbusInfo.java @@ -0,0 +1,123 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.jamod.domain; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.sql.Timestamp; + +/** +* @website https://eladmin.vip +* @description / +* @author huojin +* @date 2025-03-21 +**/ +@Entity +@Data +@Table(name="modbus_info") +public class ModbusInfo implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "`id`") + @ApiModelProperty(value = "自增主键,唯一标识每条记录") + private Integer id; + + @Column(name = "`device_name`",nullable = false) + @NotBlank + @ApiModelProperty(value = "Modbus 设备的名称,用于直观识别设备") + private String deviceName; + + @Column(name = "`device_ip`",nullable = false) + @NotBlank + @ApiModelProperty(value = "Modbus 设备的 IP 地址") + private String deviceIp; + + @Column(name = "`device_port`",nullable = false) + @NotNull + @ApiModelProperty(value = "Modbus 设备的端口号") + private Integer devicePort; + + @Column(name = "`device_description`") + @ApiModelProperty(value = "Modbus 设备的详细描述信息,如设备用途、型号等") + private String deviceDescription; + + @Column(name = "`data_type`",nullable = false) + @NotNull + @ApiModelProperty(value = "Modbus 数据的类型") + private String dataType; + + @Column(name = "`start_address`",nullable = false) + @NotNull + @ApiModelProperty(value = "批量读取数据的起始地址") + private Integer startAddress; + + @Column(name = "`data_length`",nullable = false) + @NotNull + @ApiModelProperty(value = "批量读取的数据长度") + private Integer dataLength; + + @Column(name = "`data_values`") + @ApiModelProperty(value = "批量读取的数据值集合,以特定格式存储,如逗号分隔的字符串") + private String dataValues; + + @Column(name = "`last_read_time`") + @ApiModelProperty(value = "最后一次读取该数据的时间") + private Timestamp lastReadTime; + + @Column(name = "`last_modify_time`") + @ApiModelProperty(value = "最后一次修改该数据的时间") + private Timestamp lastModifyTime; + + @Column(name = "`data_version`") + @ApiModelProperty(value = "数据的版本号,每次数据修改时版本号递增,用于数据追溯") + private Integer dataVersion; + + @Column(name = "`data_status`") + @ApiModelProperty(value = "数据的状态,normal 表示正常,abnormal 表示异常,warning 表示警告,maintenance 表示维护中") + private String dataStatus; + + @Column(name = "`alarm_status`") + @ApiModelProperty(value = "是否触发报警,TRUE 表示触发,FALSE 表示未触发") + private Integer alarmStatus; + + @Column(name = "`is_connected`") + @ApiModelProperty(value = "记录设备连接状态,TRUE 表示连接成功,FALSE 表示连接失败") + private Integer isConnected; + + @Column(name = "`max_retries`") + @ApiModelProperty(value = "异常重试次数") + private Integer maxRetries; + + @Column(name = "`enabled`") + @ApiModelProperty(value = "状态:1启用、0禁用") + private Boolean enabled; + + @Column(name = "`description`") + @ApiModelProperty(value = "报错原因") + private String description; + + public void copy(ModbusInfo source){ + BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true)); + } +} diff --git a/youchain-system/src/main/java/com/youchain/jamod/repository/ModbusInfoRepository.java b/youchain-system/src/main/java/com/youchain/jamod/repository/ModbusInfoRepository.java new file mode 100644 index 0000000..65a10c3 --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/jamod/repository/ModbusInfoRepository.java @@ -0,0 +1,28 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.jamod.repository; + +import com.youchain.jamod.domain.ModbusInfo; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** +* @website https://eladmin.vip +* @author huojin +* @date 2025-03-21 +**/ +public interface ModbusInfoRepository extends JpaRepository, JpaSpecificationExecutor { +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/jamod/rest/ModbusInfoController.java b/youchain-system/src/main/java/com/youchain/jamod/rest/ModbusInfoController.java new file mode 100644 index 0000000..ba24f8b --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/jamod/rest/ModbusInfoController.java @@ -0,0 +1,89 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.jamod.rest; + +import com.youchain.annotation.Log; +import com.youchain.jamod.domain.ModbusInfo; +import com.youchain.jamod.service.ModbusInfoService; +import com.youchain.jamod.service.dto.ModbusInfoQueryCriteria; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** +* @website https://eladmin.vip +* @author huojin +* @date 2025-03-21 +**/ +@RestController +@RequiredArgsConstructor +@Api(tags = "modbusInfo管理") +@RequestMapping("/api/modbusInfo") +public class ModbusInfoController { + + private final ModbusInfoService modbusInfoService; + + @Log("导出数据") + @ApiOperation("导出数据") + @GetMapping(value = "/download") + @PreAuthorize("@el.check('modbusInfo:list')") + public void exportModbusInfo(HttpServletResponse response, ModbusInfoQueryCriteria criteria) throws IOException { + modbusInfoService.download(modbusInfoService.queryAll(criteria), response); + } + + @GetMapping + @Log("查询modbusInfo") + @ApiOperation("查询modbusInfo") + @PreAuthorize("@el.check('modbusInfo:list')") + public ResponseEntity queryModbusInfo(ModbusInfoQueryCriteria criteria, Pageable pageable){ + return new ResponseEntity<>(modbusInfoService.queryAll(criteria,pageable),HttpStatus.OK); + } + + @PostMapping + @Log("新增modbusInfo") + @ApiOperation("新增modbusInfo") + @PreAuthorize("@el.check('modbusInfo:add')") + public ResponseEntity createModbusInfo(@Validated @RequestBody ModbusInfo resources){ + return new ResponseEntity<>(modbusInfoService.create(resources),HttpStatus.CREATED); + } + + @PutMapping + @Log("修改modbusInfo") + @ApiOperation("修改modbusInfo") + @PreAuthorize("@el.check('modbusInfo:edit')") + public ResponseEntity updateModbusInfo(@Validated @RequestBody ModbusInfo resources){ + modbusInfoService.update(resources); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @DeleteMapping + @Log("删除modbusInfo") + @ApiOperation("删除modbusInfo") + @PreAuthorize("@el.check('modbusInfo:del')") + public ResponseEntity deleteModbusInfo(@RequestBody Integer[] ids) { + modbusInfoService.deleteAll(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/jamod/service/ModbusInfoService.java b/youchain-system/src/main/java/com/youchain/jamod/service/ModbusInfoService.java new file mode 100644 index 0000000..d6b7e87 --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/jamod/service/ModbusInfoService.java @@ -0,0 +1,84 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.jamod.service; + +import com.youchain.jamod.domain.ModbusInfo; +import com.youchain.jamod.service.dto.ModbusInfoDto; +import com.youchain.jamod.service.dto.ModbusInfoQueryCriteria; +import org.springframework.data.domain.Pageable; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** +* @website https://eladmin.vip +* @description 服务接口 +* @author huojin +* @date 2025-03-21 +**/ +public interface ModbusInfoService { + + /** + * 查询数据分页 + * @param criteria 条件 + * @param pageable 分页参数 + * @return Map + */ + Map queryAll(ModbusInfoQueryCriteria criteria, Pageable pageable); + + /** + * 查询所有数据不分页 + * @param criteria 条件参数 + * @return List + */ + List queryAll(ModbusInfoQueryCriteria criteria); + + /** + * 根据ID查询 + * @param id ID + * @return ModbusInfoDto + */ + ModbusInfoDto findById(Integer id); + + /** + * 创建 + * @param resources / + * @return ModbusInfoDto + */ + ModbusInfoDto create(ModbusInfo resources); + + /** + * 编辑 + * @param resources / + */ + void update(ModbusInfo resources); + + /** + * 多选删除 + * @param ids / + */ + void deleteAll(Integer[] ids); + + /** + * 导出数据 + * @param all 待导出的数据 + * @param response / + * @throws IOException / + */ + void download(List all, HttpServletResponse response) throws IOException; +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/jamod/service/dto/ModbusInfoDto.java b/youchain-system/src/main/java/com/youchain/jamod/service/dto/ModbusInfoDto.java new file mode 100644 index 0000000..2642f6f --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/jamod/service/dto/ModbusInfoDto.java @@ -0,0 +1,85 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.jamod.service.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.sql.Timestamp; + +/** +* @website https://eladmin.vip +* @description / +* @author huojin +* @date 2025-03-21 +**/ +@Data +public class ModbusInfoDto implements Serializable { + + /** 自增主键,唯一标识每条记录 */ + private Integer id; + + /** Modbus 设备的名称,用于直观识别设备 */ + private String deviceName; + + /** Modbus 设备的 IP 地址 */ + private String deviceIp; + + /** Modbus 设备的端口号 */ + private Integer devicePort; + + /** Modbus 设备的详细描述信息,如设备用途、型号等 */ + private String deviceDescription; + + /** Modbus 数据的类型 */ + private String dataType; + + /** 批量读取数据的起始地址 */ + private Integer startAddress; + + /** 批量读取的数据长度 */ + private Integer dataLength; + + /** 批量读取的数据值集合,以特定格式存储,如逗号分隔的字符串 */ + private String dataValues; + + /** 最后一次读取该数据的时间 */ + private Timestamp lastReadTime; + + /** 最后一次修改该数据的时间 */ + private Timestamp lastModifyTime; + + /** 数据的版本号,每次数据修改时版本号递增,用于数据追溯 */ + private Integer dataVersion; + + /** 数据的状态,normal 表示正常,abnormal 表示异常,warning 表示警告,maintenance 表示维护中 */ + private String dataStatus; + + /** 是否触发报警,TRUE 表示触发,FALSE 表示未触发 */ + private Integer alarmStatus; + + /** 记录设备连接状态,TRUE 表示连接成功,FALSE 表示连接失败 */ + private Integer isConnected; + + /** 异常重试次数 */ + private Integer maxRetries; + + /** 状态:1启用、0禁用 */ + private Boolean enabled; + + /** 报错原因 */ + private String description; +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/jamod/service/dto/ModbusInfoQueryCriteria.java b/youchain-system/src/main/java/com/youchain/jamod/service/dto/ModbusInfoQueryCriteria.java new file mode 100644 index 0000000..0bfebe5 --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/jamod/service/dto/ModbusInfoQueryCriteria.java @@ -0,0 +1,36 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.jamod.service.dto; + +import com.youchain.annotation.Query; +import lombok.Data; + +/** +* @website https://eladmin.vip +* @author huojin +* @date 2025-03-21 +**/ +@Data +public class ModbusInfoQueryCriteria{ + + /** 模糊 */ + @Query(type = Query.Type.INNER_LIKE) + private String deviceName; + + /** 模糊 */ + @Query(type = Query.Type.INNER_LIKE) + private String deviceIp; +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/jamod/service/impl/ModbusInfoServiceImpl.java b/youchain-system/src/main/java/com/youchain/jamod/service/impl/ModbusInfoServiceImpl.java new file mode 100644 index 0000000..0b17275 --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/jamod/service/impl/ModbusInfoServiceImpl.java @@ -0,0 +1,121 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.jamod.service.impl; + +import com.youchain.jamod.domain.ModbusInfo; +import com.youchain.jamod.repository.ModbusInfoRepository; +import com.youchain.jamod.service.ModbusInfoService; +import com.youchain.jamod.service.dto.ModbusInfoDto; +import com.youchain.jamod.service.dto.ModbusInfoQueryCriteria; +import com.youchain.jamod.service.mapstruct.ModbusInfoMapper; +import com.youchain.utils.FileUtil; +import com.youchain.utils.PageUtil; +import com.youchain.utils.QueryHelp; +import com.youchain.utils.ValidationUtil; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** +* @website https://eladmin.vip +* @description 服务实现 +* @author huojin +* @date 2025-03-21 +**/ +@Service +@RequiredArgsConstructor +public class ModbusInfoServiceImpl implements ModbusInfoService { + + private final ModbusInfoRepository modbusInfoRepository; + private final ModbusInfoMapper modbusInfoMapper; + + @Override + public Map queryAll(ModbusInfoQueryCriteria criteria, Pageable pageable){ + Page page = modbusInfoRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); + return PageUtil.toPage(page.map(modbusInfoMapper::toDto)); + } + + @Override + public List queryAll(ModbusInfoQueryCriteria criteria){ + return modbusInfoMapper.toDto(modbusInfoRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder))); + } + + @Override + @Transactional + public ModbusInfoDto findById(Integer id) { + ModbusInfo modbusInfo = modbusInfoRepository.findById(id).orElseGet(ModbusInfo::new); + ValidationUtil.isNull(modbusInfo.getId(),"ModbusInfo","id",id); + return modbusInfoMapper.toDto(modbusInfo); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public ModbusInfoDto create(ModbusInfo resources) { + return modbusInfoMapper.toDto(modbusInfoRepository.save(resources)); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void update(ModbusInfo resources) { + ModbusInfo modbusInfo = modbusInfoRepository.findById(resources.getId()).orElseGet(ModbusInfo::new); + ValidationUtil.isNull( modbusInfo.getId(),"ModbusInfo","id",resources.getId()); + modbusInfo.copy(resources); + modbusInfoRepository.save(modbusInfo); + } + + @Override + public void deleteAll(Integer[] ids) { + for (Integer id : ids) { + modbusInfoRepository.deleteById(id); + } + } + + @Override + public void download(List all, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (ModbusInfoDto modbusInfo : all) { + Map map = new LinkedHashMap<>(); + map.put("Modbus 设备的名称,用于直观识别设备", modbusInfo.getDeviceName()); + map.put("Modbus 设备的 IP 地址", modbusInfo.getDeviceIp()); + map.put("Modbus 设备的端口号", modbusInfo.getDevicePort()); + map.put("Modbus 设备的详细描述信息,如设备用途、型号等", modbusInfo.getDeviceDescription()); + map.put("Modbus 数据的类型", modbusInfo.getDataType()); + map.put("批量读取数据的起始地址", modbusInfo.getStartAddress()); + map.put("批量读取的数据长度", modbusInfo.getDataLength()); + map.put("批量读取的数据值集合,以特定格式存储,如逗号分隔的字符串", modbusInfo.getDataValues()); + map.put("最后一次读取该数据的时间", modbusInfo.getLastReadTime()); + map.put("最后一次修改该数据的时间", modbusInfo.getLastModifyTime()); + map.put("数据的版本号,每次数据修改时版本号递增,用于数据追溯", modbusInfo.getDataVersion()); + map.put("数据的状态,normal 表示正常,abnormal 表示异常,warning 表示警告,maintenance 表示维护中", modbusInfo.getDataStatus()); + map.put("是否触发报警,TRUE 表示触发,FALSE 表示未触发", modbusInfo.getAlarmStatus()); + map.put("记录设备连接状态,TRUE 表示连接成功,FALSE 表示连接失败", modbusInfo.getIsConnected()); + map.put("异常重试次数", modbusInfo.getMaxRetries()); + map.put("状态:1启用、0禁用", modbusInfo.getEnabled()); + map.put("报错原因", modbusInfo.getDescription()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} \ No newline at end of file diff --git a/youchain-system/src/main/java/com/youchain/jamod/service/mapstruct/ModbusInfoMapper.java b/youchain-system/src/main/java/com/youchain/jamod/service/mapstruct/ModbusInfoMapper.java new file mode 100644 index 0000000..3b835d5 --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/jamod/service/mapstruct/ModbusInfoMapper.java @@ -0,0 +1,32 @@ +/* +* Copyright 2019-2020 Zheng Jie +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package com.youchain.jamod.service.mapstruct; + +import com.youchain.base.BaseMapper; +import com.youchain.jamod.domain.ModbusInfo; +import com.youchain.jamod.service.dto.ModbusInfoDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** +* @website https://eladmin.vip +* @author huojin +* @date 2025-03-21 +**/ +@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface ModbusInfoMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/youchain-system/src/main/resources/config/application-dev.yml b/youchain-system/src/main/resources/config/application-dev.yml index 8937805..9ef2c3d 100644 --- a/youchain-system/src/main/resources/config/application-dev.yml +++ b/youchain-system/src/main/resources/config/application-dev.yml @@ -14,13 +14,9 @@ spring: druid: db-type: com.alibaba.druid.pool.DruidDataSource driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy -# url: jdbc:log4jdbc:mysql://${DB_HOST:47.100.54.81}:${DB_PORT:53306}/${DB_NAME:hefeihvac_wms}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false - url: jdbc:log4jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:hefeihvac_wms}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false -# url: jdbc:log4jdbc:mysql://${DB_HOST:10.175.163.49}:${DB_PORT:3306}/${DB_NAME:hefeihvac_wms}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false -# url: jdbc:log4jdbc:mysql://${DB_HOST:10.173.188.206}:${DB_PORT:53306}/${DB_NAME:wms}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false + url: jdbc:log4jdbc:mysql://${DB_HOST:47.103.100.52}:${DB_PORT:53306}/${DB_NAME:hefeihvac_wms}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false username: ${DB_USER:root} -# password: ${DB_PWD:Youchain@56} - password: ${DB_PWD:123456} + password: ${DB_PWD:Youchain@56} # 初始连接数 initial-size: 5 # 最小连接数