在C# 和Java中,利用反射处理S7协议读取西门子PLC的变量

您所在的位置:网站首页 西门子1500plc模拟量如何编程 在C# 和Java中,利用反射处理S7协议读取西门子PLC的变量

在C# 和Java中,利用反射处理S7协议读取西门子PLC的变量

2023-01-02 05:17| 来源: 网络整理| 查看: 265

在C#和java中,有开源通信库NetS7Plus和S7Connector提供后台与PLC的通信。由于这两个库都提供了连续读取的方法。

以java为例,按偏移量读取Db块中的数值:

package com.zg.mymes.myConnPLC.myS7.myS7entities; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.fasterxml.jackson.annotation.JsonFormat; import com.github.s7connector.api.annotation.S7Variable; import com.github.s7connector.impl.utils.S7Type; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.format.annotation.DateTimeFormat; import org.yaml.snakeyaml.scanner.Constant; import java.util.Date; /** * @Auther: Zg * @Date: 2022/11/23 - 11 - 23 - 17:13 * @Description: com.zg.mymes.myConnPLC.myS7.myS7entities * @version: 1.0 * 可定制化的PLC值 */ @Builder @Data @AllArgsConstructor @NoArgsConstructor //@PropertySource("classpath:myS7Db.properties") public class MyS7Entity { // @TableId(type = IdType.AUTO) // private Integer id; // // public static final Integer dbNum = 30; // //@Value("${myS7Db.offSet}") // public static final Integer offSet = 42; // // @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") // @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8") // private Date createTime; // @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") // @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8") // private Date insertTime; //必须为public 否则报错 @S7Variable(byteOffset = 0, type = S7Type.REAL) public Double aBLineVoltage_PLC; @S7Variable(byteOffset = 4, type = S7Type.REAL) public Double bCLineVoltage_PLC; @S7Variable(byteOffset = 8, type = S7Type.REAL) public Double aCLineVoltage_PLC; @S7Variable(byteOffset = 12, type = S7Type.REAL) public Double aPhaseVoltage_PLC; @S7Variable(byteOffset = 16, type = S7Type.REAL) public Double bPhaseVoltage_PLC; @S7Variable(byteOffset = 20, type = S7Type.REAL) public Double cPhaseVoltage_PLC; @S7Variable(byteOffset = 24, type = S7Type.REAL) public Double aPhaseCurrent_PLC; @S7Variable(byteOffset = 28, type = S7Type.REAL) public Double bPhaseCurrent_PLC; @S7Variable(byteOffset = 32, type = S7Type.REAL) public Double cPhaseCurrent_PLC; @S7Variable(byteOffset = 36, type = S7Type.REAL) public Double allActivePower_PLC; @S7Variable(byteOffset = 40, type = S7Type.REAL) public Double aActivePower_PLC; @S7Variable(byteOffset = 44, type = S7Type.REAL) public Double bActivePower_PLC; @S7Variable(byteOffset = 48, type = S7Type.REAL) public Double cActivePower_PLC; @S7Variable(byteOffset = 52, type = S7Type.REAL) public Double allReactivePower_PLC; @S7Variable(byteOffset = 56, type = S7Type.REAL) public Double aReactivePower_PLC; @S7Variable(byteOffset = 60, type = S7Type.REAL) public Double bReactivePower_PLC; @S7Variable(byteOffset = 64, type = S7Type.REAL) public Double cReactivePower_PLC; @S7Variable(byteOffset = 68, type = S7Type.REAL) public Double allPowerFactor_PLC; @S7Variable(byteOffset = 72, type = S7Type.REAL) public Double aPowerFactor_PLC; @S7Variable(byteOffset = 76, type = S7Type.REAL) public Double bPowerFactor_PLC; @S7Variable(byteOffset = 80, type = S7Type.REAL) public Double cPowerFactor_PLC; @S7Variable(byteOffset = 84, type = S7Type.REAL) public Double aBLineVoltage_Power; @S7Variable(byteOffset = 88, type = S7Type.REAL) public Double bCLineVoltage_Power; @S7Variable(byteOffset = 92, type = S7Type.REAL) public Double aCLineVoltage_Power; @S7Variable(byteOffset = 96, type = S7Type.REAL) public Double aPhaseVoltage_Power; @S7Variable(byteOffset = 100, type = S7Type.REAL) public Double bPhaseVoltage_Power; @S7Variable(byteOffset = 104, type = S7Type.REAL) public Double cPhaseVoltage_Power; @S7Variable(byteOffset = 108, type = S7Type.REAL) public Double aPhaseCurrent_Power; @S7Variable(byteOffset = 112, type = S7Type.REAL) public Double bPhaseCurrent_Power; @S7Variable(byteOffset = 116, type = S7Type.REAL) public Double cPhaseCurrent_Power; @S7Variable(byteOffset = 120, type = S7Type.REAL) public Double allActivePower_Power; @S7Variable(byteOffset = 124, type = S7Type.REAL) public Double aActivePower_Power; @S7Variable(byteOffset = 128, type = S7Type.REAL) public Double bActivePower_Power; @S7Variable(byteOffset = 132, type = S7Type.REAL) public Double cActivePower_Power; @S7Variable(byteOffset = 136, type = S7Type.REAL) public Double allReactivePower_Power; @S7Variable(byteOffset = 140, type = S7Type.REAL) public Double aReactivePower_Power; @S7Variable(byteOffset = 144, type = S7Type.REAL) public Double bReactivePower_Power; @S7Variable(byteOffset = 148, type = S7Type.REAL) public Double cReactivePower_Power; @S7Variable(byteOffset = 152, type = S7Type.REAL) public Double allPowerFactor_Power; @S7Variable(byteOffset = 156, type = S7Type.REAL) public Double aPowerFactor_Power; @S7Variable(byteOffset = 160, type = S7Type.REAL) public Double bPowerFactor_Power; @S7Variable(byteOffset = 164, type = S7Type.REAL) public Double cPowerFactor_Power; @S7Variable(byteOffset = 168, type = S7Type.REAL) public Double testAlarm; @S7Variable(byteOffset = 404, type = S7Type.WORD) public Integer heartBeat; @S7Variable(byteOffset = 606,size = 130, type = S7Type.STRING) public String var100; @S7Variable(byteOffset = 738,size = 130, type = S7Type.STRING) public String var101; /** @S7Variable(byteOffset=0, type= S7Type.REAL) public double var1; @S7Variable(byteOffset=4, type= S7Type.REAL) public double var2; @S7Variable(byteOffset=8, type= S7Type.REAL) public double var3; @S7Variable(byteOffset=144, type= S7Type.BOOL) public boolean STATE_P1; @S7Variable(byteOffset=144, type= S7Type.BOOL,bitOffset = 1) public boolean STATE_P1; */ }

读取的变量为类中的字段,但是实际情况中,我们往往需要各个变量的采集时间,报警值,缩放比例,中文名等,例如

package com.zg.mymes.entities; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import org.springframework.format.annotation.DateTimeFormat; import java.util.Date; /** * @Auther: Zg * @Date: 2022/11/23 - 11 - 23 - 14:26 * @Description: com.zg.mymes.entities * @version: 1.0 */ @Builder @Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true) public class ActualData { @TableId(type = IdType.AUTO) private Integer id; private String name; private String description; @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8") // @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") // @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8") private Date createTime; @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8") private Date insertTime; private String varAddress; private String varType; private String scale; private String highAlarm; private String highHighAlarm; private String lowAlarm; private String lowLowAlarm; private String alarmDescription; private String value; }

这样的格式的变量,这时就需要我们把第一个类class MyS7Entity中的字段映射到class ActualData中,这时就可以利用反射特性快速映射:

//S7 @Async @Scheduled(cron = "*/1 * * * * *") public void Listen(){ try { s7ConnHelper.readPlcData(31, MyS7Entity.class, 0); Map myMap = new HashMap(); Field[] fields = s7ConnHelper.getMyDbData().getClass().getFields(); for (Field f :fields ) { //log.info(f.getType().toString()); if (f.get(s7ConnHelper.getMyDbData()) instanceof Double){ String format = String.format("%.3f", f.get(s7ConnHelper.getMyDbData())); myMap.put(f.getName(),format); } else { myMap.put(f.getName(),f.get(s7ConnHelper.getMyDbData())); } } s7ConnHelper.setMyMap(myMap); java.util.Date date = new Date();//获得当前时间 Timestamp t = new Timestamp(date.getTime());//将时间转换成Timestamp类型,这样便可以存入到Mysql数据库中 for (ActualData actualData:s7ConnHelper.getActualDatas() ) { actualData.setCreateTime(t); actualData.setValue(myMap.get(actualData.getName()).toString()); if ( actualData.getVarType().equals("Float")&& actualData.getHighHighAlarm()!=null && actualData.getHighHighAlarm().length()!=0&& actualData.getHighAlarm()!=null && actualData.getHighAlarm().length()!=0 && actualData.getLowLowAlarm()!=null && actualData.getLowLowAlarm().length()!=0 && actualData.getLowAlarm()!=null && actualData.getLowAlarm().length()!=0 ){ if ((Double.parseDouble(actualData.getValue())>Double.parseDouble(actualData.getHighAlarm())) && (Double.parseDouble(actualData.getValue()) actualData.setAlarmDescription("该变量高高报警!"); actualData.setInsertTime(t); actualDataService.save(actualData); } if ((Double.parseDouble(actualData.getValue())Double.parseDouble(actualData.getLowLowAlarm())) ){ actualData.setAlarmDescription("该变量低报警!"); actualData.setInsertTime(t); actualDataService.save(actualData); } if (Double.parseDouble(actualData.getValue()) log.info(ex.getMessage()+"====="); s7ConnHelper.s7Connector=null; s7ConnHelper.s7Serializer=null; try { s7ConnHelper.initConnect(); errorTimes=0; } catch (IOException e) { e.printStackTrace(); } } }

通信帮助类:

package com.zg.mymes.myConnPLC.myS7; import com.github.s7connector.api.DaveArea; import com.github.s7connector.api.S7Connector; import com.github.s7connector.api.S7Serializer; import com.github.s7connector.api.factory.S7ConnectorFactory; import com.github.s7connector.api.factory.S7SerializerFactory; import com.zg.mymes.entities.ActualData; import com.zg.mymes.entities.MyConfig; import com.zg.mymes.helper.MyJsonConfigTool; import com.zg.mymes.myConnPLC.DataConvert; import com.zg.mymes.myConnPLC.myS7.myS7entities.MyS7Entity; import com.zg.mymes.myConnPLC.myS7.myS7entities.MyS7WriteEntity; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import java.io.IOException; import java.sql.Timestamp; import java.util.*; /** * @Auther: Zg * @Date: 2022/11/23 - 11 - 23 - 17:14 * @Description: com.zg.mymes.myConnPLC.myS7 * @version: 1.0 */ @Component @Slf4j @Builder @Data @AllArgsConstructor @NoArgsConstructor public class S7ConnHelper implements IS7ConnHelper { private String Ip; private Integer Port; public S7Connector s7Connector; public S7Serializer s7Serializer; private List actualDatas = new ArrayList(); private MyS7Entity myDbData; private List myDbDataList = new ArrayList(); private List myDbDatas = new ArrayList(); private Map myMap = new HashMap(); private Integer errorTimes = 0; private Boolean isConnected = false; private Boolean heart = false; @Autowired private MyJsonConfigTool configTool; @Autowired private DataConvert dataConvert; @Override public void initConnect() throws IOException { MyConfig myConfig = configTool.ReadJson(); Ip = myConfig.getIp(); Port = 102; actualDatas = myConfig.getActualDatas(); if (this.s7Connector==null){ this.s7Connector = S7ConnectorFactory.buildTCPConnector() .withHost(Ip) .withPort(Port) .withTimeout(10000) .withRack(0)//机架号 .withSlot(1)//插槽号 .build(); this.s7Serializer = S7SerializerFactory.buildSerializer(s7Connector); this.isConnected = true; } } /** * * @param dbNum DB号 * @param clazz 变量 * @param offSet 偏移量 */ @Override public MyS7Entity readPlcData(Integer dbNum, Class clazz, int offSet){ //第一个参数:DaveArea.DB 表示读取PLC的地址区域为DB //第二个参数:DB块地址,若plc中是DB1000,则填1000 //第三个参数:数据长度 //第四个参数:偏移量 //s7Connector.read(DaveArea.DB,) // this.clazz = clazz; // this.dbNum = dbNum; //S7Serializer s7Serializer = S7SerializerFactory.buildSerializer(s7Connector); //db号,偏移量 if (this.isConnected=true){ // java.util.Date date = new Date();//获得当前时间 // Timestamp t = new Timestamp(date.getTime()); this.myDbData = (MyS7Entity)this.s7Serializer.dispense(clazz, dbNum, offSet); //this.myDbData.setCreateTime(t); //心跳 if (heart==false){ this.myDbData.setHeartBeat(10); heart=true; } else if (heart==true){ this.myDbData.setHeartBeat(20); heart=false; } try { this.s7Serializer.store(this.myDbData,dbNum,offSet); } //断线重连 catch (Exception ex){ log.info(ex.getMessage()+"Inner+=+="); this.isConnected=false; try { this.s7Connector.close(); } catch (IOException e) { e.printStackTrace(); } this.s7Connector=null; this.s7Serializer=null; try { this.initConnect(); errorTimes=0; } catch (IOException e) { e.printStackTrace(); } } this.myDbData = (MyS7Entity)this.s7Serializer.dispense(clazz, dbNum, offSet); if (myDbDatas.size() myDbDatas.remove(0); } } return myDbData; } @Override public MyS7Entity readTheDbData(Integer dbNum, MyS7Entity clazz, int offSet) { MyS7Entity myData = this.s7Serializer.dispense(clazz.getClass(), dbNum, offSet); return myData; } @Override public void writePlcData(Integer dbNum, MyS7WriteEntity clazz){ this.s7Serializer.store(clazz,dbNum,0); } //DB,DB号,偏移量,Byte数组 @Override public void writePlcByte(byte[] bytes){ this.s7Connector.write(DaveArea.DB,31,0,bytes); } } package com.zg.mymes.myConnPLC.myS7; import com.zg.mymes.myConnPLC.myS7.myS7entities.MyS7Entity; import com.zg.mymes.myConnPLC.myS7.myS7entities.MyS7WriteEntity; import java.io.IOException; /** * @Auther: Zg * @Date: 2022/11/23 - 11 - 23 - 17:10 * @Description: com.zg.mymes.myConnPLC.myS7 * @version: 1.0 */ public interface IS7ConnHelper { void initConnect() throws IOException; MyS7Entity readPlcData(Integer dbNum, Class clazz, int offSet); MyS7Entity readTheDbData(Integer dbNum, MyS7Entity clazz, int offSet); void writePlcData(Integer dbNum, MyS7WriteEntity clazz); void writePlcByte(byte[] bytes); } package com.zg.mymes.helper; import com.fasterxml.jackson.databind.ObjectMapper; import com.zg.mymes.entities.MyConfig; import org.springframework.stereotype.Service; import java.io.*; /** * @Auther: Zg * @Date: 2022/11/23 - 11 - 23 - 14:58 * @Description: com.zg.mymes.helper * @version: 1.0 */ @Service public class MyJsonConfigTool { public String jsonStr="D:\\s7cfg.json"; public void CreatJson( MyConfig config) throws IOException { // 创建文件对象 File fileText = new File(jsonStr); ObjectMapper mapper = new ObjectMapper(); // 向文件写入对象写入信息 FileWriter fileWriter = new FileWriter(fileText); // 写文件 String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(config); fileWriter.write(jsonString); // 关闭 fileWriter.close(); } public MyConfig ReadJson() throws IOException { ObjectMapper mapper = new ObjectMapper(); File file = new File(jsonStr); String str = getStr(file); MyConfig myConfig = mapper.readValue(str, MyConfig.class); return myConfig; } public String getStr(File jsonFile){ String jsonStr = ""; try { FileReader fileReader = new FileReader(jsonFile); Reader reader = new InputStreamReader(new FileInputStream(jsonFile),"utf-8"); int ch = 0; StringBuffer sb = new StringBuffer(); while ((ch = reader.read()) != -1) { sb.append((char) ch); } fileReader.close(); reader.close(); jsonStr = sb.toString(); return jsonStr; } catch (IOException e) { e.printStackTrace(); return null; } } }

C#的对应代码:

using S7.Net.Types; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ZgCsharp.Entities { public class MyS7Db { public float aBLineVoltage_PLC { get; set; } public float bCLineVoltage_PLC { get; set; } public float aCLineVoltage_PLC { get; set; } public float aPhaseVoltage_PLC { get; set; } public float bPhaseVoltage_PLC { get; set; } public float cPhaseVoltage_PLC { get; set; } public float aPhaseCurrent_PLC { get; set; } public float bPhaseCurrent_PLC { get; set; } public float cPhaseCurrent_PLC { get; set; } public float allActivePower_PLC { get; set; } public float aActivePower_PLC { get; set; } public float bActivePower_PLC { get; set; } public float cActivePower_PLC { get; set; } public float allReactivePower_PLC { get; set; } public float aReactivePower_PLC { get; set; } public float bReactivePower_PLC { get; set; } public float cReactivePower_PLC { get; set; } public float allPowerFactor_PLC { get; set; } public float aPowerFactor_PLC { get; set; } public float bPowerFactor_PLC { get; set; } public float cPowerFactor_PLC { get; set; } public float aBLineVoltage_Power { get; set; } public float bCLineVoltage_Power { get; set; } public float aCLineVoltage_Power { get; set; } public float aPhaseVoltage_Power { get; set; } public float bPhaseVoltage_Power { get; set; } public float cPhaseVoltage_Power { get; set; } public float aPhaseCurrent_Power { get; set; } public float bPhaseCurrent_Power { get; set; } public float cPhaseCurrent_Power { get; set; } public float allActivePower_Power { get; set; } public float aActivePower_Power { get; set; } public float bActivePower_Power { get; set; } public float cActivePower_Power { get; set; } public float allReactivePower_Power { get; set; } public float aReactivePower_Power { get; set; } public float bReactivePower_Power { get; set; } public float cReactivePower_Power { get; set; } public float allPowerFactor_Power { get; set; } public float aPowerFactor_Power { get; set; } public float bPowerFactor_Power { get; set; } public float cPowerFactor_Power { get; set; } public float testAlarm { get; set; } //public ushort heartBeat { get; set; } //[S7String(S7StringType.S7String, 130)] //public string var100; //public string Var100 //{ // get { return var100; } // set { var100 = value; } //} //[S7String(S7StringType.S7String, 130)] //public string var101; //public string Var101 //{ // get { return var101; } // set { var101 = value; } //} //public bool Bool1 { get; set; } //public byte Byte1 { get; set; } //public double Float1 { get; set; } //public uint MD101 { get; set; } } } using Newtonsoft.Json; using S7.Net; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using ZgCsharp.Entities; using ZgCsharp.SqlSugar.Repository.Impl; namespace ZgCsharp.S7 { /* public enum CpuType { S7200 = 0, Logo0BA8 = 1, S7200Smart = 2, S7300 = 10, S7400 = 20, S71200 = 30, S71500 = 40 } */ public class MyS7Helper { public Plc myS7Master = null; //配置文件地址 private string jsonfile = Application.StartupPath + "\\Config\\modbuscfg1.json"; private string str; private CfgJson cfgJson; private ModelRepository modelRepository; private string ip; private int port; private string myCpuType; private string s7DbNum; private string s7StartByte; private int strMax; private MyS7Db myS7Db = new MyS7Db(); private List actualDatas = new List(); public List ActualDatas { get { return actualDatas; } set { actualDatas = value; } } public MyS7Db MyS7Db { get { return myS7Db; } set { myS7Db = value; } } private CancellationTokenSource cts = new CancellationTokenSource(); public MyS7Helper(ModelRepository modelRepository) { this.modelRepository = modelRepository; str = File.ReadAllText(jsonfile); cfgJson = JsonConvert.DeserializeObject(str); this.ip = cfgJson.Ip; this.port = 102; this.myCpuType = cfgJson.CPUType; this.s7DbNum = cfgJson.S7DbNum; this.s7StartByte = cfgJson.S7StartByte; this.strMax = int.Parse(cfgJson.strMax); this.actualDatas = cfgJson.ActualDatas; this.Conn(); this.ReadPLCClass(); } public bool Conn() { myS7Master = new Plc((CpuType)Enum.Parse(typeof(CpuType), this.myCpuType), this.ip, 0, 0); try { myS7Master.Open(); } catch (Exception ex) { return false; } return true; } public void DisConn() { myS7Master.Close(); } public void ReadPLCClass() { Task.Run(async () => { while (!cts.IsCancellationRequested) { if (myS7Master.IsConnected) { //int i = myS7Master.ReadClass(myS7Db, int.Parse(this.s7DbNum), int.Parse(this.s7StartByte)); myS7Db = myS7Master.ReadClass(int.Parse(this.s7DbNum), int.Parse(this.s7StartByte)); await Task.Delay(500); System.Reflection.PropertyInfo[] fields = MyS7Db.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); //System.Reflection.FieldInfo[] fields = MyS7Db.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); foreach (var item in fields) { foreach (var i in this.actualDatas) { if (item.Name == i.Name) { i.Value = item.GetValue(MyS7Db).ToString(); } } } } } }, cts.Token); } public void WritePLCClass(MyS7Db myS7DbData) { myS7Master.WriteClass(myS7DbData, int.Parse(this.s7DbNum), int.Parse(this.s7StartByte)); } public void WriteStr(string str) { byte[] myBytes = Encoding.ASCII.GetBytes(str); byte[] byte1 = { (byte)130, (byte)myBytes.Length }; byte[] b = byte1.Concat(myBytes).ToArray(); //myS7Master.WriteBytes(DataType.DataBlock, int.Parse(this.s7DbNum), int.Parse(this.s7StartByte), b); myS7Master.WriteBytes(DataType.DataBlock, 32, 3696, b); } public void WriteBadApple(byte[] bytes) { myS7Master.WriteBytes(DataType.DataBlock, 32, 0, bytes); } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ZgCsharp.Entities { public class CfgJson { public string Ip { get; set; } public string Port { get; set; } public string SlaveNo { get; set; } public string Address { get; set; } public string VarNum { get; set; } public string CPUType { get; set; } public string S7DbNum { get; set; } public string S7StartByte { get; set; } public string strMax { get; set; } public List ActualDatas { get; set; } } }

使用springboot当后端,layui+thyme leaf当前端:

在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3