严智鑫
2025-06-13 d14cdaf28222bfef468185e34de7c823f1436b19
设备交互模块化组件 初步完成
188个文件已添加
14655 ■■■■■ 已修改文件
.idea/.gitignore 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/ShangHaiMES.iml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/compiler.xml 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/encodings.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/jarRepositories.xml 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/misc.xml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/modules.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/uiDesigner.xml 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/vcs.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/.idea/.gitignore 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/.idea/compiler.xml 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/.idea/encodings.xml 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/.idea/inspectionProfiles/Project_Default.xml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/.idea/jarRepositories.xml 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/.idea/libraries/servicebase_1_0_SNAPSHOT.xml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/.idea/libraries/springsecurity_1_0_SNAPSHOT.xml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/.idea/misc.xml 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/.idea/modules.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/.idea/uiDesigner.xml 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/.idea/vcs.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/JsonFile/PlcCacheGlass.json 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/JsonFile/PlcCleaning.json 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/JsonFile/PlcEdging.json 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/JsonFile/PlcFlipSlice.json 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/JsonFile/PlcLamination.json 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/JsonFile/PlcLoad.json 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/JsonFile/PlcLoad2.json 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/JsonFile/PlcMarking.json 318 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/JsonFile/PlcRotate.json 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/JsonFile/PlcSilkScreen.json 184 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/pom.xml 217 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/pom.xml 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/servicebase1.iml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/config/Const.java 172 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/config/MybatisPlusConfig.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/config/Swagger2Config.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/config/WebSocketConfig.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/exception/GlobalExceptionHandler.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/exception/ServiceException.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/handler/MyMetaObjectHandler.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/device/PlcBitInfo.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/device/PlcBitObject.java 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/device/PlcParameterInfo.java 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/device/PlcParameterObject.java 254 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/entity/request/GeneralRequest.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/service/Communication.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/service/ModbusTcp.java 223 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/service/PlcAgreement.java 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/service/PlcParameter.java 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/tools/CodeGet.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/tools/DatabaseDesignDocUtil.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/tools/HexConversion.java 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/tools/InitUtil.java 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/tools/S7control.java 489 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/tools/WebSocketServer.java 174 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/utils/HexUtil.java 269 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/utils/MD5.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/utils/ResponseUtil.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/utils/Result.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/utils/ResultCodeEnum.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/servicebase/src/main/resources/banner.txt 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/pom.xml 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/springsecurity1.iml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/config/RedisConfig.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/config/TokenWebSecurityConfig.java 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/filter/JwtAuthenticationTokenFilter.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/handler/JwtAccessDeniedHandler.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/handler/JwtAuthenticationEntryPoint.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/handler/JwtLogoutSuccessHandler.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/handler/LoginFailureHandler.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/handler/LoginSuccessHandler.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/utils/FastJsonRedisSerializer.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/utils/JwtUtil.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/utils/RedisUtil.java 235 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/utils/UserInfoUtils.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/utils/WebUtils.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/menu/controller/SysMenuController.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/menu/entity/SysMenu.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/menu/mapper/SysMenuMapper.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/menu/service/SysMenuService.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/menu/service/impl/SysMenuServiceImpl.java 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/controller/SysRoleController.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/entity/SysRole.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/entity/SysRoleMenu.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/entity/vo/SysRoleVO.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/mapper/SysRoleMapper.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/mapper/SysRoleMenuMapper.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/mapper/xml/SysRoleMapper.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/mapper/xml/SysRoleMenuMapper.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/service/SysRoleMenuService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/service/SysRoleService.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/service/impl/SysRoleMenuServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/service/impl/SysRoleServiceImpl.java 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/controller/SysUserController.java 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/entity/LoginUser.java 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/entity/SysUser.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/entity/SysUserRole.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/entity/vo/SysUserVO.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/mapper/SysUserMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/mapper/SysUserRoleMapper.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/mapper/xml/SysUserMapper.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/mapper/xml/SysUserRoleMapper.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/service/SysUserRoleService.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/service/SysUserService.java 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/service/impl/SysUserRoleServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/service/impl/SysUserServiceImpl.java 271 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/resources/application-dev.yml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/resources/application-loc.yml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/resources/application-prod.yml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/common/springsecurity/src/main/resources/mapper/SysMenuMapper.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/gateway/gateway1.iml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/gateway/pom.xml 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/gateway/src/main/java/com/mes/GateWayApplication.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/gateway/src/main/java/com/mes/config/MyCorsConfig.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/gateway/src/main/resources/application.yml 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/pom.xml 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/AppRunnerConfig.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/common/JsonConversion.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/common/ReadFile.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/common/RestTemplateConfig.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/ExampleDataHandler.java 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/IndustrialInterface/AddressParser.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/IndustrialInterface/Api.java 232 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/IndustrialInterface/ApiService.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/IndustrialInterface/IndustrialClient.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/IndustrialInterface/IndustrialDataHandler.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/IndustrialInterface/IndustrialServer.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/Thread/MachineThread.java 394 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/addressParser/ModbusAddressParser.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/addressParser/ModbusIpAddressParser.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/addressParser/ModbusRtuAddressParser.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/addressParser/S7AddressParser.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/addressParser/S7OldAddressParser.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/entity/Logic.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/entity/LogicConfig.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/entity/LogicItem.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/entity/Parameters.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/entity/PlcParameters.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/entity/ReturnValue.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/modbus/ModbusIpClient.java 461 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/modbus/ModbusIpServer.java 393 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/modbus/ModbusTcpClient.java 374 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/modbus/ModbusTcpServer.java 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/protocol/ProtocolAddress.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/protocol/ProtocolType.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/s7/S7Client.java 615 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/s7/S7ClientOld.java 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/s7/S7Server.java 434 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/controller/AccountController.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/entity/Account.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/entity/Machine.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/entity/PlcType.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/entity/ProtocolType.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/AccountMapper.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/MachineMapper.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/PlcTypeMapper.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/ProtocolTypeMapper.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/xml/AccountMapper.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/xml/MachineMapper.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/xml/PlcTypeMapper.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/xml/ProtocolTypeMapper.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/AccountService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/MachineService.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/PlcTypeService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/ProtocolTypeService.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/impl/AccountServiceImpl.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/impl/MachineServiceImpl.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/impl/PlcTypeServiceImpl.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/impl/ProtocolTypeServiceImpl.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/plcConnectModuleApplication.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/main.iml 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/loadLogic.json 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/loadLogic2.json 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/loadLogicS7.json 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/logicalRelationship.json 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/shelf.json 244 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/shelfLogic.json 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/shelfS7.json 244 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/application-cz.yml 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/application-dev.yml 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/application-prod.yml 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/application.yml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/logback-spring.xml 170 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/test/java/com/mes/plcConnectModuleApplicationTest.java 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/plcConnectModule/src/test/test.iml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/moduleService/pom.xml 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/pom.xml 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ShangHaiMesParent/readMe.md 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/.gitignore
New file
@@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
.idea/ShangHaiMES.iml
New file
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$" />
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
</module>
.idea/compiler.xml
New file
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="CompilerConfiguration">
    <annotationProcessing>
      <profile default="true" name="Default" enabled="true" />
      <profile name="Maven default annotation processors profile" enabled="true">
        <sourceOutputDir name="target/generated-sources/annotations" />
        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
        <outputRelativeToContentRoot value="true" />
        <module name="plcConnect" />
        <module name="servicebase" />
        <module name="gateway" />
      </profile>
    </annotationProcessing>
    <bytecodeTargetLevel>
      <module name="springsecurity" target="1.8" />
    </bytecodeTargetLevel>
  </component>
  <component name="JavacSettings">
    <option name="ADDITIONAL_OPTIONS_OVERRIDE">
      <module name="gateway" options="-parameters" />
      <module name="plcConnect" options="-parameters" />
      <module name="servicebase" options="-parameters" />
      <module name="springsecurity" options="-parameters" />
    </option>
  </component>
</project>
.idea/encodings.xml
New file
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="Encoding">
    <file url="file://$PROJECT_DIR$/ShangHaiMesParent/common/servicebase/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/ShangHaiMesParent/common/springsecurity/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/ShangHaiMesParent/common/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/ShangHaiMesParent/common/src/main/resources" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/ShangHaiMesParent/gateway/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/ShangHaiMesParent/moduleService/plcConnectModule/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/ShangHaiMesParent/moduleService/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/ShangHaiMesParent/moduleService/src/main/resources" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/ShangHaiMesParent/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/ShangHaiMesParent/src/main/resources" charset="UTF-8" />
  </component>
</project>
.idea/jarRepositories.xml
New file
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="RemoteRepositoriesConfiguration">
    <remote-repository>
      <option name="id" value="central" />
      <option name="name" value="Central Repository" />
      <option name="url" value="https://repo.maven.apache.org/maven2" />
    </remote-repository>
    <remote-repository>
      <option name="id" value="central" />
      <option name="name" value="Maven Central repository" />
      <option name="url" value="https://repo1.maven.org/maven2" />
    </remote-repository>
    <remote-repository>
      <option name="id" value="jboss.community" />
      <option name="name" value="JBoss Community repository" />
      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
    </remote-repository>
    <remote-repository>
      <option name="id" value="nexus-aliyun" />
      <option name="name" value="Nexus aliyun" />
      <option name="url" value="https://maven.aliyun.com/repository/public" />
    </remote-repository>
    <remote-repository>
      <option name="id" value="spring" />
      <option name="name" value="spring" />
      <option name="url" value="https://maven.aliyun.com/repository/spring" />
    </remote-repository>
  </component>
</project>
.idea/misc.xml
New file
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ExternalStorageConfigurationManager" enabled="true" />
  <component name="MavenProjectsManager">
    <option name="originalFiles">
      <list>
        <option value="$PROJECT_DIR$/JiuMuMesParent/pom.xml" />
        <option value="$PROJECT_DIR$/JiuMuMesParent/common/springsecurity/pom.xml" />
        <option value="$PROJECT_DIR$/ShangHaiMesParent/pom.xml" />
      </list>
    </option>
  </component>
  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
    <output url="file://$PROJECT_DIR$/out" />
  </component>
</project>
.idea/modules.xml
New file
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectModuleManager">
    <modules>
      <module fileurl="file://$PROJECT_DIR$/.idea/ShangHaiMES.iml" filepath="$PROJECT_DIR$/.idea/ShangHaiMES.iml" />
    </modules>
  </component>
</project>
.idea/uiDesigner.xml
New file
@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="Palette2">
    <group name="Swing">
      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
      </item>
      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
      </item>
      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
      </item>
      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
      </item>
      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
        <initial-values>
          <property name="text" value="Button" />
        </initial-values>
      </item>
      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
        <initial-values>
          <property name="text" value="RadioButton" />
        </initial-values>
      </item>
      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
        <initial-values>
          <property name="text" value="CheckBox" />
        </initial-values>
      </item>
      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
        <initial-values>
          <property name="text" value="Label" />
        </initial-values>
      </item>
      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
          <preferred-size width="150" height="-1" />
        </default-constraints>
      </item>
      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
          <preferred-size width="150" height="-1" />
        </default-constraints>
      </item>
      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
          <preferred-size width="150" height="-1" />
        </default-constraints>
      </item>
      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
          <preferred-size width="150" height="50" />
        </default-constraints>
      </item>
      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
          <preferred-size width="150" height="50" />
        </default-constraints>
      </item>
      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
          <preferred-size width="150" height="50" />
        </default-constraints>
      </item>
      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
      </item>
      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
          <preferred-size width="150" height="50" />
        </default-constraints>
      </item>
      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
          <preferred-size width="150" height="50" />
        </default-constraints>
      </item>
      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
          <preferred-size width="150" height="50" />
        </default-constraints>
      </item>
      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
          <preferred-size width="200" height="200" />
        </default-constraints>
      </item>
      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
          <preferred-size width="200" height="200" />
        </default-constraints>
      </item>
      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
      </item>
      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
      </item>
      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
      </item>
      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
      </item>
      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
          <preferred-size width="-1" height="20" />
        </default-constraints>
      </item>
      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
      </item>
      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
      </item>
    </group>
  </component>
</project>
.idea/vcs.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="VcsDirectoryMappings">
    <mapping directory="" vcs="Git" />
  </component>
</project>
ShangHaiMesParent/.idea/.gitignore
New file
@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
ShangHaiMesParent/.idea/compiler.xml
New file
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="CompilerConfiguration">
    <annotationProcessing>
      <profile default="true" name="Default" enabled="true" />
      <profile name="Maven default annotation processors profile" enabled="true">
        <sourceOutputDir name="target/generated-sources/annotations" />
        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
        <outputRelativeToContentRoot value="true" />
        <module name="springsecurity" />
        <module name="servicebase" />
        <module name="deviceInteraction" />
        <module name="gateway" />
      </profile>
    </annotationProcessing>
    <bytecodeTargetLevel>
      <module name="cacheGlass" target="1.8" />
      <module name="cacheVerticalGlass" target="1.8" />
      <module name="glassStorage" target="1.8" />
      <module name="loadGlass" target="1.8" />
      <module name="temperingGlass" target="1.8" />
      <module name="unLoadGlass" target="1.8" />
    </bytecodeTargetLevel>
  </component>
  <component name="JavacSettings">
    <option name="ADDITIONAL_OPTIONS_OVERRIDE">
      <module name="cacheGlass" options="-parameters" />
      <module name="cacheVerticalGlass" options="-parameters" />
      <module name="deviceInteraction" options="-parameters" />
      <module name="gateway" options="-parameters" />
      <module name="glassStorage" options="-parameters" />
      <module name="loadGlass" options="-parameters" />
      <module name="servicebase" options="-parameters" />
      <module name="springsecurity" options="-parameters" />
      <module name="temperingGlass" options="-parameters" />
      <module name="unLoadGlass" options="-parameters" />
    </option>
  </component>
</project>
ShangHaiMesParent/.idea/encodings.xml
New file
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="Encoding">
    <file url="file://$PROJECT_DIR$/common/servicebase/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/common/springsecurity/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/common/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/common/src/main/resources" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/gateway/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/moduleService/CacheGlassModule/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/moduleService/CacheVerticalGlassModule/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/moduleService/DeviceInteractionModule/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/moduleService/GlassStorageModule/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/moduleService/LoadGlassModule/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/moduleService/TemperingGlassModule/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/moduleService/UnLoadGlassModule/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/moduleService/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/moduleService/src/main/resources" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
    <file url="file://$PROJECT_DIR$/../../Work/北玻/apache-maven-3.3.9/repository/org/springframework/boot/spring-boot-starter-parent/2.1.8.RELEASE/src/main/resources" charset="UTF-8" />
  </component>
</project>
ShangHaiMesParent/.idea/inspectionProfiles/Project_Default.xml
New file
@@ -0,0 +1,26 @@
<component name="InspectionProjectProfileManager">
  <profile version="1.0">
    <option name="myName" value="Project Default" />
    <inspection_tool class="AliAccessStaticViaInstance" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaAbstractClassShouldStartWithAbstractNaming" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaAvoidApacheBeanUtilsCopy" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaAvoidCallStaticSimpleDateFormat" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaAvoidComplexCondition" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaAvoidNewDateGetTime" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaAvoidPatternCompileInMethod" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaAvoidUseTimer" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaClassMustHaveAuthor" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaLockShouldWithTryFinally" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaMethodTooLong" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaPackageNaming" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaSneakyThrowsWithoutExceptionType" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaTestClassShouldEndWithTestNaming" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaTransactionMustHaveRollback" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="AlibabaUseRightCaseForDateFormat" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
      <Languages>
        <language minSize="106" name="Java" />
      </Languages>
    </inspection_tool>
  </profile>
</component>
ShangHaiMesParent/.idea/jarRepositories.xml
New file
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="RemoteRepositoriesConfiguration">
    <remote-repository>
      <option name="id" value="central" />
      <option name="name" value="Central Repository" />
      <option name="url" value="https://repo.maven.apache.org/maven2" />
    </remote-repository>
    <remote-repository>
      <option name="id" value="central" />
      <option name="name" value="Maven Central repository" />
      <option name="url" value="https://repo1.maven.org/maven2" />
    </remote-repository>
    <remote-repository>
      <option name="id" value="central" />
      <option name="name" value="Central Repository" />
      <option name="url" value="http://maven.aliyun.com/nexus/content/groups/public" />
    </remote-repository>
    <remote-repository>
      <option name="id" value="jboss.community" />
      <option name="name" value="JBoss Community repository" />
      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
    </remote-repository>
    <remote-repository>
      <option name="id" value="nexus-aliyun" />
      <option name="name" value="Nexus aliyun" />
      <option name="url" value="https://maven.aliyun.com/repository/public" />
    </remote-repository>
    <remote-repository>
      <option name="id" value="spring" />
      <option name="name" value="spring" />
      <option name="url" value="https://maven.aliyun.com/repository/spring" />
    </remote-repository>
  </component>
</project>
ShangHaiMesParent/.idea/libraries/servicebase_1_0_SNAPSHOT.xml
New file
@@ -0,0 +1,9 @@
<component name="libraryTable">
  <library name="servicebase-1.0-SNAPSHOT">
    <CLASSES>
      <root url="jar://$PROJECT_DIR$/common/servicebase/target/servicebase-1.0-SNAPSHOT.jar!/" />
    </CLASSES>
    <JAVADOC />
    <SOURCES />
  </library>
</component>
ShangHaiMesParent/.idea/libraries/springsecurity_1_0_SNAPSHOT.xml
New file
@@ -0,0 +1,9 @@
<component name="libraryTable">
  <library name="springsecurity-1.0-SNAPSHOT">
    <CLASSES>
      <root url="jar://$PROJECT_DIR$/common/springsecurity/target/springsecurity-1.0-SNAPSHOT.jar!/" />
    </CLASSES>
    <JAVADOC />
    <SOURCES />
  </library>
</component>
ShangHaiMesParent/.idea/misc.xml
New file
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ExternalStorageConfigurationManager" enabled="true" />
  <component name="MavenProjectsManager">
    <option name="originalFiles">
      <list>
        <option value="$PROJECT_DIR$/pom.xml" />
        <option value="$PROJECT_DIR$/common/springsecurity/pom.xml" />
      </list>
    </option>
    <option name="ignoredFiles">
      <set>
        <option value="$PROJECT_DIR$/moduleService/CacheVerticalGlassModule/pom.xml" />
      </set>
    </option>
  </component>
  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
</project>
ShangHaiMesParent/.idea/modules.xml
New file
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ProjectModuleManager">
    <modules>
      <module fileurl="file://$PROJECT_DIR$/moduleService/CacheGlassModule/cacheGlass.iml" filepath="$PROJECT_DIR$/moduleService/CacheGlassModule/cacheGlass.iml" />
    </modules>
  </component>
</project>
ShangHaiMesParent/.idea/uiDesigner.xml
New file
@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="Palette2">
    <group name="Swing">
      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
      </item>
      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
      </item>
      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
      </item>
      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
      </item>
      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
        <initial-values>
          <property name="text" value="Button" />
        </initial-values>
      </item>
      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
        <initial-values>
          <property name="text" value="RadioButton" />
        </initial-values>
      </item>
      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
        <initial-values>
          <property name="text" value="CheckBox" />
        </initial-values>
      </item>
      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
        <initial-values>
          <property name="text" value="Label" />
        </initial-values>
      </item>
      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
          <preferred-size width="150" height="-1" />
        </default-constraints>
      </item>
      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
          <preferred-size width="150" height="-1" />
        </default-constraints>
      </item>
      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
          <preferred-size width="150" height="-1" />
        </default-constraints>
      </item>
      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
          <preferred-size width="150" height="50" />
        </default-constraints>
      </item>
      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
          <preferred-size width="150" height="50" />
        </default-constraints>
      </item>
      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
          <preferred-size width="150" height="50" />
        </default-constraints>
      </item>
      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
      </item>
      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
          <preferred-size width="150" height="50" />
        </default-constraints>
      </item>
      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
          <preferred-size width="150" height="50" />
        </default-constraints>
      </item>
      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
          <preferred-size width="150" height="50" />
        </default-constraints>
      </item>
      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
          <preferred-size width="200" height="200" />
        </default-constraints>
      </item>
      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
          <preferred-size width="200" height="200" />
        </default-constraints>
      </item>
      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
      </item>
      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
      </item>
      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
      </item>
      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
      </item>
      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
          <preferred-size width="-1" height="20" />
        </default-constraints>
      </item>
      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
      </item>
      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
      </item>
    </group>
  </component>
</project>
ShangHaiMesParent/.idea/vcs.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="VcsDirectoryMappings">
    <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
  </component>
</project>
ShangHaiMesParent/JsonFile/PlcCacheGlass.json
New file
@@ -0,0 +1,64 @@
{
   "plcAddressBegin":"DB11.0",
   "plcAddressLenght":"80",
   "dataType":"word",
   "parameteInfor":[
      {
         "codeId": "A06_request_word",
         "addressIndex":"0",
         "addressLenght":"2",
         "ratio":"1",
         "unit":"m/min"
      },
      {
          "codeId": "A05_scanning_ID",
          "addressIndex":"2",
          "addressLenght":"30",
          "ratio":"1",
          "unit":""
       },
       {
          "codeId": "Current_slot",
          "addressIndex":"36",
          "addressLenght":"2",
          "ratio":"1",
          "unit":""
       },
        {
          "codeId": "MES_confirmation_word",
          "addressIndex":"38",
          "addressLenght":"2",
          "ratio":"1",
          "unit":""
       },
       {
          "codeId": "A08_glass_status",
          "addressIndex":"68",
          "addressLenght":"2",
          "ratio":"1",
          "unit":""
       },
       {
          "codeId": "A10_glass_status",
          "addressIndex":"70",
          "addressLenght":"2",
          "ratio":"1",
          "unit":""
       },
       {
          "codeId": "A09_prohibit_film_production",
          "addressIndex":"72",
          "addressLenght":"2",
          "ratio":"1",
          "unit":""
       }
       ,
       {
          "codeId": "A10_prohibit_film_production",
          "addressIndex":"74",
          "addressLenght":"2",
          "ratio":"1",
          "unit":""
       }
   ]
}
ShangHaiMesParent/JsonFile/PlcCleaning.json
New file
@@ -0,0 +1,22 @@
{
   "plcAddressBegin":"DB1.8000",
   "plcAddressLenght":"84",
   "dataType":"word",
   "parameteInfor":[
       {
         "codeId": "edgSpeed",
         "addressIndex": "48",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "thinness",
         "addressIndex": "50",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       }
   ]
}
ShangHaiMesParent/JsonFile/PlcEdging.json
New file
@@ -0,0 +1,190 @@
{
   "plcAddressBegin":"0000",
   "plcAddressLength":"50",
   "requestHead":"000100000006010300000032",
   "parameterInfo":[
       {
         "codeId": "plcRequest",
         "addressIndex": "0",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "plcRequestID",
         "addressIndex": "2",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "plcReport",
         "addressIndex": "10",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "plcReportID",
         "addressIndex": "12",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
     {
       "codeId": "plcReport2",
       "addressIndex": "16",
       "addressLength": "2",
       "type": "word",
       "unit": ""
     },
     {
       "codeId": "plcReportID2",
       "addressIndex": "18",
       "addressLength": "2",
       "type": "word",
       "unit": ""
     },
       {
         "codeId": "mesSend",
         "addressIndex": "20",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "mesSendID",
         "addressIndex": "22",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "length",
         "addressIndex": "24",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "width",
         "addressIndex": "26",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "thickness",
         "addressIndex": "28",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "mesConfirm",
         "addressIndex": "38",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "mesConfirmID",
         "addressIndex": "40",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
     {
       "codeId": "mesConfirm2",
       "addressIndex": "46",
       "addressLength": "2",
       "type": "word",
       "unit": ""
     },
     {
       "codeId": "mesConfirmID2",
       "addressIndex": "48",
       "addressLength": "2",
       "type": "word",
       "unit": ""
     },
       {
         "codeId": "alarmStatus",
         "addressIndex": "58",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmWord1",
         "addressIndex": "60",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmWord2",
         "addressIndex": "62",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmWord3",
         "addressIndex": "64",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "machineStatusWord",
         "addressIndex": "68",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut2",
         "addressIndex": "70",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut3",
         "addressIndex": "72",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut4",
         "addressIndex": "74",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut5",
         "addressIndex": "76",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut6",
         "addressIndex": "78",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut7",
         "addressIndex": "80",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       }
     ]
}
ShangHaiMesParent/JsonFile/PlcFlipSlice.json
New file
@@ -0,0 +1,148 @@
{
   "plcAddressBegin":"DB100.0",
   "plcAddressLenght":"568",
   "dataType":"word",
   "parameteInfor":[
       {
         "codeId": "plcRequest",
         "addressIndex": "0",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "plcRequestID",
         "addressIndex": "2",
         "addressLenght": "256",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "plcRequestType",
         "addressIndex": "258",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby20",
         "addressIndex": "260",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby21",
         "addressIndex": "262",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "plcReport",
         "addressIndex": "264",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "plcReportID",
         "addressIndex": "266",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby25",
         "addressIndex": "268",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby26",
         "addressIndex": "270",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby27",
         "addressIndex": "272",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "mesSend",
         "addressIndex": "274",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "mesSendID",
         "addressIndex": "276",
         "addressLenght": "256",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "length",
         "addressIndex": "532",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
     {
       "codeId": "width",
       "addressIndex": "534",
       "addressLenght": "2",
       "ratio": "1",
       "unit": ""
     },
     {
       "codeId": "thickness",
       "addressIndex": "536",
       "addressLenght": "2",
       "ratio": "1",
       "unit": ""
     },
     {
       "codeId": "standby28",
       "addressIndex": "538",
       "addressLenght": "2",
       "ratio": "1",
       "unit": ""
     },
       {
         "codeId": "mesSendType",
         "addressIndex": "540",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby30",
         "addressIndex": "542",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby31",
         "addressIndex": "544",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby32",
         "addressIndex": "546",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       }
   ]
}
ShangHaiMesParent/JsonFile/PlcLamination.json
New file
@@ -0,0 +1,86 @@
{
   "plcAddressBegin":"DB44.0",
   "plcAddressLenght":"22",
   "dataType":"word",
   "parameteInfor":[
       {
         "codeId": "plcRequest",
         "addressIndex": "0",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "plcReport",
         "addressIndex": "2",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "mesSend",
         "addressIndex": "4",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "mesSendID",
         "addressIndex": "6",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "length",
         "addressIndex": "8",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
     {
       "codeId": "width",
       "addressIndex": "10",
       "addressLenght": "2",
       "ratio": "1",
       "unit": ""
     },
     {
       "codeId": "thickness",
       "addressIndex": "12",
       "addressLenght": "2",
       "ratio": "1",
       "unit": ""
     },
       {
         "codeId": "mesConfirm",
         "addressIndex": "14",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "mesConfirmID",
         "addressIndex": "16",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "alarmStatus",
         "addressIndex": "18",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "machineStatusWord",
         "addressIndex": "20",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       }
   ]
}
ShangHaiMesParent/JsonFile/PlcLoad.json
New file
@@ -0,0 +1,134 @@
{
   "plcAddressBegin":"0000",
   "plcAddressLength":"50",
   "requestHead":"000100000006010300000032",
   "parameterInfo":[
       {
         "codeId": "plcRequest",
         "addressIndex": "0",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "plcRequestID",
         "addressIndex": "2",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "plcReport",
         "addressIndex": "10",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "plcReportID",
         "addressIndex": "12",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "mesSend",
         "addressIndex": "20",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "mesSendCount",
         "addressIndex": "22",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "mesConfirm",
         "addressIndex": "40",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmStatus",
         "addressIndex": "62",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmWord1",
         "addressIndex": "64",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmWord2",
         "addressIndex": "66",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmWord3",
         "addressIndex": "68",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "machineStatusWord",
         "addressIndex": "70",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut2",
         "addressIndex": "72",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut3",
         "addressIndex": "74",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut4",
         "addressIndex": "76",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut5",
         "addressIndex": "78",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut6",
         "addressIndex": "80",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut7",
         "addressIndex": "82",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       }
     ]
}
ShangHaiMesParent/JsonFile/PlcLoad2.json
New file
@@ -0,0 +1,134 @@
{
   "plcAddressBegin":"0000",
   "plcAddressLength":"50",
   "requestHead":"000100000006010300000032",
   "parameterInfo":[
       {
         "codeId": "plcRequest",
         "addressIndex": "2",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "plcRequestID",
         "addressIndex": "4",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "plcReport",
         "addressIndex": "10",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "plcReportID",
         "addressIndex": "12",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "mesSend",
         "addressIndex": "20",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "mesSendCount",
         "addressIndex": "22",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "mesConfirm",
         "addressIndex": "40",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmStatus",
         "addressIndex": "62",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmWord1",
         "addressIndex": "64",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmWord2",
         "addressIndex": "66",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmWord3",
         "addressIndex": "68",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "machineStatusWord",
         "addressIndex": "70",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut2",
         "addressIndex": "72",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut3",
         "addressIndex": "74",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut4",
         "addressIndex": "76",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut5",
         "addressIndex": "78",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut6",
         "addressIndex": "80",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut7",
         "addressIndex": "82",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       }
     ]
}
ShangHaiMesParent/JsonFile/PlcMarking.json
New file
@@ -0,0 +1,318 @@
{
   "plcAddressBegin":"DB14.0",
   "plcAddressLenght":"1096",
   "dataType":"word",
   "parameteInfor":[
       {
         "codeId": "plcRequest",
         "addressIndex": "0",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "plcRequestID",
         "addressIndex": "2",
         "addressLenght": "4",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby19",
         "addressIndex": "6",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby20",
         "addressIndex": "8",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby21",
         "addressIndex": "10",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "plcReport",
         "addressIndex": "12",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "plcReportID",
         "addressIndex": "14",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby25",
         "addressIndex": "18",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby26",
         "addressIndex": "20",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby27",
         "addressIndex": "22",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "mesSend",
         "addressIndex": "24",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "mesSendID",
         "addressIndex": "26",
         "addressLenght": "4",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "drawingMark",
         "addressIndex": "30",
         "addressLenght": "256",
         "ratio": "1",
         "unit": ""
       },
     {
       "codeId": "drawingMark2",
       "addressIndex": "258",
       "addressLenght": "256",
       "ratio": "1",
       "unit": ""
     },
     {
       "codeId": "drawingMark3",
       "addressIndex": "542",
       "addressLenght": "256",
       "ratio": "1",
       "unit": ""
     },
     {
       "codeId": "drawingMark4",
       "addressIndex": "798",
       "addressLenght": "236",
       "ratio": "1",
       "unit": ""
     },
       {
         "codeId": "isMark",
         "addressIndex": "1034",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "width(OutOfService)",
         "addressIndex": "1036",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "length(OutOfService)",
         "addressIndex": "1038",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "thickness(OutOfService)",
         "addressIndex": "1040",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "sumCount(OutOfService)",
         "addressIndex": "1042",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby34",
         "addressIndex": "1044",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "markingMode",
         "addressIndex": "1046",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby36",
         "addressIndex": "1048",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "mesConfirm",
         "addressIndex": "1050",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "mesConfirmID",
         "addressIndex": "1052",
         "addressLenght": "4",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby39",
         "addressIndex": "1056",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby40",
         "addressIndex": "1058",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby41",
         "addressIndex": "1060",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby42",
         "addressIndex": "1062",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby43",
         "addressIndex": "1064",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby44",
         "addressIndex": "1066",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "MesTaskStatus",
         "addressIndex": "1068",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby46",
         "addressIndex": "1070",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "alarmStatus",
         "addressIndex": "1072",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "alarmWord1",
         "addressIndex": "1074",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "alarmWord2",
         "addressIndex": "1076",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "alarmWord3",
         "addressIndex": "1078",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "alarmWord4",
         "addressIndex": "1080",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "machineStatusWord",
         "addressIndex": "1082",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "inputOrOut2",
         "addressIndex": "1084",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "inputOrOut3",
         "addressIndex": "1086",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "inputOrOut4",
         "addressIndex": "1088",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "inputOrOut5",
         "addressIndex": "1090",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       }
   ]
}
ShangHaiMesParent/JsonFile/PlcRotate.json
New file
@@ -0,0 +1,169 @@
{
   "plcAddressBegin":"DB100.0",
   "plcAddressLenght":"554",
   "dataType":"word",
   "parameteInfor":[
       {
         "codeId": "plcRequest",
         "addressIndex": "0",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "plcRequestID",
         "addressIndex": "2",
         "addressLenght": "256",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "plcRequestType",
         "addressIndex": "258",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby20",
         "addressIndex": "260",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby21",
         "addressIndex": "262",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "plcReport",
         "addressIndex": "264",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "plcReportID",
         "addressIndex": "266",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby25",
         "addressIndex": "268",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby26",
         "addressIndex": "270",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby27",
         "addressIndex": "272",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "mesSend",
         "addressIndex": "274",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "mesSendID",
         "addressIndex": "276",
         "addressLenght": "256",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "length",
         "addressIndex": "532",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
     {
       "codeId": "width",
       "addressIndex": "534",
       "addressLenght": "2",
       "ratio": "1",
       "unit": ""
     },
     {
       "codeId": "thickness",
       "addressIndex": "536",
       "addressLenght": "2",
       "ratio": "1",
       "unit": ""
     },
     {
       "codeId": "rotateType",
       "addressIndex": "538",
       "addressLenght": "2",
       "ratio": "1",
       "unit": ""
     },
       {
         "codeId": "mesSendType",
         "addressIndex": "540",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby30",
         "addressIndex": "542",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby31",
         "addressIndex": "544",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
       {
         "codeId": "standby32",
         "addressIndex": "546",
         "addressLenght": "2",
         "ratio": "1",
         "unit": ""
       },
     {
       "codeId": "mesConfirm",
       "addressIndex": "548",
       "addressLenght": "2",
       "ratio": "1",
       "unit": ""
     },
     {
       "codeId": "mesConfirmID",
       "addressIndex": "550",
       "addressLenght": "2",
       "ratio": "1",
       "unit": ""
     },
     {
       "codeId": "standby35",
       "addressIndex": "552",
       "addressLenght": "2",
       "ratio": "1",
       "unit": ""
     }
   ]
}
ShangHaiMesParent/JsonFile/PlcSilkScreen.json
New file
@@ -0,0 +1,184 @@
{
   "plcAddressBegin":"0000",
   "plcAddressLength":"40",
   "requestHead":"000100000006010300000028",
   "parameterInfo":[
       {
         "codeId": "plcRequest",
         "addressIndex": "0",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "plcRequestID",
         "addressIndex": "2",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "plcReport",
         "addressIndex": "10",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "plcReportID",
         "addressIndex": "12",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "mesSend",
         "addressIndex": "20",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "mesSendID",
         "addressIndex": "22",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "length",
         "addressIndex": "24",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "width",
         "addressIndex": "26",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "thickness",
         "addressIndex": "28",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "X",
         "addressIndex": "30",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "Y",
         "addressIndex": "32",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "isSilkScreen",
         "addressIndex": "34",
         "addressLength": "2",
         "type": "word",
         "unit": ""
        },
       {
         "codeId": "mesConfirm",
         "addressIndex": "40",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "mesConfirmID",
         "addressIndex": "42",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmStatus",
         "addressIndex": "60",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmWord1",
         "addressIndex": "62",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmWord2",
         "addressIndex": "64",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "alarmWord3",
         "addressIndex": "66",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "machineStatusWord",
         "addressIndex": "68",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut2",
         "addressIndex": "70",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut3",
         "addressIndex": "72",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut4",
         "addressIndex": "74",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut5",
         "addressIndex": "76",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut6",
         "addressIndex": "78",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       },
       {
         "codeId": "inputOrOut7",
         "addressIndex": "80",
         "addressLength": "2",
         "type": "word",
         "unit": ""
       }
     ]
}
ShangHaiMesParent/common/pom.xml
New file
@@ -0,0 +1,217 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ShangHaiMesParent</artifactId>
        <groupId>com.mes</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>common</artifactId>
    <packaging>pom</packaging>
    <modules>
        <module>servicebase</module>
<!--        <module>springsecurity</module>-->
    </modules>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--        mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.github.yulichang</groupId>
            <artifactId>mybatis-plus-join-boot-starter</artifactId>
            <version>1.4.8</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.12</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <!--    导入mysql驱动    -->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>
        <!--代码生成工具-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.0</version>
            <exclusions>
                <exclusion>
                    <groupId>com.alibaba</groupId>
                    <artifactId>fastjson</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.8</version>
        </dependency>
        <!--  数据库设计文档生成工具-->
        <dependency>
            <groupId>cn.smallbun.screw</groupId>
            <artifactId>screw-core</artifactId>
            <version>1.0.5</version>
            <exclusions>
                <exclusion>
                    <groupId>com.alibaba</groupId>
                    <artifactId>fastjson</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--        2.0~2.2    Knife4j 2.0.0 ~ 2.0.6-->
        <!--        <dependency>-->
        <!--            <groupId>com.github.xiaoymin</groupId>-->
        <!--            <artifactId>knife4j-spring-boot-starter</artifactId>-->
        <!--            <version>2.0.6</version>-->
        <!--        </dependency>-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.7.0</version>
        </dependency>
        <!--hutool java验证方法类-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.4.0</version>
        </dependency>
        <dependency>
            <groupId>com.github.xingshuangs</groupId>
            <artifactId>iot-communication</artifactId>
            <version>1.4.2</version>
        </dependency>
        <!--引入redis,排除lettuce的引用-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 引入Jedis客戶端-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.33</version>
        </dependency>
        <!--        <dependency>-->
        <!--            <groupId>com.github.yulichang</groupId>-->
        <!--            <artifactId>mybatis-plus-join</artifactId>-->
        <!--            <version>1.2.4</version>-->
        <!--        </dependency>-->
        <dependency>
            <groupId>com.github.yulichang</groupId>
            <artifactId>mybatis-plus-join-boot-starter</artifactId>
            <version>1.4.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>
</project>
ShangHaiMesParent/common/servicebase/pom.xml
New file
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>common</artifactId>
        <groupId>com.mes</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>servicebase</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
            <version>6.4.0.jre8</version>
        </dependency>
        <dependency>
            <groupId>com.github.s7connector</groupId>
            <artifactId>s7connector</artifactId>
            <version>2.1</version>
        </dependency>
    </dependencies>
</project>
ShangHaiMesParent/common/servicebase/servicebase1.iml
New file
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
</module>
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/config/Const.java
New file
@@ -0,0 +1,172 @@
package com.mes.common.config;
import java.util.Arrays;
import java.util.List;
/**
 * @Author : zhoush
 * @Date: 2024/4/24 10:33
 * @Description:
 */
public class Const {
    //默认密码
    public static final String DEFULT_PASSWORD = "123456";
    //默认角色
    public static final Long DEFULT_ROLE = 1L;
    /**
     * 磨边清洗前
     */
    /**
     * A09出片目标位置  d02卧转立    2001
     * A10出片目标位置  d05卧转立    2002
     */
    public static final Integer OUT_TARGET_POSITION_ZERO = 0;
    public static final Integer A09_OUT_TARGET_POSITION = 2001;
    public static final Integer A10_OUT_TARGET_POSITION = 2002;
    /**
     * A09出片目标位置  d02卧转立 钢化出片    3001
     * A10出片目标位置  d05卧转立 人工出片    3002
     */
    public static final Integer TEMPERING_OUT_TARGET_POSITION = 3001;
    public static final Integer ARTIFICIAL_OUT_TARGET_POSITION = 3002;
    /**
     * 卧式理片笼详情表玻璃状态
     * 识别后成功状态0
     * 识别后成功进笼的状态100
     * 出片任务101
     * 人工下片102
     * 出片中103
     * 调度中104
     * 拿走200
     * 破损201
     */
    public static final Integer GLASS_STATE_NEW = 0;
    public static final Integer GLASS_STATE_IN = 100;
    public static final Integer GLASS_STATE_OUT = 101;
    public static final Integer GLASS_STATE_ARTIFICIAL = 102;
    public static final Integer GLASS_STATE_OUT_ING = 103;
    public static final Integer GLASS_STATE_SCHEDULE_ING = 104;
    public static final Integer GLASS_STATE_TAKE = 200;
    public static final Integer GLASS_STATE_DAMAGE = 201;
    public static final List<Integer> GLASS_STATE_IN_ALL = Arrays.asList(100, 102, 103, 104);
    public static final List<Integer> GLASS_STATE_IN_ALL_ZERO = Arrays.asList(0, 100, 102, 103, 104);
    /**
     * 卧式理片笼详情表玻璃状态
     * 进片任务1
     * 出片任务2
     */
    public static final Integer GLASS_CACHE_TYPE_IN = 1;
    public static final Integer GLASS_CACHE_TYPE_OUT = 2;
    public static final Integer GLASS_CACHE_TYPE_THROUGH = 3;
    public static final List<Integer> GLASS_CACHE_TYPE_OUT_ALL = Arrays.asList(2, 3);
    /**
     * 磨边任务玻璃状态
     * 进片任务1
     * 出片任务2
     */
    public static final Integer EDG_GLASS_BEFORE = 0;
    public static final Integer EDG_GLASS_START = 1;
    public static final Integer EDG_GLASS_SUCCESS = 2;
    /**
     * 磨边任务玻璃状态
     * 1单机自动状态
     * 2联机自动状态
     * 3手动状态
     */
    public static final Integer BIG_STORAGE_STAND_ALONE = 1;
    public static final Integer BIG_STORAGE_ONLINE = 2;
    public static final Integer BIG_STORAGE_MT = 3;
    /**
     * 大理片笼请求
     * 0 大理片笼无请求
     * 1 大理片笼进片请求
     */
    public static final String BIG_STORAGE_REQUEST = "0";
    public static final String BIG_STORAGE_REQUEST_IN = "1";
    /**
     * 卧转立进片请求
     * 1 任务生成
     * 2 卧转立进片完成
     * 3 大车进片完成
     * 4 大理片笼进片完成
     * 5 大理片笼进片失败
     * 6 大理片笼进片破损
     */
    public static final Integer BIG_STORAGE_IN_NEW = 1;
    public static final Integer BIG_STORAGE_IN_UP = 2;
    public static final Integer BIG_STORAGE_IN_CAR = 3;
    public static final Integer BIG_STORAGE_IN_SLOT = 4;
    public static final Integer BIG_STORAGE_IN_ERROR = 5;
    public static final Integer BIG_STORAGE_IN_DAMAGE = 6;
    public static final List<Integer> BIG_STORAGE_IN_UP_ALL = Arrays.asList(1, 2);
    /**
     * 卧转立出片请求
     * 1 任务生成
     * 2 玻璃进大车完成
     * 3 大车出片完成
     * 4 大理片笼进片失败
     * 5 大理片笼进片破损
     */
    public static final Integer BIG_STORAGE_OUT_NEW = 1;
    public static final Integer BIG_STORAGE_OUT_CAR = 2;
    public static final Integer BIG_STORAGE_OUT_SUCCESS = 3;
    public static final Integer BIG_STORAGE_OUT_ERROR = 4;
    public static final Integer BIG_STORAGE_OUT_DAMAGE = 5;
    public static final List<Integer> BIG_STORAGE_OUT_ALL = Arrays.asList(2, 3);
    /**
     * 卧转立出片请求
     * 1 上车等待
     * 2 上车启动
     */
    public static final Integer BIG_STORAGE_IN_WAIT = 1;
    public static final Integer BIG_STORAGE_IN_RUN = 2;
    /**
     * 钢化小片表
     * -1 生成任务
     * 0  出片完成
     * 1  摆片完成
     * 2  进炉完成
     * 3  钢化完成
     * 4  出片完成
     * 5  破损
     * 6  拿走
     */
    public static final Integer TEMPERING_NEW = -1;
    public static final Integer TEMPERING_OUT = 0;
    public static final Integer TEMPERING_DROP = 1;
    public static final Integer TEMPERING_START = 2;
    public static final Integer TEMPERING_SUCCESS = 3;
    public static final Integer TEMPERING_END = 4;
    public static final Integer TEMPERING_DAMAGE = 5;
    public static final Integer TEMPERING_TAKE = 6;
    /**
     * 下片
     */
    /**
     * 执行线路格子信息
     */
    public static final List<Integer> G06_WORK_STATION = Arrays.asList(1, 2, 3);
    public static final List<Integer> G11_WORK_STATION = Arrays.asList(4, 5, 6);
    public static final int G13_WORK_STATION = 7;
    /**
     * 启用 1
     * 禁用 0
     */
    public static final Integer SLOT_ON = 1;
    public static final Integer SLOT_OFF = 0;
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/config/MybatisPlusConfig.java
New file
@@ -0,0 +1,30 @@
package com.mes.common.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @author zhoush
 * @Date 2024/1/26 13:44
 */
@MapperScan(basePackages = "com.mes.*.mapper")
@Configuration
public class MybatisPlusConfig {
    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/config/Swagger2Config.java
New file
@@ -0,0 +1,78 @@
package com.mes.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
 * @author zhan_py
 * @Date 2024/1/26 16:11
 * Swagger2配置信息
 */
@Configuration
public class Swagger2Config {
    @Bean
    public Docket webApiConfig() {
        List<Parameter> pars = new ArrayList<>();
        ParameterBuilder tokenPar = new ParameterBuilder();
        tokenPar.name("userId")
                .description("用户token")
                //.defaultValue(JwtHelper.createToken(1L, "admin"))
                .defaultValue("1")
                .modelRef(new ModelRef("string"))
                .parameterType("header")
                .required(false)
                .build();
        pars.add(tokenPar.build());
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("webApi")
                .apiInfo(webApiInfo())
                .select()
                //只显示api路径下的页面
                .apis(RequestHandlerSelectors.basePackage("com.mes"))
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(pars)
                .securitySchemes(Collections.EMPTY_LIST)
                .securityContexts(Arrays.asList(securityContext()));
    }
    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.any())
                .build();
    }
    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return Arrays.asList(new SecurityReference("Authorization", authorizationScopes));
    }
    private ApiInfo webApiInfo() {
        return new ApiInfoBuilder()
                .title("网站-API文档")
                .description("本文档描述了mes网站微服务接口定义")
                .version("1.0")
                .contact(new Contact("zhan_py", "", ""))
                .build();
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/config/WebSocketConfig.java
New file
@@ -0,0 +1,21 @@
package com.mes.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
 * @author SNG-010
 */
@Configuration
public class WebSocketConfig {
    /**
     * bean注册:会自动扫描带有@ServerEndpoint注解声明的Websocket Endpoint(端点),注册成为Websocket bean。
     * 要注意,如果项目使用外置的servlet容器,而不是直接使用springboot内置容器的话,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理。
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/exception/GlobalExceptionHandler.java
New file
@@ -0,0 +1,32 @@
package com.mes.common.exception;
import com.mes.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
 * @author zhoush
 * @Date 2024/1/26 15:31
 */
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 如果是serviceExcaption,则调用该方法
     */
    @ExceptionHandler(ServiceException.class)
    @ResponseBody
    public Result handle(ServiceException se) {
        return Result.error(se.getCode(), se.getMessage());
    }
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result<Object> error(Exception e) {
        e.printStackTrace();
        return Result.error();
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/exception/ServiceException.java
New file
@@ -0,0 +1,14 @@
package com.mes.common.exception;
import com.mes.utils.ResultCodeEnum;
import lombok.Getter;
@Getter
public class ServiceException extends RuntimeException {
    private Integer code;
    public ServiceException(ResultCodeEnum resultCodeEnum, String msg) {
        super(msg);
        this.code = resultCodeEnum.getCode();
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/common/handler/MyMetaObjectHandler.java
New file
@@ -0,0 +1,22 @@
package com.mes.common.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        //属性名称,不是字段名称
        this.setFieldValByName("gmtCreate", new Date(), metaObject);
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/device/PlcBitInfo.java
New file
@@ -0,0 +1,85 @@
package com.mes.device;
public class PlcBitInfo {
    public PlcBitInfo(String startAddress) {
        this.startAddress = startAddress;
    }
    private String startAddress;
    // 参数标识
    private String codeId;
    // 参数名称
    private String name;
    // 读取 参数值
    private Boolean value;
    // 参数地址
    private int addressIndex;
    public String getCodeId() {
        return this.codeId;
    }
    public void setCodeId(String codeId) {
        this.codeId = codeId;
    }
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Boolean getValue() {
        return this.value;
    }
    public void setValue(Boolean value) {
        this.value = value;
    }
    public int getAddressIndex() {
        return this.addressIndex;
    }
    /**
     * 获取地址
     *
     * @param index 索引地址
     */
    public String getAddress(int index) {
        String[] stringdatas = this.startAddress.trim().split("\\.");
        if (stringdatas.length < 2) {
            return null;
        }
        int dbwindex = 0;
        int bitindex = 0;
        if (stringdatas.length == 3) {
            dbwindex = Integer.parseInt(stringdatas[1]);
            bitindex = Integer.parseInt(stringdatas[2]);
        } else
        {
            return null;
        }
        dbwindex += index / 8;
        bitindex += index % 8;
        return stringdatas[0] + "." + dbwindex + "." + bitindex;
    }
    /**
     * 获取地址
     *
     */
    public String getAddress() {
      return   getAddress(this.addressIndex);
    }
    public void setAddressIndex(int addressindex) {
        this.addressIndex = addressindex;
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/device/PlcBitObject.java
New file
@@ -0,0 +1,124 @@
package com.mes.device;
import java.util.*;
public class PlcBitObject {
    // 该模块数据类型,数据起始位置
    private String plcAddressBegin;
    // 数据地址长度:第一参数到最后一个参数的长度
    private int plcAddressLength;
    //private ArrayList<PlcBitInfo> plcBitList;
    private LinkedHashMap<String,PlcBitInfo> plcBitMap;
    /**
     * @return 数据区开始地址
     */
    public String getPlcAddressBegin() {
        return plcAddressBegin;
    }
    /**
     * @param plcAddressBegin 设置数据区开始地址
     */
    public void setPlcAddressBegin(String plcAddressBegin) {
        this.plcAddressBegin = plcAddressBegin;
    }
    /**
     * @return 数据区 读取所有数据所需的长度(以byte类型为基准)
     */
    public int getPlcAddressLength() {
        return plcAddressLength;
    }
    /**
     * @return 设置:数据区 读取所有数据所需的长度(以byte类型为基准)
     */
    public void setPlcAddressLength(int plcAddressLength) {
        this.plcAddressLength = plcAddressLength;
    }
    /**
     * @return 获取参数实例集合
     */
    public LinkedHashMap<String,PlcBitInfo> getBitMap() {
        return plcBitMap;
    }
    /**
     * 根据参数标识 获取某个参数实例
     *
     * @param codeid 参数标识
     * @return 获取某个参数实例
     */
    public PlcBitInfo getPlcBit(String codeid) {
        if (plcBitMap != null) {
            /*for (PlcBitInfo plcbitInfo : plcBitList) {
                if (plcbitInfo.getCodeId().equals(codeid))
                    return plcbitInfo;
            }*/
            return plcBitMap.get(codeid);
        } else
        {
            return null;
        }
    }
    /**
     * 根据参数标识 获取某个参数实例
     *
     * @param codeids 参数标识
     * @return 获取某个参数实例
     */
    public List<Boolean> getPlcBitValues(List<String> codeids) {
        List<Boolean> arrayList = new ArrayList<>();
        if (plcBitMap != null) {
            for (String codeId : codeids) { // 按照传入参数的顺序遍历
                    arrayList.add(plcBitMap.get(codeId).getValue());
            }
        }
        return arrayList;
    }
    public List<String> getAddressListByCodeId(List<String> codeIdList) {
        List<String> addressList = new ArrayList<>();
        for (String codeId : codeIdList) {
            addressList.add(plcBitMap.get(codeId).getAddress());
        }
        return addressList;
    }
    /**
     * 添加参数实例
     *
     * @param param 参数实例
     */
    public void addPlcBit(PlcBitInfo param) {
        if (plcBitMap != null) {
            plcBitMap.put(param.getCodeId(), param);
        }
        else {
            plcBitMap = new LinkedHashMap<String,PlcBitInfo>();
            plcBitMap.put(param.getCodeId(),param);
        }
    }
    /**
     * 根据PLC返回的数据 给参数实例赋值
     *
     * @param plcValueArray PLC读取回来的byte类型数据集合
     */
    public void setPlcBitList(List<Boolean> plcValueArray) {
        if (plcBitMap != null) {
            Collection<PlcBitInfo> values=plcBitMap.values();
            for (PlcBitInfo plcbitInfo : values) {
                plcbitInfo.setValue(plcValueArray.get(plcbitInfo.getAddressIndex()));
            }
        }
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/device/PlcParameterInfo.java
New file
@@ -0,0 +1,126 @@
package com.mes.device;
public class PlcParameterInfo {
    public PlcParameterInfo(String startAddress) {
        this.startAddress = startAddress;
    }
    private String startAddress;
    // 参数标识
    private String codeId;
    // 参数名称
    private String name;
    // 读取 参数值
    private String value;
    // // 写入 参数值
    // private String writeValue;
    // 参数单位
    private String unit;
    // 参数值转换系数
    private int ratio;
    // 参数地址
    private int addressIndex;
    // 参数地址位长度
    private int addressLength;
    public String getCodeId() {
        return this.codeId;
    }
    public void setCodeId(String codeId) {
        this.codeId = codeId;
    }
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getValue() {
        return this.value;
    }
    public void setValue(String value) {
        this.value = value;
    }
    // public String getWriteValue() {
    //     return this.writeValue;
    // }
    // public void setWriteValue(String writeValue) {
    //     this.writeValue = writeValue;
    // }
    public String getUnit() {
        return this.unit;
    }
    public void setUnit(String unit) {
        this.unit = unit;
    }
    public int getAddressIndex() {
        return this.addressIndex;
    }
    public void setAddressIndex(int addressindex) {
        this.addressIndex = addressindex;
    }
    public int getAddressLength() {
        return this.addressLength;
    }
    public void setAddressLength(int addresslength) {
        this.addressLength = addresslength;
    }
    public int getRatio() {
        return this.ratio;
    }
    public void setRatio(int ratio) {
        this.ratio = ratio;
    }
    /**
     * 获取地址
     *
     * @param index 索引地址
     */
    public String getAddress(int index) {
        String[] stringdatas = this.startAddress.trim().split("\\.");
        int addressLength = this.addressLength;
        if (addressLength < 2) {
            return null;
        }
        int wordindex = Integer.parseInt(stringdatas[1]) + index;
        return stringdatas[0] + "." + wordindex;
      /*  if (addressLength == 2) {
            return stringdatas[0] + "." + wordindex;
        }
        if (addressLength == 14) {
            int wordindex = index;
            int newIndex = wordindex + 13;
            return stringdatas[0] + "." + wordindex + "-" + newIndex;
        }*/
//        return null;
    }
    public String getAddress() {
        return getAddress(this.addressIndex);
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/device/PlcParameterObject.java
New file
@@ -0,0 +1,254 @@
package com.mes.device;
import com.github.s7connector.impl.serializer.converter.StringConverter;
import com.github.xingshuangs.iot.utils.IntegerUtil;
import com.github.xingshuangs.iot.utils.ShortUtil;
import com.mes.service.PlcAgreement;
import com.mes.service.PlcParameter;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Array;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
@Slf4j
public class PlcParameterObject {
    // 该模块数据类型,数据起始位置
    private String plcAddressBegin;
    // 数据地址长度:第一参数到最后一个参数的长度
    private int plcAddressLength;
    private LinkedHashMap<String,PlcParameterInfo> plcParameterMap;
    /**
     * @return 数据区开始地址
     */
    public String getPlcAddressBegin() {
        return plcAddressBegin;
    }
    /**
     * @param plcAddressBegin 设置数据区开始地址
     */
    public void setPlcAddressBegin(String plcAddressBegin) {
        this.plcAddressBegin = plcAddressBegin;
    }
    /**
     * @return 数据区 读取所有数据所需的长度(以byte类型为基准)
     */
    public int getPlcAddressLength() {
        return plcAddressLength;
    }
    /**
     * @return 设置:数据区 读取所有数据所需的长度(以byte类型为基准)
     */
    public void setPlcAddressLength(int plcAddressLength) {
        this.plcAddressLength = plcAddressLength;
    }
    /**
     * @return 获取参数实例集合
     */
    public LinkedHashMap<String,PlcParameterInfo> getPlcParameterMap() {
        return plcParameterMap;
    }
    /**
     * 根据参数标识 获取某个参数实例
     *
     * @param codeid 参数标识
     * @return 获取某个参数实例
     */
    public PlcParameterInfo getPlcParameter(String codeid) {
        if (plcParameterMap != null) {
            return plcParameterMap.get(codeid);
        } else {
            return null;
        }
        /*if (plcParameterList != null) {
            for (PlcParameterInfo plcParameterInfo : plcParameterList) {
                if (plcParameterInfo.getCodeId().equals(codeid))
                    return plcParameterInfo;
            }
            return null;
        } else
            return null;*/
    }
    /**
     * 根据参数标识 获取某个参数实例
     *
     * @param codeids 参数标识
     * @return 获取某个参数实例
     */
    public List<String> getPlcParameterValues(List<String> codeids) {
        List<String> arrayList = new ArrayList<>();
        if (plcParameterMap != null) {
            /*Map<String, PlcParameterInfo> resultMap = new LinkedHashMap<>(); // 使用 LinkedHashMap 保留插入顺序
            for (PlcParameterInfo plcParameterInfo : plcParameterList) {
                if (codeids.contains(plcParameterInfo.getCodeId())) {
                    resultMap.put(plcParameterInfo.getCodeId(), plcParameterInfo);
                }
            }*/
            for (String codeId : codeids) { // 按照传入参数的顺序遍历
                PlcParameterInfo plcParameterInfo = plcParameterMap.get(codeId);
                if (plcParameterInfo != null) {
                    arrayList.add(plcParameterInfo.getValue());
                } else {
                    arrayList.add(null); // 如果找不到对应的值,添加 null
                }
            }
        }
        return arrayList;
    }
    /**
     * 根据参数标识 获取传入参数的plc地址
     *
     * @param codeIdList 参数标识
     * @return 传入参数的plc地址
     */
    public List<String> getAddressListByCodeId(List<String> codeIdList) {
        List<String> addressList = new ArrayList<>();
        if (plcParameterMap!=null)
        {
            for (String codeId : codeIdList) {
                    String address = plcParameterMap.get(codeId).getAddress();
                    if (address != null) {
                        addressList.add(address);
                    }
        }
        }
        return addressList;
    }
    /**
     * 添加参数实例
     *
     * @param param 参数实例
     */
    public void addPlcParameter(PlcParameterInfo param) {
        if (plcParameterMap != null) {
            plcParameterMap.put(param.getCodeId(), param);
        }
        else {
            plcParameterMap =new  LinkedHashMap<String,PlcParameterInfo>();
            plcParameterMap.put(param.getCodeId(), param);
        }
        /*if (plcParameterList != null)
            plcParameterList.add(param);
        else {
            plcParameterList = new ArrayList<PlcParameterInfo>();
            plcParameterList.add(param);
        }*/
    }
    /**
     * 根据PLC返回的数据 给参数实例赋值
     *
     * @param plcValueArray PLC读取回来的byte类型数据集合
     */
    public void setPlcParameterList(byte[] plcValueArray) {
        if (plcParameterMap != null) {
            Collection<PlcParameterInfo> values=  plcParameterMap.values();
            for (PlcParameterInfo plcParameterInfo :values) {
                byte[] valueList = new byte[plcParameterInfo.getAddressLength()];
//                System.out.println(plcParameterInfo.getAddressLength());
                for (int i = 0; i < plcParameterInfo.getAddressLength(); i++) {
                    Array.setByte(valueList, i, plcValueArray[plcParameterInfo.getAddressIndex() + i]);
                }
                if (plcParameterInfo.getAddressLength() == 2) {
                    plcParameterInfo.setValue(String.valueOf(ShortUtil.toUInt16(valueList)));
                } else if (plcParameterInfo.getAddressLength() == 4) {
                    plcParameterInfo.setValue(String.valueOf(IntegerUtil.toUInt32(valueList)));
                }else if(plcParameterInfo.getAddressLength()==256){
                    StringConverter converter = new StringConverter();
                    String s="";
                    String extract1 = converter.extract(s.getClass(),plcValueArray, plcParameterInfo.getAddressIndex(), 0);
                    plcParameterInfo.setValue(extract1);
                }else {
                    plcParameterInfo.setValue((byteToHexString(valueList)));
                }
            }
        }
    }
    /**
     * 把写入值转化为byte[]
     * @param param 参数实例
     * @param data 写入值的字符类型
     */
    public byte[] setValueToBytes(PlcParameterInfo param, String data) {
        if (param.getAddressLength() == 2) {
            return ShortUtil.toByteArray(Integer.parseInt(data));
        } else if (param.getAddressLength() == 4) {
            return IntegerUtil.toByteArray(Long.parseLong(data));
        }
        else if (param.getAddressLength() >10) {
           return data.getBytes();
        } else {
            return data.getBytes();
        }
    }
    /**
     * short类型转byte[]
     *
     * @param s short类型值
     */
    public static byte[] short2byte(short s) {
        byte[] b = new byte[2];
        for (int i = 0; i < 2; i++) {
            int offset = 16 - (i + 1) * 8; //计算偏移量
            b[i] = (byte) ((s >> offset) & 0xff); //把16位分为2个8位进行分别存储
        }
        return b;
    }
    /**
     * byte[]类型转short
     *
     * @param b byte[]类型值
     */
    public static short byte2short(byte[] b) {
        short l = 0;
        for (int i = 0; i < 2; i++) {
            l <<= 8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
            l |= (b[i] & 0xff); //和上面也是一样的  l = l | (b[i]&0xff)
        }
        return l;
    }
    /**
     * byte[]类型转short
     *
     * @param b byte[]类型值
     */
    public static int byte2int(byte[] b) {
        int l = 0;
        for (int i = 0; i < 4; i++) {
            l <<= 8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
            l |= (b[3-i] & 0xff); //和上面也是一样的  l = l | (b[i]&0xff)
        }
        return l;
    }
    public static byte[] int2byte(int s){
        byte[] b = new byte[2];
        for(int i = 0; i < 4; i++){
            int offset = 16 - (i+1)*8; //因为byte占4个字节,所以要计算偏移量
            b[i] = (byte)((s >> offset)&0xff); //把32位分为4个8位进行分别存储
        }
        return b;
    }
    public static String byteToHexString(byte[] bytes) {
        String str = new String(bytes, StandardCharsets.UTF_8).trim();
        return str;
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/entity/request/GeneralRequest.java
New file
@@ -0,0 +1,17 @@
package com.mes.entity.request;
import cn.hutool.db.Page;
import lombok.Data;
/**
 * @Author : zhoush
 * @Date: 2024/4/22 11:21
 * @Description:
 */
@Data
public class GeneralRequest {
    private String key;
    private Page page;
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/service/Communication.java
New file
@@ -0,0 +1,36 @@
package com.mes.service;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.mes.device.PlcParameterInfo;
import com.mes.tools.HexConversion;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.*;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
/**
 * Plc通讯方式 [S7/ModbusTcp]
 */
@Component
@Slf4j
public class Communication {
    /**
     * 方式标识 [S7/ModbusTcp]
     */
    private String type;
    Communication(){
        if("ModbusTcp".equals(type)){
        }else if("S7".equals(type)){
        }
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/service/ModbusTcp.java
New file
@@ -0,0 +1,223 @@
package com.mes.service;
import com.mes.tools.HexConversion;
import com.mes.utils.HexUtil;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import static com.mes.tools.HexConversion.*;
@Component
@Slf4j
public class ModbusTcp {
    //同IP下会有多个协议地址  key=地址区   PlcAgreement为协议内容  plcAgreements为协议组
    private Map<String,PlcAgreement> plcAgreement=new LinkedHashMap<String,PlcAgreement>();
    private String Ip;
    private int Port;
    public Socket socket =null;//通讯
    public String fileName ="";
    public ModbusTcp(){}
    public ModbusTcp(String Ip,int Port,String fileName){
        this.Ip=Ip;
        this.Port=Port;
        this.fileName=fileName;
        try {
            plcAgreement.put(this.fileName,new PlcAgreement(this.fileName));
        } catch (Exception e) {
            log.info("file error:"+this.fileName+",{}",e.getMessage());
        }
    }
    //连接
    public void connect(){
        try {
            this.socket=new Socket(Ip,Port);
            this.socket.setSoTimeout(1000);
        }catch (Exception e) {
            log.info("The IP address of the host cannot be determined:{}",e.getMessage());
        }
    }
    //关闭连接
    public void close(){
        try {
            this.socket.close();
        }catch (Exception e) {
            //log.info("连接关闭异常:{}",e.getMessage());
        }
    }
    //返回连接状态
    public boolean isConnect(){
        try {
            this.socket.isConnected();
        }catch (Exception e) {
            log.info("Connection status exception:{}",this.socket);
        }
        return false;
    }
    //读取数据
    public boolean read(PlcAgreement plcAgreement){
        try {
            if (!this.socket.isConnected()){
               // log.info("通讯连接失败:{}",this.socket.isConnected());
                return false;
            }
            int bufSizes = 0;
            byte[] msgs = new byte[2048];
            byte[] content = new byte[2048];
            //写入读取地址
            DataOutputStream outToServer = new DataOutputStream(this.socket.getOutputStream());
            outToServer.write(HexConversion.stringToInt(plcAgreement.requestHead));
            outToServer.flush();
            //读取内容
            DataInputStream in = new DataInputStream(this.socket.getInputStream());
            bufSizes = in.read(msgs);
            if(bufSizes<plcAgreement.plcAddressLength+9){
                log.info("Read byte length <1:{},content:{}",bufSizes,msgs);
                return false;
            }
            content=Arrays.copyOfRange(msgs,9,2048);
            //获取参数值
            Map<String, PlcParameter> plcParameters=plcAgreement.getPlcParameters();
            for (String key:plcParameters.keySet()){
                PlcParameter plcParameter=plcParameters.get(key);
                if("bit".equals(plcParameter.getType())){
                    byte font=content[plcParameter.getAddressStart()];
                    String[] fontBitString=String.format("%8s", Integer.toBinaryString((int)font)).replace(" ", "0").split("");
                    byte[] bit=new byte[1];
                    bit[0]=Byte.parseByte(fontBitString[plcParameter.getAddressLength()]);
                    plcParameter.setReadByte(bit);
                }else{
                    plcParameter.setReadByte(Arrays.copyOfRange(content,plcParameter.getAddressStart(),(plcParameter.getAddressStart()+plcParameter.getAddressLength())));
                }
            }
            return true;
        }catch (Exception e) {
            //log.info("读取异常:{}",plcAgreement);
        }
        return false;
    }
    //写入数据
    public void write(PlcParameter plcParameter){
        try {
            if (plcParameter.getWriteValue() != null && !"".equals(plcParameter.getWriteValue())) {
                //写入发送数据 0000 0000 0009 0110 0024 0001 02 0006
                byte []sendByte=new byte[13+plcParameter.getAddressLength()];
                byte []sendLength=intToBytesDesc(7+plcParameter.getAddressLength(),2);
                byte []sendAddress=intToBytesDesc(plcParameter.getAddressStart()/2,2);
                byte []sendFontLength=intToBytesDesc(plcParameter.getAddressLength()/2,2);
                byte []sendContent=plcParameter.getWriteByte();
                //byte []sendContent=intToBytesDesc(Integer.parseInt(plcParameter.getWriteValue().toString()),plcParameter.getAddressLength());
                sendByte[4]=sendLength[0];
                sendByte[5]=sendLength[1];
                sendByte[6]=(byte)1;
                sendByte[7]=(byte)16;
                sendByte[8]=sendAddress[0];
                sendByte[9]=sendAddress[1];
                sendByte[10]=sendFontLength[0];
                sendByte[11]=sendFontLength[1];
                sendByte[12]=(byte)plcParameter.getAddressLength();
                for(int i=0;i<sendContent.length;i++){
                    sendByte[i+13]=sendContent[i];
                }
                log.info("sendByte:{}",sendByte);
                DataOutputStream out = new DataOutputStream(this.socket.getOutputStream());
                out.write(sendByte);
                out.flush();
                //log.info("sendByte:{}",sendByte);
            }
        } catch (IOException e) {
            log.info("写入数据异常:{}",plcParameter);
            throw new RuntimeException(e);
        }
    }
    //数据处理
    public void handleData(PlcParameter plcParameter){
        //写入发送数据 0000 0000 0009 0110 0024 0001 02 0006
        try {
            int sendLength=plcParameter.getAddressLength()+7;//发送长度
            byte [] addressLength=intToBytesDesc(plcParameter.getAddressLength(),1);//字节长度
            byte [] addressLengthFont=intToBytesDesc((plcParameter.getAddressLength()/2),2);//字长度
            byte start[]=intToBytesDesc(plcParameter.getAddressStart()/2,2);//起始地址
            byte content[]=intToBytesDesc(Integer.valueOf(plcParameter.getWriteValue().toString()) ,2);//起始地址
            if (sendLength>14&&
                    addressLength.length>0&&
                    addressLengthFont.length>1&&
                    start.length>1&&
                    content.length>1){
                byte head[]=new byte[]{0,0,0,(byte)sendLength,1,16,start[0],start[1],addressLengthFont[0],addressLengthFont[1],addressLength[0],content[0],content[1]};
                this.write(head);
            }else{
                log.info("发送内容不符合: 字节长度 {},字长度:{},起始地址,{},内容:{}",addressLength,addressLengthFont,start,content);
            }
        } catch (Exception e) {
            log.info("数据处理异常: 内容 {}",plcParameter);
        }
    }
    //写入数据
    public void write(byte []sendByte){
        try {
            if (sendByte != null) {
                //写入发送数据
                DataOutputStream out = new DataOutputStream(this.socket.getOutputStream());
                out.write(sendByte);
                out.flush();
                log.info("写入成功: 内容 {}",sendByte);
            }
        } catch (Exception e) {
            log.info("写入失败: 内容 {}",sendByte);
        }
    }
    //写入数据String
    public void writeString(String sendString,String startAddress){
        try {
            String result=message(sendString,startAddress);
            if (result != null && !"".equals(result)) {
                //写入数据
                DataOutputStream out = new DataOutputStream(socket.getOutputStream());
                out.write(HexUtil.stringToInt(result));
                out.flush();
                log.info("写入成功:地址 {},内容 {},字节:{}",startAddress,sendString,HexUtil.stringToInt(result));
                //this.close();
            }
        } catch (Exception e) {
            log.info("写入异常:地址 {},内容 {}",startAddress,sendString);
        }
    }
    //写
    public String message(String senddate, String address) {
        String Herd = "0110" + address;
        int length = senddate.length() / 4;
        String dates = Herd + HexUtil.intTo2ByteHex(length) + HexUtil.intTo1ByteHex(length * 2) + senddate;
        int lengths = dates.length() / 2;
        String date = "00000000" + HexUtil.intTo2ByteHex(lengths) + dates;
        return date;
    }
    public PlcAgreement getPlcAgreement(String key){
        return plcAgreement.get(key);
    }
    public void consoleLogInfo(PlcAgreement thisPlcAgreement){
        String logInfo=this.fileName+"  ";
        Map<String,PlcParameter> plcParameterMap=thisPlcAgreement.getPlcParameters();
        for (String key:plcParameterMap.keySet()) {
            logInfo+=key+":"+plcParameterMap.get(key).getValueString()+",";
        }
        log.info(logInfo);
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/service/PlcAgreement.java
New file
@@ -0,0 +1,113 @@
package com.mes.service;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.mes.device.PlcParameterInfo;
import com.mes.tools.HexConversion;
import com.mes.utils.HexUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.*;
import java.net.Socket;
import java.util.*;
/**
 * Plc协议:协议参数,协议配置,协议请求头,协议类型
 */
@Component
@Slf4j
public class PlcAgreement {
    //public Socket socket =null;//通讯
    /**
     * 协议参数
     */
    private List<String> parameterKeys=new ArrayList<>();
    private Map<String,PlcParameter> parameters=null;
    /**
     * 协议路径
     */
    private String jsonFilePath=null;
    /**
     * 读取起始地址
     */
    public String plcAddressBegin=null;
    /**
     * 读取长度
     */
    public int plcAddressLength=0;
    //类似序列号(4)+协议标志(4)+长度(4)+从站地址(2)+功能代码(2)+起始地址(4)+读取数量(4) "000100000006010300000032"
    public String requestHead=null;
    private PlcAgreement(){}
    PlcAgreement(String fileName){
        //jsonFilePath = "D:/mes/JsonFile/"+fileName+".json";
        jsonFilePath = System.getProperty("user.dir") + "/JsonFile/"+fileName+".json";
        boolean initSuccess=initword();
        //log.info("初始化PlcCacheGlass:"+initSuccess);
    }
    //初始化word
    public boolean initword() {
        try {
            parameters=new LinkedHashMap<String,PlcParameter>();
            FileReader fileReader = new FileReader(jsonFilePath);
            BufferedReader bufferedReader = new BufferedReader(fileReader);
            StringBuilder content = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                content.append(line);
            }
            bufferedReader.close();
            fileReader.close();
            JSONObject jsonFile = new JSONObject(content.toString());
            //log.info("读取内容:{}",jsonFile);
            JSONArray jsonArray = jsonFile.getJSONArray("parameterInfo");
            this.plcAddressBegin=jsonFile.getStr("plcAddressBegin");//设置起始位地址
            this.plcAddressLength=Integer.valueOf(jsonFile.getStr("plcAddressLength"));//设置地址长度
            this.requestHead=jsonFile.getStr("requestHead");//设置请求头部
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject parameterObj = jsonArray.getJSONObject(i);
                String code = parameterObj.getStr("codeId");
                PlcParameter plcParameter = new PlcParameter(
                        code,
                        Integer.valueOf(parameterObj.getStr("addressIndex")),
                        Integer.valueOf(parameterObj.getStr("addressLength")),
                        parameterObj.getStr("type")); //参数实例
                parameterKeys.add(code);
                parameters.put(code,plcParameter);
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
    //获取此地址全部参数
    public Map<String,PlcParameter> getPlcParameters(){
        return parameters;
    }
    //通过参数名称获取
    public PlcParameter getPlcParameter(String name){
        return parameters.get(name);
    }
    //通过参数序号获取
    public PlcParameter getPlcParameter(int index){
        String key=parameterKeys.get(index);
        if(key!=null&& !key.isEmpty()){
            return this.getPlcParameter(key);
        }
        log.info("无效下标:{},下标范围:0-{}",index,parameterKeys.size());
        return null;
    }
    public int getValueInt(){
        return 0;
    }
    public double getValueDouble(){
        return 0;
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/service/PlcParameter.java
New file
@@ -0,0 +1,154 @@
package com.mes.service;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.mes.device.PlcParameterInfo;
import com.mes.tools.HexConversion;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.*;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import static com.mes.tools.HexConversion.*;
/**
 * Plc参数
 */
@Component
@Slf4j
public class PlcParameter {
    /**
     * 编号
     */
    private String CodeId;
    /**
     * 起始地址
     */
    private int addressStart=0;
    /**
     * 长度
     */
    private int addressLength=0;
    /**
     * 类型
     */
    private String type="int";
    /**
     * 实时读取的byte值
     */
    private byte[] readByte=null;
    /**
     * 实时读取的byte值转换成 对应类型
     */
    private Object readValue=null;
    /**
     * 需要写入的值
     */
    private Object writeValue=null;
    /**
     * 需要写入的值
     */
    private byte[] writeByte=null;
    PlcParameter(){
    }
    PlcParameter(String codeId, int addressStart, int addressLength, String type){
        this.CodeId=codeId;
        this.addressStart=addressStart;
        this.addressLength=addressLength;
        this.type=type;
    }
    public String getCodeId() {
        return CodeId;
    }
    public void setCodeId(String codeId) {
        CodeId = codeId;
    }
    public int getAddressStart() {
        return addressStart;
    }
    public void setAddressStart(int addressIndex) {
        this.addressStart = addressStart;
    }
    public int getAddressLength() {
        return addressLength;
    }
    public void setAddressLength(int addressLength) {
        this.addressLength = addressLength;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public Object getReadValue() {
        return readValue;
    }
    public String getValueString() {
        return getValueInt()+"";
    }
    public int getValueInt() {
        if(this.readByte==null||this.readByte.length<1){
            //log.info("读取内容为null: {}  :{}",this.getCodeId(),this.readByte);
            return 0;
        }
        return bytesToIntDesc(this.readByte,0);
    }
    public void setReadValue(Object readValue) {
        this.readValue = readValue;
    }
    public byte[] getReadByte() {
        return this.readByte;
    }
    public void setReadByte(byte[] readByte) {
        this.readByte = readByte;
    }
    public Object getWriteValue() {
        return writeValue;
    }
    public byte [] setWriteValue(Object writeValue) {
        //传入值根据参数类型进行转换成字符串保存进写入 字节内并且返回
        byte []sendByte=new byte[13+this.addressLength];
        if ("int".equals(this.type)){
            this.writeByte=intToBytesDesc(Integer.parseInt(writeValue.toString()),this.addressLength);
            return this.writeByte;
        }else if ("word".equals(this.type)){
            this.writeByte=intToBytesDesc(Integer.parseInt(writeValue.toString()),this.addressLength);
            return this.writeByte;
        }else if("string".equals(this.type)){
        }else{
        }
        return null;
    }
    public byte [] getWriteByte() {
        return this.writeByte;
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/tools/CodeGet.java
New file
@@ -0,0 +1,84 @@
package com.mes.tools;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
/**
 * @author mybatis-plus
 */
public class CodeGet {
    public static void main(String[] args) {
        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();
        // 2、全局配置
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir("D:\\Documents\\hangzhoumesParent5\\");
        gc.setServiceName("%sService");    //去掉Service接口的首字母I
        gc.setAuthor("wu");
        gc.setOpen(false);
        mpg.setGlobalConfig(gc);
        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://10.153.19.150:3306/hangzhoumes?serverTimezone=GMT%2b8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("beibo.123/");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);
        // 4、包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent("com.mes");
        pc.setModuleName("work_assignment"); //模块名
        pc.setController("controller");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);
        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("work_assignment");
        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
        strategy.setRestControllerStyle(true); //restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
        mpg.setStrategy(strategy);
        // 6、执行
        mpg.execute();
        System.out.println("执行完成");
    }
}
/*
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.4.1</version>
</dependency>
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.0</version>
</dependency>
 */
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/tools/DatabaseDesignDocUtil.java
New file
@@ -0,0 +1,97 @@
package com.mes.tools;
/**
 * @Author : zhoush
 * @Date: 2024/3/26 9:01
 * @Description:
 */
import cn.smallbun.screw.core.Configuration;
import cn.smallbun.screw.core.engine.EngineConfig;
import cn.smallbun.screw.core.engine.EngineFileType;
import cn.smallbun.screw.core.engine.EngineTemplateType;
import cn.smallbun.screw.core.execute.DocumentationExecute;
import cn.smallbun.screw.core.process.ProcessConfig;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;
public class DatabaseDesignDocUtil {
    public static void main(String[] args) {
        documentGeneration();
    }
    /**
     * 文档生成
     */
    public static void documentGeneration() {
        //数据源
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        hikariConfig.setJdbcUrl("jdbc:sqlserver://10.153.19.150:1433;databasename=hangzhoumes");
        hikariConfig.setUsername("sa");
        hikariConfig.setPassword("beibo.123/");
        //设置可以获取tables remarks信息
        hikariConfig.addDataSourceProperty("useInformationSchema", "true");
        hikariConfig.setMinimumIdle(2);
        hikariConfig.setMaximumPoolSize(5);
        DataSource dataSource = new HikariDataSource(hikariConfig);
        //生成配置
        EngineConfig engineConfig = EngineConfig.builder()
                //生成文件路径
                .fileOutputDir("E:\\项目\\项目文档\\杭州利来2")
                //打开目录
                .openOutputDir(true)
                //文件类型
                .fileType(EngineFileType.WORD)
                //生成模板实现
                .produceType(EngineTemplateType.freemarker)
                //自定义文件名称
                .fileName("杭州利来数据库文档").build();
        //忽略表
        List<String> ignoreTableName = new ArrayList<>();
        ignoreTableName.add("test_user");
        ignoreTableName.add("test_group");
        //忽略表前缀
        ArrayList<String> ignorePrefix = new ArrayList<>();
        ignorePrefix.add("test_");
        //忽略表后缀
        ArrayList<String> ignoreSuffix = new ArrayList<>();
        ignoreSuffix.add("_test");
        ProcessConfig processConfig = ProcessConfig.builder()
                //指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时,将生成指定表,其余表不生成、并跳过忽略表配置
                //根据名称指定表生成
                .designatedTableName(new ArrayList<>())
                //根据表前缀生成
                .designatedTablePrefix(new ArrayList<>())
                //根据表后缀生成
                .designatedTableSuffix(new ArrayList<>())
                //忽略表名
                .ignoreTableName(ignoreTableName)
                //忽略表前缀
                .ignoreTablePrefix(ignorePrefix)
                //忽略表后缀
                .ignoreTableSuffix(ignoreSuffix).build();
        //配置
        Configuration config = Configuration.builder()
                //版本
                .version("1.0.0")
                //描述
                .description("数据库设计文档生成")
                //数据源
                .dataSource(dataSource)
                //生成配置
                .engineConfig(engineConfig)
                //生成配置
                .produceConfig(processConfig)
                .build();
        //执行生成
        new DocumentationExecute(config).execute();
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/tools/HexConversion.java
New file
@@ -0,0 +1,112 @@
package com.mes.tools;
public class HexConversion {
    /**
     * @param a shuzi
     * @return shuzu
     */
    public static byte[] stringToInt(String a){
        byte[] byt = new byte[a.length()/2];
        for (int i = 0; i < a.length() - 1; i+=2) {
            String output = a.substring(i, i + 2);
            byt[i/2]=(byte)Integer.parseInt(output, 16);
        }
        return byt;
    }
    public static String byteToHexString(int bufSize,byte[] msg){
        String tempHex = "";
        String command = "";
        if (bufSize != -1) {
            for (int i = 0; i < bufSize; i++) {
                tempHex = Integer.toHexString(msg[i] & 0xFF);
                if (tempHex.length() == 1) {
                    tempHex = "0" + tempHex;
                }
                command += tempHex;
            }
        }
        return command;
    }
    public static String intToHex(int number) {
        return Integer.toHexString(number);
    }
    /**
     * 将整数转换为4位16进制,如1转换为0001,10转换为000a
     *
     * @param number
     * @return
     */
    public static String intTo2ByteHex(int number) {
        String numberHex = intToHex(number);
        numberHex = String.format("%4s", numberHex).replace(' ', '0');
        return numberHex;
    }
    /**
     * 将整数转换为2位16进制,如1转换为01,10转换为0a
     *
     * @param
     * @return
     */
    public static String intTo1ByteHex(int number) {
        String numberHex = intToHex(number);
        numberHex = String.format("%2s", numberHex).replace(' ', '0');
        return numberHex;
    }
    /**
     * 从byte数组中取int数值,本方法适用于(低位在前,高位在后)的顺序,和和intToBytes()配套使用
     *
     * @param src: byte数组
     * @param offset: 从数组的第offset位开始
     * @return int数值
     */
    public static int bytesToIntDesc(byte[] src, int offset) {
        int value=0;
        int length = src.length;
        for(int i=0;i<length;i++){
            value+=(int)((src[offset+i]&0xFF)<<(length-i-1)*8);
        }
        return value;
    }
    /**
     * 将int数值转换为占size个字节的byte数组,本方法适用于(低位在前,高位在后)的顺序。 和bytesToInt()配套使用
     * @param value
     *            要转换的int值
     * @return byte数组
     */
    public static byte[] intToBytesDesc( int value,int size )
    {
        byte[] src = new byte[size];
        for(int i=0;i<size;i++){
            src[i] = (byte) ((value>>(size-i-1)*8) & 0xFF);
        }
        return src;
    }
    /**
     * 从byte数组中取int数值,本方法适用于(低位在前,高位在后)的顺序,和和intToBytes()配套使用
     *
     * @param src: byte数组
     * @param offset: 从数组的第offset位开始
     * @return int数值
     */
    public static int bytesToInt(byte[] src, int offset) {
        int value=0;
        for(int i=0;i<src.length;i++){
            value+=(int)((src[offset+i]&0xFF)<<i*8);
        }
        return value;
    }
    /**
     * 将int数值转换为占size个字节的byte数组,本方法适用于(低位在前,高位在后)的顺序。 和bytesToInt()配套使用
     * @param value
     *            要转换的int值
     * @return byte数组
     */
    public static byte[] intToBytes( int value,int size )
    {
        byte[] src = new byte[size];
        for(int i=0;i<src.length;i++){
            src[i] = (byte) ((value>>i*8) & 0xFF);
        }
        return src;
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/tools/InitUtil.java
New file
@@ -0,0 +1,104 @@
package com.mes.tools;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.mes.device.PlcBitInfo;
import com.mes.device.PlcBitObject;
import com.mes.device.PlcParameterInfo;
import com.mes.device.PlcParameterObject;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class InitUtil {
    //初始化word
    public static PlcParameterObject initword(String jsonFilePath) {
        try {
            FileReader fileReader = new FileReader(jsonFilePath);
            BufferedReader bufferedReader = new BufferedReader(fileReader);
            StringBuilder content = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                content.append(line);
            }
            bufferedReader.close();
            fileReader.close();
            JSONObject jsonfileobj = new JSONObject(content.toString());
            JSONArray jsonArray = jsonfileobj.getJSONArray("parameteInfor");
            PlcParameterObject plcParameterObject = new PlcParameterObject();
            plcParameterObject.setPlcAddressBegin(jsonfileobj.getStr("plcAddressBegin"));//设置起始位地址
            plcParameterObject.setPlcAddressLength(Integer.valueOf(jsonfileobj.getStr("plcAddressLenght")));//设置地址长度
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject parameterObj = jsonArray.getJSONObject(i);
                PlcParameterInfo plcParameterInfo = new PlcParameterInfo(jsonfileobj.getStr("plcAddressBegin")); //参数实例
                String codeid = parameterObj.getStr("codeId");
                plcParameterInfo.setCodeId(codeid);
                plcParameterInfo.setAddressIndex(Integer.valueOf(parameterObj.getStr("addressIndex")));
                //plcParameterInfo.setRatio(Integer.valueOf(parameterObj.getStr("ratio")));
                plcParameterInfo.setAddressLength(Integer.valueOf(parameterObj.getStr("addressLenght")));
                plcParameterInfo.setUnit(parameterObj.getStr("unit"));
                plcParameterObject.addPlcParameter(plcParameterInfo);
            }
            // byte[] getplcvlues = {0x01, 0x02, 0x03, 0x04,0x01, 0x02, 0x03, 0x04,0x01, 0x02, 0x03, 0x04,0x01, 0x02,0x01, 0x02, 0x03, 0x04,0x01, 0x02, 0x03, 0x04,0x01, 0x02, 0x03, 0x04,0x01, 0x02,0x01, 0x02, 0x03, 0x04,0x01, 0x02, 0x03, 0x04,0x01, 0x02, 0x03, 0x04,0x01, 0x02};
            // byte[] getplcvlues = S7control.getinstance().ReadByte(plcParameterObject.getPlcAddressBegin(), plcParameterObject.getPlcAddressLength());
            // plcParameterObject.setPlcParameterList(getplcvlues);
            return plcParameterObject;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    //初始化bit
    public static PlcBitObject initbit(String jsonFilePath) {
        PlcBitObject plcBitObject = new PlcBitObject();
        try {
            FileReader fileReader = new FileReader(jsonFilePath);
            BufferedReader bufferedReader = new BufferedReader(fileReader);
            StringBuilder content = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                content.append(line);
            }
            bufferedReader.close();
            fileReader.close();
            JSONObject jsonfileobj = new JSONObject(content.toString());
            JSONArray jsonArray = jsonfileobj.getJSONArray("parameteInfor");
            plcBitObject.setPlcAddressBegin(jsonfileobj.getStr("plcAddressBegin"));//设置起始位地址
            plcBitObject.setPlcAddressLength(Integer.valueOf(jsonfileobj.getStr("plcAddressLenght")));//设置地址长度
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject parameterObj = jsonArray.getJSONObject(i);
                PlcBitInfo plcBitInfo = new PlcBitInfo(jsonfileobj.getStr("plcAddressBegin")); //参数实例
                String codeid = parameterObj.getStr("codeId");
                plcBitInfo.setCodeId(codeid);
                plcBitInfo.setAddressIndex(Integer.valueOf(parameterObj.getStr("addressIndex")));
                plcBitObject.addPlcBit(plcBitInfo);
            }
            System.out.println("");
        } catch (IOException e) {
            e.printStackTrace();
        }
        //Boolean[] values1 = { false, true, true, true, false, false, true, false,
        //  false, true ,true };
        // List<Boolean> getplcvlues = new ArrayList<>(Arrays.asList(values1));
//        List<Boolean> getplcvlues = S7control.getinstance().ReadBits(plcBitObject.getPlcAddressBegin(), plcBitObject.getPlcAddressLength());
//        plcBitObject.setPlcBitList(getplcvlues);
        return plcBitObject;
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/tools/S7control.java
New file
@@ -0,0 +1,489 @@
package com.mes.tools;
import com.github.s7connector.api.DaveArea;
import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
import com.github.xingshuangs.iot.protocol.s7.service.MultiAddressWrite;
import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
public class S7control {
    S7PLC s7PLC; // PLC通讯类实例
    public S7control(EPlcType plcType, String ip, int port, int rack, int slot) {
        if (s7PLC == null) {
            s7PLC = new S7PLC(plcType, ip, port, 0, 0);
        }
    }
    /**
     * 关闭西门子s7通讯连接
     */
    public void closeS7client() {
        if (s7PLC != null) {
            s7PLC.close();
        }
    }
    /**
     * 重启西门子s7通讯连接
     */
    public boolean reStartS7client() {
        if (s7PLC != null) {
            try {
                s7PLC.hotRestart();
                return true;
            } catch (Exception ex) {
                return false;
            }
        }
        return false;
    }
    /**
     * s7通讯连接状态
     */
    public boolean checkConnected() {
        return s7PLC.checkConnected();
    }
    /**
     * 按指定的地址 写入一个word
     *
     * @param address 地址
     * @param data    word的值
     */
    public boolean writeWord(String address, int data) {
        if (s7PLC == null) {
            return false;
        }
        boolean result = false;
        int tryCount = 2;
        do {
            try {
                s7PLC.writeUInt16(address, data);
                result = true;
            } catch (Exception ex) {
                System.out.println("向plc写命令过程中发生异常,原因为:" + ex.getMessage());
                reStartS7client();
            } finally {
                tryCount -= 1;
            }
        }
        while (!result && tryCount > 0);
        return result;
    }
    /**
     * 从某地址连续 写入多个word
     *
     * @param address 地址
     * @param datas   word的值
     */
    public boolean writeWord(String address, List<Integer> datas) {
        if (s7PLC == null) {
            return false;
        }
        boolean result = false;
        int tryCount = 2;
        // s7PLC.write(address, data);
        List<String> addresslist = getAddressList(address, datas.size(), 16);
        MultiAddressWrite addressWrite = new MultiAddressWrite();
        for (int i = 0; i < datas.size(); i++) {
            addressWrite.addUInt16(addresslist.get(i), datas.get(i));
        }
        do {
            try {
                s7PLC.writeMultiData(addressWrite);
                result = true;
            } catch (Exception ex) {
                reStartS7client();
            } finally {
                tryCount -= 1;
            }
        }
        while (!result && tryCount > 0);
        return result;
    }
    /**
     * 按指定的地址 写入多个word
     *
     * @param address 地址
     * @param datas   word的值
     */
    /**
     * 按指定的地址 写入一个Bit
     *
     * @param address 地址
     * @param data    Bit的值
     */
    public boolean writeBit(String address, Boolean data) {
        if (s7PLC == null) {
            return false;
        }
        boolean result = false;
        int tryCount = 2;
        do {
            try {
                s7PLC.writeBoolean(address, data);
                result = true;
            } catch (Exception ex) {
                reStartS7client();
            } finally {
                tryCount -= 1;
            }
        }
        while (!result && tryCount > 0);
        return result;
    }
    /**
     * 按指定的地址 写入多个bit
     *
     * @param address 地址
     * @param datas   bit的值
     */
    public boolean writeBit(List<String> address, List<Boolean> datas) {
        if (s7PLC == null) {
            return false;
        }
        MultiAddressWrite addressWrite = new MultiAddressWrite();
        for (int i = 0; i < address.size(); i++) {
            addressWrite.addBoolean(address.get(i), datas.get(i));
        }
        boolean result = false;
        int tryCount = 2;
        do {
            try {
                s7PLC.writeMultiData(addressWrite);
                result = true;
            } catch (Exception ex) {
                reStartS7client();
            } finally {
                tryCount -= 1;
            }
        }
        while (!result && tryCount > 0);
        return result;
    }
    /**
     * 从某地址连续 写入多个bit
     *
     * @param address 地址
     * @param datas   word的值
     */
    public boolean writeBit(String address, List<Boolean> datas) {
        if (s7PLC == null) {
            return false;
        }
        // s7PLC.write(address, data);
        List<String> addresslist = getAddressList(address, datas.size(), 1);
        MultiAddressWrite addressWrite = new MultiAddressWrite();
        for (int i = 0; i < datas.size(); i++) {
            addressWrite.addBoolean(addresslist.get(i), datas.get(i));
        }
        boolean result = false;
        int tryCount = 2;
        do {
            try {
                s7PLC.writeMultiData(addressWrite);
                result = true;
            } catch (Exception ex) {
                reStartS7client();
            } finally {
                tryCount -= 1;
            }
        }
        while (!result && tryCount > 0);
        return result;
    }
    /**
     * 按指定的地址 写入多个byte
     *
     * @param address 地址
     * @param datas   byte的值
     */
    public boolean writeByte(String address, byte[] datas) {
        if (s7PLC == null) {
            return false;
        }
        boolean result = false;
        int tryCount = 2;
        do {
            try {
                s7PLC.writeByte(address, datas);
                result = true;
            } catch (Exception ex) {
                reStartS7client();
            } finally {
                tryCount -= 1;
            }
        }
        while (!result && tryCount > 0);
        return result;
    }
    /**
     * 按指定的地址 读取word结果集
     *
     * @param address 地址
     * @return 结果
     */
    public List<Integer> readWord(List<String> address) {
        if (s7PLC == null) {
            return null;
        }
        List<Integer> result = null;
        try {
            result = s7PLC.readUInt16(address);
        } catch (Exception e) {
            s7PLC.hotRestart();
            System.out.println("读取 " + address + " 失败:" + e.getMessage());
        } finally {
            return result;
        }
    }
    /**
     * 按指定的地址 读取word结果集
     *
     * @param address 地址
     * @param count   连续读多少个word
     * @return 结果
     */
    public List<Integer> readWord(String address, int count) {
        if (s7PLC == null) {
            return null;
        }
        List<Integer> result = null;
        List<String> addresslist = getAddressList(address, count, 16);
        try {
            result = s7PLC.readUInt16(addresslist);
        } catch (Exception e) {
            s7PLC.hotRestart();
            System.out.println("读取 " + address + " 失败:" + e.getMessage());
        } finally {
            return result;
        }
    }
    /**
     * 按指定的地址 读取byte结果集
     *
     * @param address 地址
     * @param count   连续读多少个byte
     * @return 结果
     */
    public byte[] readByte(String address, int count) {
        if (s7PLC == null) {
            return null;
        }
        // List<String> addresslist = GetAddressList(address, count, 16);
        byte[] bytes = null;
        try {
            bytes = s7PLC.readByte(address, count);
        } catch (Exception e) {
            // 处理异常
            s7PLC.hotRestart();
            System.out.println("读取 " + address + " 失败:" + e.getMessage());
        } finally {
            return bytes;
        }
    }
    /**
     * 按指定的地址 按bit位 0 flase 1 true 读取结果
     *
     * @param addresslist 地址集
     * @return Boolean结果
     */
    public List<Boolean> readBits(List<String> addresslist) {
        if (s7PLC == null) {
            return null;
        }
        List<Boolean> values = new ArrayList<>();
        try {
            values = s7PLC.readBoolean(addresslist);
        } catch (Exception e) {
            // 处理异常
            s7PLC.hotRestart();
        } finally {
            return values;
        }
    }
   /* //读取不连续地址bit
    public List<Boolean> readBits(List<String> addressList) {
        if (s7PLC == null || addressList.isEmpty()) {
            return null;
        }
        List<Boolean> values = new ArrayList<>();
        for (String address : addressList) {
            try {
                boolean value = s7PLC.readBoolean(address);
                values.add(value);
            } catch (Exception e) {
                // 处理异常
                System.out.println("读取 " + address + " 失败:" + e.getMessage());
            }
        }
        return values;
    }*/
    //读取字符串
    public String readString(String address) {
        if (s7PLC == null) {
            return null;
        }
        String result = null;
        try {
            result = s7PLC.readString(address);
        } catch (Exception e) {
            s7PLC.hotRestart();
            System.out.println("读取 " + address + " 失败:" + e.getMessage());
        } finally {
            return result;
        }
    }
    //读取时间
    public Long readtime(String address) {
        if (s7PLC == null) {
            return null;
        }
        Long result = null;
        try {
            result = s7PLC.readTime(address);
        } catch (Exception e) {
            s7PLC.hotRestart();
            System.out.println("读取 " + address + " 失败:" + e.getMessage());
        } finally {
            return result;
        }
    }
    public boolean writetime(String address, long datas) {
        if (s7PLC == null) {
            return false;
        }
        boolean result = false;
        int tryCount = 2;
        do {
            try {
                s7PLC.writeTime(address, datas); // 将数据写入单个地址
                result = true;
            } catch (Exception ex) {
                reStartS7client();
            } finally {
                tryCount -= 1;
            }
        }
        while (!result && tryCount > 0);
        return result;
    }
    /**
     * 从指定的地址开始 连续按bit位读取
     *
     * @param address 地址
     * @param count   长度
     * @return Boolean结果
     */
    public List<Boolean> readBits(String address, int count) {
        if (s7PLC == null) {
            return null;
        }
        List<Boolean> values = new ArrayList<>();
        List<String> addresslist = getAddressList(address, count, 1);
        try {
            values = s7PLC.readBoolean(addresslist);
        } catch (Exception e) {
            s7PLC.hotRestart();
            System.out.println("读取 " + address + " 失败:" + e.getMessage());
        } finally {
            return values;
        }
    }
    ;
    private List<String> getAddressList(String address, int count, int addedbit) {
        List<String> addresslist = new ArrayList<String>();
        String[] stringdatas = address.trim().split("\\.");
        if (stringdatas.length < 2 || !address.startsWith("DB")) {
            return null;
        }
        int dbwindex = 0;
        int bitindex = 0;
        if (stringdatas.length == 2) {
            dbwindex = Integer.parseInt(stringdatas[1]);
        } else if (stringdatas.length == 3) {
            dbwindex = Integer.parseInt(stringdatas[1]);
            bitindex = Integer.parseInt(stringdatas[2]);
        } else {
            return null;
        }
        addresslist.add(address);
        for (int i = 0; i < count - 1; i++) {
            int bitcurrent = bitindex + addedbit;
            if (bitcurrent > 7) {
                dbwindex += bitcurrent / 8;
                bitindex = 0;
            } else {
                bitindex = bitcurrent;
            }
            String endstr = stringdatas.length == 3 ? "." + bitindex : "";
            addresslist.add(stringdatas[0] + "." + dbwindex + endstr);
        }
        return addresslist;
    }
    public void writeString(String addr,String data) {
        s7PLC.writeString(addr,data);
    }
    public void writeUInt16(String addr,int data) {
        s7PLC.writeUInt16(addr,data);
    }
    public void writeUInt32(String addr,int data) {
        s7PLC.writeUInt32(addr,data);
    }
    public void writeStringy(String addr,String value) {
        byte[] bytes = value.getBytes();
        s7PLC.writeByte(addr,bytes);
    }
    public String readStrings(String addr) {
        return s7PLC.readString(addr);
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/tools/WebSocketServer.java
New file
@@ -0,0 +1,174 @@
package com.mes.tools;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint(value = "/api/talk/{username}")
@Component("webSocketServer")
public class WebSocketServer {
    public static ConfigurableApplicationContext applicationContext;
    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
    private List<String> messages;
    /**
     * 记录当前在线连接数
     */
    public static final Map<String, ArrayList<WebSocketServer>> sessionMap = new ConcurrentHashMap<>();
    public String username;
    public Session session;
    public WebSocketServer() {
        this.messages = new ArrayList<>();
    }
    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("username") String username) {
        this.username = username;
        this.session = session;
        List<WebSocketServer> webSocketServers = sessionMap.get(username);
        if (webSocketServers == null) {
            ArrayList<WebSocketServer> arrayListwebserver = new ArrayList<WebSocketServer>();
            arrayListwebserver.add(this);
            sessionMap.put(username, arrayListwebserver);
        } else {
            webSocketServers.add(this);
        }
        log.info("有新用户加入,username={}, 当前在线人数为:{}", username, sessionMap.get(username).size());
        // JSONObject result = new JSONObject();
        // JSONArray array = new JSONArray();
        // result.set("users", array);
        // for (Object key : sessionMap.keySet()) {
        // JSONObject jsonObject = new JSONObject();
        // jsonObject.set("username", key);
        // array.add(jsonObject);
        // }
        // sendAllMessage(JSONUtil.toJsonStr(result)); // 后台发送消息给所有的客户端
    }
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session, @PathParam("username") String username) {
        List<WebSocketServer> webSocketServers = sessionMap.get(username);
        ArrayList<WebSocketServer> arrayListwebserver = new ArrayList<WebSocketServer>();
        if (webSocketServers.size() > 1) {
            for (WebSocketServer webSocketServer : webSocketServers) {
                if (webSocketServer != this) {
                    arrayListwebserver.add(webSocketServer);
                }
            }
            sessionMap.put(username, arrayListwebserver);
            log.info("移除username={}一名用户session, {}的当前在线人数为:{}", username, username, sessionMap.get(username).size());
        } else {
            sessionMap.remove(username);
            log.info("移除username={}一名用户session, {}连接关闭, 当前连接数为:{}", username, username, sessionMap.size());
        }
    }
    /**
     * 收到客户端消息后调用的方法
     * 后台收到客户端发送过来的消息
     * onMessage 是一个消息的中转站
     * 接受 浏览器端 socket.send 发送过来的 json数据
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("username") String username) {
        log.info("服务端收到用户username={}的消息:{}", username, message);
        JSONObject obj = JSONUtil.parseObj(message);
        String text = obj.getStr("data");
        JSONObject jsonObject = new JSONObject();
        jsonObject.set("message", text);
        this.messages.add(text);
    }
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }
    /**
     * 服务端发送消息给客户端
     */
    public void sendMessage(String message) {
        try {
            // log.info("服务端给客户端[{}]发送消息{}", this.session.getId(), message);
            if(this.session.isOpen()){
                int maxChunkSize = 50000; // 定义最大的分块大小
                int length = message.length();
                if(length>50000){
                    int chunks = (int) Math.ceil((double) length / maxChunkSize);
                    //分块发送消息
                    for (int i = 0; i < chunks; i++) {
                        int startIndex = i * maxChunkSize;
                        int endIndex = Math.min(startIndex + maxChunkSize, length);
                        String chunk = message.substring(startIndex, endIndex);
                        // 判断是否是最后一块消息
                        boolean isLastChunk = (i == chunks - 1);
                        if(isLastChunk==true){
                            chunk+="<END>";
                        }
                        // 发送分块消息,并传递是否是最后一块消息的标识
                        this.session.getBasicRemote().sendText(chunk);
                    }
                }else{
                    this.session.getBasicRemote().sendText(message);
                }
            }
        } catch (Exception e) {
            //log.error("发送消息给客户端失败:{}", e.getMessage(), e);
        }
    }
    // /**
    //  * 服务端发送消息给所有客户端
    //  */
    // public void sendAllMessage(String message) {
    //     try {
    //         for (WebSocketServer webSocketServer : sessionMap.values()) {
    //             // log.info("服务端给客户端[{}]发送消息{}", this.session.getId(), message);
    //             webSocketServer.sendMessage(message);
    //         }
    //     } catch (Exception e) {
    //         log.error("服务端发送消息给客户端失败", e);
    //     }
    // }
    public List<String> getMessages() {
        return messages;
    }
    public void clearMessages() {
        messages.clear();
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/utils/HexUtil.java
New file
@@ -0,0 +1,269 @@
package com.mes.utils;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class HexUtil {
    public static String formatHex(String hex) {
        String result = "";
        for (int i = 0; i < hex.length() - 1; i+=2) {
            String output = hex.substring(i, i + 2);
            result += ("0x" + output + " ");
        }
        if (result.length() > 0) {
            result = result.substring(0, result.lastIndexOf(" "));
        }
        return result;
    }
    //正常的字母数字变成字节数发送给盒子
    public static String asciiToHex(String str) {
        char[] chars = str.toCharArray();
        StringBuffer hex = new StringBuffer();
        for (int i = 0; i < chars.length; i++) {
            hex.append(Integer.toHexString(chars[i]));
        }
        return hex.toString();
    }
    public static String hexToAscii(String hex) {
        StringBuffer result = new StringBuffer();
        for (int i = 0; i < hex.length() - 1; i+= 2) {
            String output = hex.substring(i, i + 2);
            int decimal = Integer.parseInt(output, 16);
            result.append((char) decimal);
        }
        return result.toString();
    }//12300    //00321
    //二进制转十进制
    public static int int2ToHex(String number) {
        return Integer.parseInt(number, 2);
    }
    //二进制转16进制 4位
    public static String intBinaryTo16(String number) {
        int num=int2ToHex(number);
        return intTo2ByteHex(num);
    }
    //十六进制转十进制
    public static int int16ToHex(String number) {
        return Integer.parseInt(number, 16);
    }
    //十进制转二进制
    public static String intToBinary(int number) {
        return Integer.toBinaryString(number);
    }
    //十六进制转二进制
    public static String int16ToBinary(String number) {
        return intToBinary(int16ToHex(number));
    }
    //十六进制转二进制
    public static String int16ToBinaryEight(String number,int count) {
        String binary=int16ToBinary(number);
        String zero="";
        for (int i = 0; i <count-binary.length(); i++) {
            zero+="0";
        }
        binary=zero+binary;
        return binary;
    }
    public static String intToHex(int number) {
        return Integer.toHexString(number);
    }
    /**
     * 将整数转换为2位16进制,如1转换为01,10转换为0a
     *
     * @param number
     * @return
     */
    public static String intTo1ByteHex(int number) {
        String numberHex = HexUtil.intToHex(number);
        numberHex = String.format("%2s", numberHex).replace(' ', '0');
        return numberHex;
    }
    /**
     * 将整数转换为4位16进制,如1转换为0001,10转换为000a
     *
     * @param number
     * @return
     */
    public static String intTo2ByteHex(int number) {
        String numberHex = HexUtil.intToHex(number);
        numberHex = String.format("%4s", numberHex).replace(' ', '0');
        return numberHex;
    }
    /**
     * 将整数转换为8位16进制,如1转换为00000001,10转换为0000000a
     *
     * @param number
     * @return
     */
    public static String intTo4ByteHex(int number) {
        String numberHex = HexUtil.intToHex(number);
        numberHex = String.format("%8s", numberHex).replace(' ', '0');
        return numberHex;
    }
    /**
     * 将时间转换为16进制格式,年(2字节) + 月(1字节) + 日(1字节) + 时(1字节) + 分(1字节) + 秒(1字节)
     *
     * @param time
     * @return
     */
    public static String timeToHex(Date time) {
        Calendar c = Calendar.getInstance();
        c.setTime(time);
        String yearHex = intTo2ByteHex(c.get(Calendar.YEAR));
        String monthHex = intTo1ByteHex(c.get(Calendar.MONTH) + 1);
        String dayHex = intTo1ByteHex(c.get(Calendar.DAY_OF_MONTH));
        String hourHex = intTo1ByteHex(c.get(Calendar.HOUR_OF_DAY));
        String minuteHex = intTo1ByteHex(c.get(Calendar.MINUTE));
        String secondHex = intTo1ByteHex(c.get(Calendar.SECOND));
        return yearHex + monthHex + dayHex + hourHex + minuteHex + secondHex;
    }
    /**
     * 将16进制的时间转换为yyyy-MM-dd HH:mm:ss的格式
     *
     * @param hexTime
     * @return
     */
    public static String hexToTime(String hexTime) {
        String year = hexTo4DigitInt(hexTime.substring(0, 4));
        String month = hexTo2DigitInt(hexTime.substring(4, 6));
        String day = hexTo2DigitInt(hexTime.substring(6, 8));
        String hour = hexTo2DigitInt(hexTime.substring(8, 10));
        String minute = hexTo2DigitInt(hexTime.substring(10, 12));
        String second = hexTo2DigitInt(hexTime.substring(12, 14));
        return year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
    }
    //十六进制转10进制
    public static int hexToInt(String hex) {
        return Integer.parseInt(hex, 16);
    }
    //十六进制转成10进制四位
    public static String hexTo4DigitInt(String hex) {
        return new DecimalFormat("0000").format(hexToInt(hex));
    }
    //十六进制转成10进制两位
    public static String hexTo2DigitInt(String hex) {
        return new DecimalFormat("00").format(hexToInt(hex));
    }
    public static byte[] stringToInt(String a){
        byte[] byt = new byte[a.length()/2];
        for (int i = 0; i < a.length() - 1; i+=2) {
            String output = a.substring(i, i + 2);
            byt[i/2]=(byte)Integer.parseInt(output, 16);
        }
        return byt;
    }
    /**
     * 将字节转换为两位十六进制字符串,不够位前加0
     *
     * @param b
     * @return
     */
    public static String byteToHexString(byte b) {
        String hex = Integer.toHexString(b & 0xFF);
        if (hex.length() == 1) {
            hex = "0" + hex;
        }
        return hex;
    }
    /**
     * 将十六进制字符,转换成二进制的字符
     *
     * @param b
     * @return
     */
     public static String getBin(String hex){
        String[] hexs = new String[]{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
                 "a", "b", "c", "d", "e", "f"};
        String[] bins = new String[]{"0000", "0001", "0010", "0011", "0100", "0101",
                 "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
        int i;
        for(i=0; i<hexs.length && !hex.toLowerCase().equals(hexs[i]); i++);
            return bins[i];
         }
       /**
         * 将十六进制字符,转换成二进制的字符
         *
         * @param b
         * @return
         */
         public static String gethex(String hex){
            String[] hexs = new String[]{"0000", "0001", "0002", "0003", "0004", "0005", "0006", "0007", "0008", "0009",
                     "000a", "000b", "000c", "000d", "000e", "000f"};
            String[] bins = new String[]{"0000", "0001", "0010", "0011", "0100", "0101",
                     "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
            int i;
            for(i=0; i<bins.length && !hex.toLowerCase().equals(bins[i]); i++);
                return hexs[i];
             }
    /**
     * 十进制字节数组转十六进制字符串
     * @param bufSize
     * @param msg
     * @return
     */
    public static String byteToHexString(int bufSize,byte[] msg){
        String tempHex = "";
        String command = "";
        if (bufSize != -1) {
            for (int i = 0; i < bufSize; i++) {
                tempHex = Integer.toHexString(msg[i] & 0xFF);
                if (tempHex.length() == 1) {
                    tempHex = "0" + tempHex;
                }
                command += tempHex;
            }
        }
        return command;
    }
    public static String hexToBinary(String hexString) {
        String binaryString = Integer.toBinaryString(hexToInt(hexString));
        return String.format("%16s", binaryString).replace(' ', '0');
    }
    public static String binaryTo2ByteHex(String binaryString) {
        String HexString = Integer.toHexString(Integer.parseInt(binaryString, 2));
        return String.format("%4s", HexString).replace(' ', '0');
    }
    public static String hexTo2Binary(String hexString) {
        String binaryString = Integer.toBinaryString(hexToInt(hexString));
        return String.format("%8s", binaryString).replace(' ', '0');
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/utils/MD5.java
New file
@@ -0,0 +1,36 @@
package com.mes.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public final class MD5 {
    public static String encrypt(String strSrc) {
        try {
            char hexChars[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
                    '9', 'a', 'b', 'c', 'd', 'e', 'f'};
            byte[] bytes = strSrc.getBytes();
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(bytes);
            bytes = md.digest();
            int j = bytes.length;
            char[] chars = new char[j * 2];
            int k = 0;
            for (int i = 0; i < bytes.length; i++) {
                byte b = bytes[i];
                chars[k++] = hexChars[b >>> 4 & 0xf];
                chars[k++] = hexChars[b & 0xf];
            }
            return new String(chars);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new RuntimeException("MD5加密出错!!+" + e);
        }
    }
    public static void main(String[] args) {
        System.out.println(MD5.encrypt("111111"));
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/utils/ResponseUtil.java
New file
@@ -0,0 +1,28 @@
package com.mes.utils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * @Author : zhoush
 * @Date: 2024/4/8 15:46
 * @Description:
 */
public class ResponseUtil {
    public static final String APPLICATION_JSON_UTF8_VALUE = "application/json;charset=UTF-8";
    public static void out(HttpServletResponse response, Result r) {
        ObjectMapper mapper = new ObjectMapper();
        response.setStatus(HttpStatus.OK.value());
        response.setContentType(APPLICATION_JSON_UTF8_VALUE);
        try {
            mapper.writeValue(response.getWriter(), r);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/utils/Result.java
New file
@@ -0,0 +1,56 @@
package com.mes.utils;
import lombok.Data;
@Data
public class Result<T> {
    private Integer code;
    private String message;
    private T data;
    private Result() {
    }
    public static <T> Result<T> build(Integer code, String message, T data) {
        Result<T> result = new Result<T>();
        result.setCode(code);
        result.setMessage(message);
        if (data != null) {
            result.setData(data);
        }
        return result;
    }
    public static <T> Result<T> build(ResultCodeEnum resultCodeEnum, T data) {
        Result<T> result = new Result<T>();
        result.setCode(resultCodeEnum.getCode());
        result.setMessage(resultCodeEnum.getMessage());
        if (data != null) {
            result.setData(data);
        }
        return result;
    }
    public static <T> Result<T> success() {
        return build(ResultCodeEnum.SUCCESS, null);
    }
    public static <T> Result<T> success(T data) {
        return build(ResultCodeEnum.SUCCESS.getCode(), "", data);
    }
    public static Result error(Integer code, String msg) {
        return build(code, msg, null);
    }
    public static <T> Result<T> error(T data) {
        return build(ResultCodeEnum.FAIL.getCode(), "", data);
    }
    public static <T> Result<T> error() {
        return build(ResultCodeEnum.FAIL.getCode(), "服务器发生异常", null);
    }
}
ShangHaiMesParent/common/servicebase/src/main/java/com/mes/utils/ResultCodeEnum.java
New file
@@ -0,0 +1,33 @@
package com.mes.utils;
import lombok.Getter;
/**
 * @author zhoush
 */
@Getter
public enum ResultCodeEnum {
    SUCCESS(200, "成功"),
    FAIL(201, "失败"),
    SERVICE_ERROR(2012, "服务异常"),
    DATA_ERROR(204, "数据异常"),
    ILLEGAL_REQUEST(205, "非法请求"),
    REPEAT_SUBMIT(206, "重复提交"),
    LOGIN_AUTH(208, "未登陆"),
    PERMISSION(209, "没有权限"),
    ;
    private Integer code;
    private String message;
    ResultCodeEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}
ShangHaiMesParent/common/servicebase/src/main/resources/banner.txt
New file
@@ -0,0 +1,32 @@
________                ________                 ___       _____________   ____
`MMMMMMMb.          68b `MMMMMMMb.               `MMb     dMM'`MMMMMMMMM  6MMMMb\
 MM    `Mb          Y89  MM    `Mb                MMM.   ,PMM  MM      \ 6M'    `
 MM     MM   ____   ___  MM     MM   _____        M`Mb   d'MM  MM        MM
 MM    .M9  6MMMMb  `MM  MM    .M9  6MMMMMb       M YM. ,P MM  MM    ,   YM.
 MMMMMMM(  6M'  `Mb  MM  MMMMMMM(  6M'   `Mb      M `Mb d' MM  MMMMMMM    YMMMMb
 MM    `Mb MM    MM  MM  MM    `Mb MM     MM      M  YM.P  MM  MM    `        `Mb
 MM     MM MMMMMMMM  MM  MM     MM MM     MM      M  `Mb'  MM  MM              MM
 MM     MM MM        MM  MM     MM MM     MM      M   YP   MM  MM              MM
 MM    .M9 YM    d9  MM  MM    .M9 YM.   ,M9 68b  M   `'   MM  MM      / L    ,M9
_MMMMMMM9'  YMMMM9  _MM__MMMMMMM9'  YMMMMM9  Y89 _M_      _MM__MMMMMMMMM MYMMMM9
//                          _ooOoo_                               //
//                         o8888888o                              //
//                         88" . "88                              //
//                         (| ^_^ |)                              //
//                         O\  =  /O                              //
//                      ____/`---'\____                           //
//                    .'  \\|     |//  `.                         //
//                   /  \\|||  :  |||//  \                        //
//                  /  _||||| -:- |||||-  \                       //
//                  |   | \\\  -  /// |   |                       //
//                  | \_|  ''\---/''  |   |                       //
//                  \  .-\__  `-`  ___/-. /                       //
//                ___`. .'  /--.--\  `. . ___                     //
//              ."" '<  `.___\_<|>_/___.'  >'"".                  //
//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
//      ========`-.____`-.___\_____/___.-`____.-'========         //
//                           `=---='                              //
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
//            佛祖保佑       永不宕机      永无BUG                  //
ShangHaiMesParent/common/springsecurity/pom.xml
New file
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>common</artifactId>
        <groupId>com.mes</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>springsecurity</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.mes</groupId>
            <artifactId>servicebase</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- Spring Security依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>
    </dependencies>
</project>
ShangHaiMesParent/common/springsecurity/springsecurity1.iml
New file
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
    <orderEntry type="library" name="servicebase-1.0-SNAPSHOT" level="project" />
    <orderEntry type="module" module-name="servicebase1" />
  </component>
</module>
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/config/RedisConfig.java
New file
@@ -0,0 +1,37 @@
package com.mes.common.config;
import com.mes.common.utils.FastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
 * @Author : zhoush
 * @Date: 2024/4/9 19:13
 * @Description:
 */
@Configuration
public class RedisConfig {
    @Bean
    @SuppressWarnings(value = {"unchecked", "rawtypes"})
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);
        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);
        // Hash的key也采用StringRedisSerializer的序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);
        template.afterPropertiesSet();
        return template;
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/config/TokenWebSecurityConfig.java
New file
@@ -0,0 +1,94 @@
package com.mes.common.config;
import com.mes.common.filter.JwtAuthenticationTokenFilter;
import com.mes.common.handler.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    @Autowired
    LoginFailureHandler loginFailureHandler;
    @Autowired
    LoginSuccessHandler loginSuccessHandler;
    @Autowired
    JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
    @Autowired
    JwtAccessDeniedHandler jwtAccessDeniedHandler;
    @Autowired
    JwtLogoutSuccessHandler jwtLogoutSuccessHandler;
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    /**
     * 配置过滤规则
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
                // 登录配置
                .formLogin()
                .successHandler(loginSuccessHandler)
                .failureHandler(loginFailureHandler)
                .and()
                .logout()
                .logoutSuccessHandler(jwtLogoutSuccessHandler)
                // 禁用session
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // 配置拦截规则
                .and()
                .authorizeRequests()
                .antMatchers("/sys/user/login").anonymous()
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/v2/**").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/**").permitAll()
                .anyRequest().authenticated()
                // 异常处理器
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .accessDeniedHandler(jwtAccessDeniedHandler)
                // 配置自定义的过滤器
                .and()
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/filter/JwtAuthenticationTokenFilter.java
New file
@@ -0,0 +1,80 @@
package com.mes.common.filter;
import com.mes.common.utils.JwtUtil;
import com.mes.common.utils.RedisUtil;
import com.mes.common.utils.UserInfoUtils;
import com.mes.userinfo.entity.LoginUser;
import com.mes.userinfo.service.SysUserService;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
 * @Author : zhoush
 * @Date: 2024/4/10 9:42
 * @Description:
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    // 此处解释为什么不去实现Filter接口,因为在某些情况下会过滤两次,执行两次Filter里面的方法,所以我们选择继承SpringSecurity中的OncePerRequestFilter
    @Autowired
    private RedisUtil redisUtil;
    @Resource
    private SysUserService sysUserService;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //获取token
        String token = request.getHeader("token");
        if (!StringUtils.hasText(token)) {
            //放行
            filterChain.doFilter(request, response);
            return; // 此处加上return好处是后面结果返回的时候就不会再走一遍此过滤器的方法了
        }
        //解析token
        String userid;
        try {
            Claims claims = JwtUtil.getClaimByToken(token);
            userid = claims.getSubject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("token非法");
        }
        //从redis中获取用户信息
        String redisKey = "login:" + userid;
        LoginUser loginUser = redisUtil.getCacheObject(redisKey);
        if (Objects.isNull(loginUser)) {
            response.setHeader("token", "");
            throw new RuntimeException("用户未登录");
        }
        //将用户信息放入当前线程
        UserInfoUtils.set(loginUser.getUser());
        //存入SecurityContextHolder,以供后面的过滤器使用
        List<String> permissionKeyList = sysUserService.getUserAuthorityInfo(Long.parseLong(userid));
        List<GrantedAuthority> authorities = permissionKeyList.stream().
                map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, authorities);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        //放行
        filterChain.doFilter(request, response);
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/handler/JwtAccessDeniedHandler.java
New file
@@ -0,0 +1,35 @@
package com.mes.common.handler;
import cn.hutool.json.JSONUtil;
import com.mes.utils.Result;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        ServletOutputStream outputStream = response.getOutputStream();
        Result result = Result.error(HttpStatus.FORBIDDEN.value(), "权限不足");
        outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));
        outputStream.flush();
        outputStream.close();
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/handler/JwtAuthenticationEntryPoint.java
New file
@@ -0,0 +1,33 @@
package com.mes.common.handler;
import cn.hutool.json.JSONUtil;
import com.mes.utils.Result;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        ServletOutputStream outputStream = response.getOutputStream();
        Result result = Result.error(HttpStatus.UNAUTHORIZED.value(), "认证失败请重新登录");
        outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));
        outputStream.flush();
        outputStream.close();
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/handler/JwtLogoutSuccessHandler.java
New file
@@ -0,0 +1,40 @@
package com.mes.common.handler;
import cn.hutool.json.JSONUtil;
import com.mes.utils.Result;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtLogoutSuccessHandler implements LogoutSuccessHandler {
    private static final String header = "Authorization";
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        if (authentication != null) {
            new SecurityContextLogoutHandler().logout(request, response, authentication);
        }
        response.setContentType("application/json;charset=UTF-8");
        ServletOutputStream outputStream = response.getOutputStream();
        response.setHeader(header, "");
        Result result = Result.success("");
        outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));
        outputStream.flush();
        outputStream.close();
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/handler/LoginFailureHandler.java
New file
@@ -0,0 +1,31 @@
package com.mes.common.handler;
import cn.hutool.json.JSONUtil;
import com.mes.utils.Result;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class LoginFailureHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        ServletOutputStream outputStream = response.getOutputStream();
        Result result = Result.error("用户名或密码错误");
        outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));
        outputStream.flush();
        outputStream.close();
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/handler/LoginSuccessHandler.java
New file
@@ -0,0 +1,38 @@
package com.mes.common.handler;
import cn.hutool.json.JSONUtil;
import com.mes.common.utils.JwtUtil;
import com.mes.utils.Result;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
    private static final String header = "Authorization";
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        ServletOutputStream outputStream = response.getOutputStream();
        // 生成jwt,并放置到请求头中
        String jwt = JwtUtil.generateToken(authentication.getName());
        response.setHeader(header, jwt);
        Result result = Result.success("");
        outputStream.write(JSONUtil.toJsonStr(result).getBytes("UTF-8"));
        outputStream.flush();
        outputStream.close();
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/utils/FastJsonRedisSerializer.java
New file
@@ -0,0 +1,55 @@
package com.mes.common.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.Charset;
/**
 * @Author : zhoush
 * @Date: 2024/4/11 15:28
 * @Description:
 */
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private Class<T> clazz;
    static {
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
    }
    public FastJsonRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }
    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }
    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);
        return JSON.parseObject(str, clazz);
    }
    protected JavaType getJavaType(Class<?> clazz) {
        return TypeFactory.defaultInstance().constructType(clazz);
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/utils/JwtUtil.java
New file
@@ -0,0 +1,55 @@
package com.mes.common.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import java.util.Date;
/**
 * @Author : zhoush
 * @Date: 2024/4/9 19:15
 * @Description:
 */
@Data
public class JwtUtil {
    private static final long expire = 60 * 60 * 1000L;
    private static final String secret = "beibo";
    private static final String header = "Authorization";
    // 生成jwt
    public static String generateToken(String username) {
        Date nowDate = new Date();
        Date expireDate = new Date(nowDate.getTime() + 1000 * expire);
        return Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setSubject(username)
                .setIssuedAt(nowDate)
                .setExpiration(expireDate)// 7天過期
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }
    // 解析jwt
    public static Claims getClaimByToken(String jwt) {
        try {
            return Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(jwt)
                    .getBody();
        } catch (Exception e) {
            return null;
        }
    }
    // jwt是否过期
    public boolean isTokenExpired(Claims claims) {
        return claims.getExpiration().before(new Date());
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/utils/RedisUtil.java
New file
@@ -0,0 +1,235 @@
package com.mes.common.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
 * spring redis 工具类
 **/
@Component
public class RedisUtil {
    @Autowired
    public RedisTemplate redisTemplate;
    /**
     * 缓存基本的对象,Integer、String、实体类等
     *
     * @param key   缓存的键值
     * @param value 缓存的值
     */
    public <T> void setCacheObject(final String key, final T value) {
        redisTemplate.opsForValue().set(key, value);
    }
    /**
     * 缓存基本的对象,Integer、String、实体类等
     *
     * @param key      缓存的键值
     * @param value    缓存的值
     * @param timeout  时间
     * @param timeUnit 时间颗粒度
     */
    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }
    /**
     * 设置有效时间
     *
     * @param key     Redis键
     * @param timeout 超时时间
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout) {
        return expire(key, timeout, TimeUnit.SECONDS);
    }
    /**
     * 设置有效时间
     *
     * @param key     Redis键
     * @param timeout 超时时间
     * @param unit    时间单位
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout, final TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }
    /**
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public <T> T getCacheObject(final String key) {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }
    /**
     * 删除单个对象
     *
     * @param key
     */
    public boolean deleteObject(final String key) {
        return redisTemplate.delete(key);
    }
    /**
     * 删除集合对象
     *
     * @param collection 多个对象
     * @return
     */
    public long deleteObject(final Collection collection) {
        return redisTemplate.delete(collection);
    }
    /**
     * 缓存List数据
     *
     * @param key      缓存的键值
     * @param dataList 待缓存的List数据
     * @return 缓存的对象
     */
    public <T> long setCacheList(final String key, final List<T> dataList) {
        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
        return count == null ? 0 : count;
    }
    /**
     * 获得缓存的list对象
     *
     * @param key 缓存的键值
     * @return 缓存键值对应的数据
     */
    public <T> List<T> getCacheList(final String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }
    /**
     * 缓存Set
     *
     * @param key     缓存键值
     * @param dataSet 缓存的数据
     * @return 缓存数据的对象
     */
    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
        Iterator<T> it = dataSet.iterator();
        while (it.hasNext()) {
            setOperation.add(it.next());
        }
        return setOperation;
    }
    /**
     * 获得缓存的set
     *
     * @param key
     * @return
     */
    public <T> Set<T> getCacheSet(final String key) {
        return redisTemplate.opsForSet().members(key);
    }
    /**
     * 缓存Map
     *
     * @param key
     * @param dataMap
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(key, dataMap);
        }
    }
    /**
     * 获得缓存的Map
     *
     * @param key
     * @return
     */
    public <T> Map<String, T> getCacheMap(final String key) {
        return redisTemplate.opsForHash().entries(key);
    }
    /**
     * 往Hash中存入数据
     *
     * @param key   Redis键
     * @param hKey  Hash键
     * @param value 值
     */
    public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
        redisTemplate.opsForHash().put(key, hKey, value);
    }
    /**
     * 获取Hash中的数据
     *
     * @param key  Redis键
     * @param hKey Hash键
     * @return Hash中的对象
     */
    public <T> T getCacheMapValue(final String key, final String hKey) {
        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
        return opsForHash.get(key, hKey);
    }
    /**
     * 删除Hash中的数据
     *
     * @param key
     * @param hkey
     */
    public void delCacheMapValue(final String key, final String hkey) {
        HashOperations hashOperations = redisTemplate.opsForHash();
        hashOperations.delete(key, hkey);
    }
    /**
     * 获取多个Hash中的数据
     *
     * @param key   Redis键
     * @param hKeys Hash键集合
     * @return Hash对象集合
     */
    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
        return redisTemplate.opsForHash().multiGet(key, hKeys);
    }
    /**
     * 获得缓存的基本对象列表
     *
     * @param pattern 字符串前缀
     * @return 对象列表
     */
    public Collection<String> keys(final String pattern) {
        return redisTemplate.keys(pattern);
    }
    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/utils/UserInfoUtils.java
New file
@@ -0,0 +1,26 @@
package com.mes.common.utils;
import com.mes.userinfo.entity.SysUser;
/**
 * @Author : zhoush
 * @Date: 2024/4/25 15:41
 * @Description:
 */
public class UserInfoUtils {
    private static InheritableThreadLocal<SysUser> tokenPool = new InheritableThreadLocal<SysUser>();
    public static SysUser get() {
        return tokenPool.get();
    }
    public static void set(SysUser user) {
        tokenPool.set(user);
    }
    public static void remove() {
        if (get() != null) {
            tokenPool.remove();
        }
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/common/utils/WebUtils.java
New file
@@ -0,0 +1,30 @@
package com.mes.common.utils;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * @Author : zhoush
 * @Date: 2024/4/9 19:16
 * @Description:
 */
public class WebUtils {
    /**
     * 将字符串渲染到客户端
     *
     * @param response 渲染对象
     * @param string   待渲染的字符串
     * @return null
     */
    public static String renderString(HttpServletResponse response, String string) {
        try {
            response.setStatus(200);
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            response.getWriter().print(string);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/menu/controller/SysMenuController.java
New file
@@ -0,0 +1,83 @@
package com.mes.menu.controller;
import com.mes.entity.request.GeneralRequest;
import com.mes.menu.entity.SysMenu;
import com.mes.menu.service.SysMenuService;
import com.mes.utils.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
 * @author zhoush
 * @since 2024-04-11
 */
@Api(description = "菜单管理")
@RestController
@RequestMapping("/sys/menu")
public class SysMenuController {
    @Autowired
    private SysMenuService sysMenuService;
    @ApiOperation("新增菜单")
    @PostMapping("/save")
//    @PreAuthorize("hasAuthority('sys:menu:save')")
    public Result save(@Validated @RequestBody SysMenu sysMenu) {
        sysMenuService.save(sysMenu);
        GeneralRequest request=new GeneralRequest();
        return Result.success(sysMenuService.getMenuTree(request));
    }
    @ApiOperation("修改菜单信息")
    @PostMapping("/updateMenu")
//    @PreAuthorize("hasAuthority('sys:menu:update')")
    public Result<List<SysMenu>> updateMenu(@Validated @RequestBody SysMenu sysMenu) {
        //return Result.success(sysMenu);
        sysMenuService.updateMenu(sysMenu);
        GeneralRequest request=new GeneralRequest();
        return Result.build(200,"修改成功",sysMenuService.getMenuTree(request));
    }
    @ApiOperation("获取用户有权限的所有菜单")
    @GetMapping("/getMenuTree")
    public Result<List<SysMenu>> getMenuTree(GeneralRequest request) {
        return Result.success(sysMenuService.getMenuTree(request));
    }
    @ApiOperation("获取用户的权限")
    @GetMapping("/getAuthorityInfo")
    public Result<List<String>> getAuthorityInfo() {
        return Result.success(sysMenuService.getAuthorityInfo());
    }
    @ApiOperation("用户当前用户的菜单和权限信息")
    @GetMapping("/nav")
    public Result<Map<Object, Object>> nav() {
        return Result.success(sysMenuService.nav());
    }
    @ApiOperation("删除菜单")
    @PostMapping("/deleteMenu")
//    @PreAuthorize("hasAuthority('sys:menu:delete')")
    public Result<List<SysMenu>> deleteMenu(Long menuId) {
        GeneralRequest request=new GeneralRequest();
        return Result.build(200, sysMenuService.deleteMenu(menuId),sysMenuService.getMenuTree(request));
    }
    @ApiOperation("批量删除菜单")
    @PostMapping("/batchDeleteMenu")
//    @PreAuthorize("hasAuthority('sys:menu:delete')")
    public Result<String> batchDeleteMenu(@RequestBody List<Long> menuIds) {
        return Result.success(sysMenuService.batchDeleteMenu(menuIds));
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/menu/entity/SysMenu.java
New file
@@ -0,0 +1,87 @@
package com.mes.menu.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
 * <p>
 *
 * </p>
 *
 * @author zhoush
 * @since 2024-04-13
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class SysMenu implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 自增id
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * 父id
     */
    private Long parentId;
    /**
     * 模块名称
     */
    private String menuName;
    /**
     * 图标
     */
    private String icon;
    /**
     * 地址
     */
    private String url;
    /**
     * 语言类型
     */
    private String languageType;
    /**
     * 状态
     */
    private Integer status;
    /**
     * 排序
     */
    private String listSort;
    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 权限
     */
    private String perms;
    /**
     * 子菜单
     */
    @TableField(exist = false)
    private List<SysMenu> children;
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/menu/mapper/SysMenuMapper.java
New file
@@ -0,0 +1,20 @@
package com.mes.menu.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.mes.menu.entity.SysMenu;
import java.util.List;
/**
 * <p>
 * 菜单表 Mapper 接口
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
public interface SysMenuMapper extends MPJBaseMapper<SysMenu> {
    List<String> selectPermsByUserId(long parseLong);
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/menu/service/SysMenuService.java
New file
@@ -0,0 +1,66 @@
package com.mes.menu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.mes.entity.request.GeneralRequest;
import com.mes.menu.entity.SysMenu;
import java.util.List;
import java.util.Map;
/**
 * <p>
 * 菜单表 服务类
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
public interface SysMenuService extends IService<SysMenu> {
    /**
     * 更新菜单信息
     *
     * @param menu
     * @return
     */
    SysMenu updateMenu(SysMenu menu);
    /**
     * 获取用户有权限的菜单树
     *
     * @return
     */
    List<SysMenu> getMenuTree(GeneralRequest request);
    /**
     * 获取用户的权限
     *
     * @return
     */
    List<String> getAuthorityInfo();
    /**
     * 获取用户菜单及权限信息
     *
     * @return
     */
    Map<Object, Object> nav();
    /**
     * 删除菜单信息
     *
     * @param menuId
     * @return
     */
    String deleteMenu(Long menuId);
    /**
     * 批量删除菜单信息
     *
     * @param menuIds
     * @return
     */
    String batchDeleteMenu(List<Long> menuIds);
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/menu/service/impl/SysMenuServiceImpl.java
New file
@@ -0,0 +1,148 @@
package com.mes.menu.service.impl;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.mes.common.utils.UserInfoUtils;
import com.mes.entity.request.GeneralRequest;
import com.mes.menu.entity.SysMenu;
import com.mes.menu.mapper.SysMenuMapper;
import com.mes.menu.service.SysMenuService;
import com.mes.role.entity.SysRoleMenu;
import com.mes.role.service.SysRoleMenuService;
import com.mes.userinfo.entity.SysUser;
import com.mes.userinfo.entity.SysUserRole;
import com.mes.userinfo.mapper.SysUserRoleMapper;
import com.mes.userinfo.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * <p>
 * 菜单表 服务实现类
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
@Service
@Slf4j
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {
    @Autowired
    SysUserService sysUserService;
    @Autowired
    SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    SysRoleMenuService sysRoleMenuService;
    @Override
    public SysMenu updateMenu(SysMenu menu) {
        baseMapper.updateById(menu);
        // 清除所有与该菜单相关的权限缓存
        sysUserService.clearUserAuthorityInfoByMenuId(menu.getId());
        return menu;
    }
    @Override
    public List<SysMenu> getMenuTree(GeneralRequest request) {
        //todo:需要先获取用户的角色,角色下的菜单权限,拿到菜单id获取所有菜单
        SysUser user = UserInfoUtils.get();
        MPJLambdaWrapper<SysUserRole> wrapper = new MPJLambdaWrapper<>();
        wrapper.selectAll(SysMenu.class).distinct()
                .innerJoin(SysUser.class, SysUser::getId, SysUserRole::getUserId)
                .innerJoin(SysRoleMenu.class, SysRoleMenu::getRoleId, SysUserRole::getRoleId)
                .innerJoin(SysMenu.class, SysMenu::getId, SysRoleMenu::getMenuId)
                .eq(SysUser::getId, user.getId())
                .like(StringUtils.isNotBlank(request.getKey()), SysMenu::getMenuName, request.getKey());
        //
        List<SysMenu> menuList = sysUserRoleMapper.selectJoinList(SysMenu.class, wrapper);
        log.info("userinfos:{}",menuList);
        return create(menuList);
    }
    @Override
    public List<String> getAuthorityInfo() {
        SysUser user = UserInfoUtils.get();
        log.info("获取用户信息,用户名为{}", user);
        // 获取权限信息
        // ROLE_admin,ROLE_normal,sys:user:list,....
        return sysUserService.getUserAuthorityInfo(user.getId());
    }
    @Override
    public Map<Object, Object> nav() {
        List<SysMenu> menuTree = getMenuTree(new GeneralRequest());
        List<String> authorityInfo = getAuthorityInfo();
        return MapUtil.builder().put("authoritys", authorityInfo)
                .put("tree", menuTree).map();
    }
    @Override
    public String deleteMenu(Long menuId) {
        int count = this.count(new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getParentId, menuId));
        if (count > 0) {
            return "无法删除,请先删除子菜单";
        }
        // 清除所有与该菜单相关的权限缓存
        sysUserService.clearUserAuthorityInfoByMenuId(menuId);
        this.removeById(menuId);
        // 同步删除中间关联表
        sysRoleMenuService.remove(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getMenuId, menuId));
        return "删除成功";
    }
    @Override
    public String batchDeleteMenu(List<Long> menuIds) {
        menuIds.stream().forEach(e -> deleteMenu(e));
        return "批量删除成功";
    }
    /**
     * 将数据库中查询出来的list集合传入此方法即可获得排成树形结构的list集合
     *
     * @param lists
     * @return
     */
    public List<SysMenu> create(List<SysMenu> lists) {
        List<SysMenu> deptTreeList = lists.stream()
                .filter(item -> item.getParentId() == 0)
                .map(item -> {
                    item.setChildren(getChildren(item, lists));
                    return item;
                }).collect(Collectors.toList());
        return deptTreeList;
    }
    /**
     * 此方法将被递归调用
     *
     * @param menu
     * @param menus
     * @return
     */
    private List<SysMenu> getChildren(SysMenu menu, List<SysMenu> menus) {
        List<SysMenu> res = menus.stream()
                .filter(item -> item.getParentId().equals(menu.getId()))
                .collect(Collectors.toList());
        log.info("菜单树:{}", JSONUtil.toJsonStr(res));
        return res;
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/controller/SysRoleController.java
New file
@@ -0,0 +1,67 @@
package com.mes.role.controller;
import com.mes.entity.request.GeneralRequest;
import com.mes.role.entity.SysRole;
import com.mes.role.entity.vo.SysRoleVO;
import com.mes.role.service.SysRoleService;
import com.mes.utils.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
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;
/**
 * @author zhoush
 * @since 2024-04-11
 */
@Api(description = "角色管理")
@RestController
@RequestMapping("/sys/role")
public class SysRoleController {
    @Autowired
    private SysRoleService sysRoleService;
    @ApiOperation("新增角色及角色下的权限信息")
    @PostMapping("/saveRole")
//    @PreAuthorize("hasAuthority('sys:role:save')")
    public Result<SysRoleVO> saveRole(@Validated @RequestBody SysRoleVO sysRoleVO) {
        //return Result.success(sysRoleService.saveRole(sysRoleVO));
        sysRoleService.saveRole(sysRoleVO);
        return Result.build(200,"新增成功",sysRoleVO);
    }
    @ApiOperation("编辑角色及角色下的权限信息")
    @PostMapping("/updateRole")
//    @PreAuthorize("hasAuthority('sys:role:save')")
    public Result<SysRoleVO> updateRole(@Validated @RequestBody SysRoleVO sysRoleVO) {
       // return Result.success(sysRoleService.updateRole(sysRoleVO));
        sysRoleService.updateRole(sysRoleVO);
        return Result.build(200,"新增成功",sysRoleVO);
    }
    @ApiOperation("查询角色及角色下的权限信息")
    @PostMapping("/queryRole")
//    @PreAuthorize("hasAuthority('sys:role:save')")
    public Result<List<SysRoleVO>> queryRole(@Validated @RequestBody GeneralRequest request) {
        return Result.success(sysRoleService.queryRole(request));
    }
    @ApiOperation("删除角色及角色下的权限信息")
    @PostMapping("/delete")
//    @PreAuthorize("hasAuthority('sys:role:delete')")
    @Transactional
    public Result<String> deleteRole(@RequestBody List<Long> ids) {
        return Result.build(200,"删除成功",sysRoleService.deleteRole(ids));
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/entity/SysRole.java
New file
@@ -0,0 +1,50 @@
package com.mes.role.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
 * <p>
 * 角色表
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class SysRole implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    private String name;
    /**
     * 角色权限字符串
     */
    private String roleKey;
    /**
     * 角色状态(0正常 1停用)
     */
    private String status;
    /**
     * 删除标志
     */
    private Integer delFlag;
    /**
     * 备注
     */
    private String remark;
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/entity/SysRoleMenu.java
New file
@@ -0,0 +1,36 @@
package com.mes.role.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
 * <p>
 *
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class SysRoleMenu implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 角色ID
     */
    @TableId(type = IdType.NONE)
    private Long roleId;
    /**
     * 菜单id
     */
    private Long menuId;
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/entity/vo/SysRoleVO.java
New file
@@ -0,0 +1,44 @@
package com.mes.role.entity.vo;
import com.mes.menu.entity.SysMenu;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
 * @Author : zhoush
 * @Date: 2024/4/26 13:57
 * @Description:
 */
@Api(description = "角色信息")
@Data
public class SysRoleVO implements Serializable {
    @ApiModelProperty(hidden = true)
    private static final long serialVersionUID = 1L;
    @ApiModelProperty(value = "角色ID", position = 2)
    private Long id;
    @ApiModelProperty(value = "角色名称", position = 3)
    private String name;
    @ApiModelProperty(value = "角色权限字符串", position = 4)
    private String roleKey;
    @ApiModelProperty(value = "角色状态(0正常 1停用)", position = 5)
    private String status;
    @ApiModelProperty(value = "删除标志", position = 6)
    private Integer delFlag;
    @ApiModelProperty(value = "备注", position = 7)
    private String remark;
    @ApiModelProperty(value = "角色菜单信息", position = 8)
    private List<SysMenu> menuList;
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/mapper/SysRoleMapper.java
New file
@@ -0,0 +1,16 @@
package com.mes.role.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.mes.role.entity.SysRole;
/**
 * <p>
 * 角色表 Mapper 接口
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
public interface SysRoleMapper extends MPJBaseMapper<SysRole> {
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/mapper/SysRoleMenuMapper.java
New file
@@ -0,0 +1,17 @@
package com.mes.role.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mes.role.entity.SysRoleMenu;
/**
 * <p>
 * Mapper 接口
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
public interface SysRoleMenuMapper extends BaseMapper<SysRoleMenu> {
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/mapper/xml/SysRoleMapper.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mes.role.mapper.SysRoleMapper">
</mapper>
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/mapper/xml/SysRoleMenuMapper.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mes.role.mapper.SysRoleMenuMapper">
</mapper>
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/service/SysRoleMenuService.java
New file
@@ -0,0 +1,16 @@
package com.mes.role.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.mes.role.entity.SysRoleMenu;
/**
 * <p>
 * 服务类
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
public interface SysRoleMenuService extends IService<SysRoleMenu> {
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/service/SysRoleService.java
New file
@@ -0,0 +1,51 @@
package com.mes.role.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.mes.entity.request.GeneralRequest;
import com.mes.role.entity.SysRole;
import com.mes.role.entity.vo.SysRoleVO;
import java.util.List;
/**
 * <p>
 * 角色表 服务类
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
public interface SysRoleService extends IService<SysRole> {
    /**
     * 创建角色信息
     *
     * @param sysRoleVO
     * @return
     */
    SysRole saveRole(SysRoleVO sysRoleVO);
    /**
     * 修改角色信息及权限
     *
     * @param sysRoleVO
     * @return
     */
    String updateRole(SysRoleVO sysRoleVO);
    /**
     * 按照角色名查询角色信息
     *
     * @param request
     * @return
     */
    List<SysRoleVO> queryRole(GeneralRequest request);
    /**
     * 查询角色及角色下的权限信息
     *
     * @param ids
     * @return
     */
    String deleteRole(List<Long> ids);
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/service/impl/SysRoleMenuServiceImpl.java
New file
@@ -0,0 +1,20 @@
package com.mes.role.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mes.role.entity.SysRoleMenu;
import com.mes.role.mapper.SysRoleMenuMapper;
import com.mes.role.service.SysRoleMenuService;
import org.springframework.stereotype.Service;
/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
@Service
public class SysRoleMenuServiceImpl extends ServiceImpl<SysRoleMenuMapper, SysRoleMenu> implements SysRoleMenuService {
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/role/service/impl/SysRoleServiceImpl.java
New file
@@ -0,0 +1,139 @@
package com.mes.role.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.mes.entity.request.GeneralRequest;
import com.mes.menu.entity.SysMenu;
import com.mes.role.entity.SysRole;
import com.mes.role.entity.SysRoleMenu;
import com.mes.role.entity.vo.SysRoleVO;
import com.mes.role.mapper.SysRoleMapper;
import com.mes.role.service.SysRoleMenuService;
import com.mes.role.service.SysRoleService;
import com.mes.userinfo.entity.SysUserRole;
import com.mes.userinfo.service.SysUserRoleService;
import com.mes.userinfo.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.stream.Collectors;
/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
@Service
@Slf4j
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {
    @Autowired
    SysRoleMenuService sysRoleMenuService;
    @Autowired
    SysUserService sysUserService;
    @Autowired
    SysUserRoleService sysUserRoleService;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SysRole saveRole(SysRoleVO sysRoleVO) {
        log.info("保存角色信息,生成对应的角色id");
        SysRole sysRole = new SysRole();
        BeanUtils.copyProperties(sysRoleVO, sysRole);
        this.save(sysRole);
        //保存角色权限信息
        saveRoleMenu(sysRole.getId(), sysRoleVO.getMenuList());
        return sysRole;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String updateRole(SysRoleVO sysRoleVO) {
        log.info("保存角色信息,生成对应的角色id");
        SysRole sysRole = new SysRole();
        BeanUtils.copyProperties(sysRoleVO, sysRole);
        this.updateById(sysRole);
        //保存角色权限信息
        return saveRoleMenu(sysRole.getId(), sysRoleVO.getMenuList());
    }
    @Override
    public List<SysRoleVO> queryRole(GeneralRequest request) {
        MPJLambdaWrapper<SysRole> wrapper = new MPJLambdaWrapper<>();
        wrapper.selectAll(SysRole.class)
                .selectCollection(SysMenu.class, SysRoleVO::getMenuList)
                .leftJoin(SysRoleMenu.class, SysRoleMenu::getRoleId, SysRole::getId)
                .leftJoin(SysMenu.class, SysMenu::getId, SysRoleMenu::getMenuId)
                .like(StringUtils.hasText(request.getKey()), SysRole::getName, request.getKey());
        return baseMapper.selectJoinList(SysRoleVO.class, wrapper);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String deleteRole(List<Long> ids) {
        log.info("删除角色信息");
        this.removeByIds(ids);
        log.info("删除中间表信息");
        sysUserRoleService.remove(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, ids));
        sysRoleMenuService.remove(new LambdaQueryWrapper<SysRoleMenu>().in(SysRoleMenu::getRoleId, ids));
        log.info("清空缓存中的权限信息");
        ids.stream().forEach(id -> sysUserService.clearUserAuthorityInfoByRoleId(id));
        return "success";
    }
    /**
     * 保存角色权限信息
     *
     * @param roleId
     * @param menuList
     * @return
     */
    private String saveRoleMenu(Long roleId, List<SysMenu> menuList) {
        log.info("配置角色菜单关系");
        if (CollectionUtils.isEmpty(menuList)) {
            // 先删除原来的记录,再保存新的
            sysRoleMenuService.remove(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
            // 删除缓存
            sysUserService.clearUserAuthorityInfoByRoleId(roleId);
            return "success";
        }
        List<SysRoleMenu> roleMenuList = menuList.stream().map(menu -> {
            SysRoleMenu roleMenu = new SysRoleMenu();
            roleMenu.setRoleId(roleId);
            roleMenu.setMenuId(menu.getId());
            return roleMenu;
        }).collect(Collectors.toList());
        // 使用流处理菜单列表,提取 children 的 id,并设置到 SysRoleMenu 中
        List<SysRoleMenu> childrenList = menuList.stream()
                .flatMap(menu -> menu.getChildren().stream()) // 扁平化处理 children 列表
                .map(child -> {
                    SysRoleMenu roleMenu = new SysRoleMenu();
                    roleMenu.setRoleId(roleId);
                    roleMenu.setMenuId(child.getId()); // 设置 child 的 id 到 menuId
                    return roleMenu;
                })
                .collect(Collectors.toList());
        log.info("清空角色权限表中该角色信息");
        // 先删除原来的记录,再保存新的
        sysRoleMenuService.remove(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
        sysRoleMenuService.saveBatch(roleMenuList);
        sysRoleMenuService.saveBatch(childrenList);
        // 删除缓存
        sysUserService.clearUserAuthorityInfoByRoleId(roleId);
        return "success";
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/controller/SysUserController.java
New file
@@ -0,0 +1,93 @@
package com.mes.userinfo.controller;
import com.mes.entity.request.GeneralRequest;
import com.mes.userinfo.entity.SysUser;
import com.mes.userinfo.entity.vo.SysUserVO;
import com.mes.userinfo.service.SysUserService;
import com.mes.utils.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
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;
import java.util.Map;
/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
@Api(description = "用户管理")
@RestController
@RequestMapping("/sys/user")
public class SysUserController {
    @Autowired
    private SysUserService sysUserService;
    @ApiOperation("用户登录")
    @PostMapping("/login")
    public Result<Map<String, String>> login(@RequestBody SysUser user) {
        return Result.success(sysUserService.login(user));
    }
    @ApiOperation("退出登录")
    @PostMapping("/logout")
    @PreAuthorize("hasAuthority('xt:yh')")
    public Result<String> logout() {
        return Result.success(sysUserService.logout());
    }
    @ApiOperation("新增用户信息")
    @PostMapping("/saveUser")
//    @PreAuthorize("hasAuthority('sys:user:save')")
    public Result<String> saveUser(@Validated @RequestBody SysUserVO sysUser) {
        return Result.success(sysUserService.saveUser(sysUser));
    }
    @ApiOperation("更新用户信息")
    @PostMapping("/updateUser")
//    @PreAuthorize("hasAuthority('sys:user:update')")
    public Result<List<SysUserVO>> updateUser(@Validated @RequestBody SysUserVO sysUser) {
        sysUserService.updateUser(sysUser);
        GeneralRequest request=new GeneralRequest();
        //request.setKey("");
        return Result.success(sysUserService.listByUserName(request));
        //更改了修改之后返回所有用户列表
    }
    @ApiOperation("重置密码")
    @PostMapping("/resetPassword")
//    @PreAuthorize("hasAuthority('sys:user:resetPassword')")
    public Result resetPassword(String userId) {
        return Result.success(sysUserService.resetPassword(Long.parseLong(userId)));
    }
    @ApiOperation("获取用户列表")
    @PostMapping("/listByUserName")
//    @PreAuthorize("hasAuthority('sys:user:list')")
    public Result<List<SysUserVO>> listByUserName(@RequestBody GeneralRequest request) {
        return Result.success(sysUserService.listByUserName(request));
    }
    @ApiOperation("删除用户信息")
    @PostMapping("/deleteUser")
//    @PreAuthorize("hasAuthority('sys:user:delete')")
    public Result<String> deleteUser(@RequestBody List<Long> ids) {
        return Result.success(sysUserService.deleteUser(ids));
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/entity/LoginUser.java
New file
@@ -0,0 +1,94 @@
package com.mes.userinfo.entity;
import com.alibaba.fastjson.annotation.JSONField;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
 * @Author : zhoush
 * @Date: 2024/4/11 15:46
 * @Description:
 */
public class LoginUser implements UserDetails {
    private SysUser user;
    /**
     * 存储权限信息
     */
    @JSONField(serialize = false)
    private List<String> permissions;
    /**
     * 存储SpringSecurity调用getAuthorities()方法获取的权限信息的集合
     */
    @JSONField(serialize = false)
    private List<GrantedAuthority> authorities;
    public LoginUser() {
    }
    public LoginUser(SysUser user, List<String> permissions) {
        this.user = user;
        this.permissions = permissions;
    }
    public SysUser getUser() {
        return user;
    }
    public void setUser(SysUser user) {
        this.user = user;
    }
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // 优化为只需要第一次获取的时候进行遍历,后面再用就会从authorities这个成员变量中获取了,不会再进行Stream循环遍历了
        if (authorities != null) {
            return authorities;
        }
        //把permissions中字符串类型的权限信息转换成GrantedAuthority对象存入authorities中
        authorities = permissions.stream().
                map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
        return authorities;
    }
    @Override
    public String getPassword() {
        return user.getPassword();
    }
    @Override
    public String getUsername() {
        return user.getUserName();
    }
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {
        return true;
    }
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/entity/SysUser.java
New file
@@ -0,0 +1,67 @@
package com.mes.userinfo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
 * <p>
 * 用户表
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class SysUser implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * 用户名
     */
    private String userName;
    /**
     * 昵称
     */
    private String nickName;
    /**
     * 密码
     */
    private String password;
    /**
     * 账号状态(0正常 1停用)
     */
    private String status;
    /**
     * 头像
     */
    private String avatar;
    /**
     * 用户类型(0管理员,1普通用户)
     */
    private String userType;
    /**
     * 删除标志
     */
    private Integer delFlag;
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/entity/SysUserRole.java
New file
@@ -0,0 +1,38 @@
package com.mes.userinfo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
 * <p>
 *
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
public class SysUserRole implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 用户id
     */
    @TableId(type = IdType.NONE)
    private Long userId;
    /**
     * 角色id
     */
    private Long roleId;
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/entity/vo/SysUserVO.java
New file
@@ -0,0 +1,63 @@
package com.mes.userinfo.entity.vo;
import com.mes.role.entity.SysRole;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
 * <p>
 * 用户表
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
@Api(description = "用户信息")
@Data
public class SysUserVO implements Serializable {
    @ApiModelProperty(hidden = true)
    private static final long serialVersionUID = 1L;
    /**
     * 主键
     */
    @ApiModelProperty(value = "主键", position = 2)
    private Long id;
    /**
     * 用户名
     */
    @ApiModelProperty(value = "用户名", position = 3)
    private String userName;
    /**
     * 昵称
     */
    @ApiModelProperty(value = "昵称", position = 4)
    private String nickName;
    /**
     * 密码
     */
    @ApiModelProperty(value = "密码", position = 5)
    private String password;
    /**
     * 头像
     */
    @ApiModelProperty(value = "头像", position = 6)
    private String avatar;
    /**
     * 用户的角色信息
     */
    @ApiModelProperty(value = "用户的角色信息", position = 7)
    private List<SysRole> roleList;
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/mapper/SysUserMapper.java
New file
@@ -0,0 +1,18 @@
package com.mes.userinfo.mapper;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.github.yulichang.base.MPJBaseMapper;
import com.mes.userinfo.entity.SysUser;
/**
 * <p>
 * 用户表 Mapper 接口
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
@DS("hangzhoumes")
public interface SysUserMapper extends MPJBaseMapper<SysUser> {
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/mapper/SysUserRoleMapper.java
New file
@@ -0,0 +1,17 @@
package com.mes.userinfo.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.mes.userinfo.entity.SysUserRole;
/**
 * <p>
 * Mapper 接口
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
public interface SysUserRoleMapper extends MPJBaseMapper<SysUserRole> {
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/mapper/xml/SysUserMapper.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mes.userinfo.mapper.SysUserMapper">
</mapper>
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/mapper/xml/SysUserRoleMapper.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mes.userinfo.mapper.SysUserRoleMapper">
</mapper>
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/service/SysUserRoleService.java
New file
@@ -0,0 +1,17 @@
package com.mes.userinfo.service;
import com.github.yulichang.base.MPJBaseService;
import com.mes.userinfo.entity.SysUserRole;
/**
 * <p>
 * 服务类
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
public interface SysUserRoleService extends MPJBaseService<SysUserRole> {
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/service/SysUserService.java
New file
@@ -0,0 +1,110 @@
package com.mes.userinfo.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.mes.entity.request.GeneralRequest;
import com.mes.userinfo.entity.SysUser;
import com.mes.userinfo.entity.vo.SysUserVO;
import java.util.List;
import java.util.Map;
/**
 * <p>
 * 用户表 服务类
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
public interface SysUserService extends IService<SysUser> {
    /**
     * 用户登录
     *
     * @param user
     * @return
     */
    Map<String, String> login(SysUser user);
    /**
     * 退出登录
     *
     * @return
     */
    String logout();
    /**
     * 新增用户信息
     *
     * @param user
     * @return
     */
    String saveUser(SysUserVO user);
    /**
     * 更新用户信息
     *
     * @param sysUser
     * @return
     */
    SysUserVO updateUser(SysUserVO sysUser);
    /**
     * 重置密码
     *
     * @param userId
     * @return
     */
    String resetPassword(Long userId);
    /**
     * 按名称获取用户信息
     *
     * @param userName
     * @return
     */
    SysUser queryByUserName(String userName);
    /**
     * 按关键字获取用户信息列表
     *
     * @param request
     * @return
     */
    List<SysUserVO> listByUserName(GeneralRequest request);
    /**
     * 删除用户信息
     *
     * @param ids
     * @return
     */
    String deleteUser(List<Long> ids);
    /**
     * 获取用户角色权限信息
     *
     * @param userId
     * @return
     */
    List<String> getUserAuthorityInfo(Long userId);
    /**
     * 清空用户权限信息通过用户信息
     */
    void clearUserAuthorityInfo(String userName);
    /**
     * 清空用户权限信息通过角色id
     *
     * @param roleId
     */
    void clearUserAuthorityInfoByRoleId(Long roleId);
    /**
     * 清空用户权限信息通过菜单id
     *
     * @param menuId
     */
    void clearUserAuthorityInfoByMenuId(Long menuId);
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/service/impl/SysUserRoleServiceImpl.java
New file
@@ -0,0 +1,20 @@
package com.mes.userinfo.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mes.userinfo.entity.SysUserRole;
import com.mes.userinfo.mapper.SysUserRoleMapper;
import com.mes.userinfo.service.SysUserRoleService;
import org.springframework.stereotype.Service;
/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
@Service
public class SysUserRoleServiceImpl extends ServiceImpl<SysUserRoleMapper, SysUserRole> implements SysUserRoleService {
}
ShangHaiMesParent/common/springsecurity/src/main/java/com/mes/userinfo/service/impl/SysUserServiceImpl.java
New file
@@ -0,0 +1,271 @@
package com.mes.userinfo.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.mes.common.config.Const;
import com.mes.common.utils.JwtUtil;
import com.mes.common.utils.RedisUtil;
import com.mes.common.utils.UserInfoUtils;
import com.mes.entity.request.GeneralRequest;
import com.mes.menu.mapper.SysMenuMapper;
import com.mes.role.entity.SysRole;
import com.mes.role.entity.SysRoleMenu;
import com.mes.role.service.SysRoleService;
import com.mes.userinfo.entity.LoginUser;
import com.mes.userinfo.entity.SysUser;
import com.mes.userinfo.entity.SysUserRole;
import com.mes.userinfo.entity.vo.SysUserVO;
import com.mes.userinfo.mapper.SysUserMapper;
import com.mes.userinfo.mapper.SysUserRoleMapper;
import com.mes.userinfo.service.SysUserRoleService;
import com.mes.userinfo.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author zhoush
 * @since 2024-04-11
 */
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService, UserDetailsService {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private RedisUtil redisUtil;
    @Resource
    private SysMenuMapper sysMenuMapper;
    @Resource
    private SysUserRoleService sysUserRoleService;
    @Resource
    private SysRoleService sysRoleService;
    @Resource
    BCryptPasswordEncoder passwordEncoder;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;
    @Override
    public Map<String, String> login(SysUser user) {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        if (Objects.isNull(authenticate)) {
            throw new RuntimeException("用户名或密码错误");
        }
        //使用userid生成token
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        String userId = loginUser.getUser().getId().toString();
        String jwt = JwtUtil.generateToken(userId);
        //查询权限信息
//        List<String> perms = sysMenuMapper.selectPermsByUserId(userId);
        //authenticate存入redis
        redisUtil.setCacheObject("login:" + userId, loginUser);
        //把token响应给前端
        HashMap<String, String> map = new HashMap<>();
        map.put("token", jwt);
        return map;
    }
    @Override
    public String logout() {
        log.info("用户退出");
        SysUser user = UserInfoUtils.get();
        redisUtil.deleteObject("login:" + user.getId());
        return "注销成功";
    }
    @Transactional
    @Override
    public String saveUser(SysUserVO user) {
        log.info("保存用户信息");
        // 默认密码
        String password = passwordEncoder.encode(Const.DEFULT_PASSWORD);
        user.setPassword(password);
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(user, sysUser);
        this.save(sysUser);
        saveUserRole(user.getRoleList(), sysUser.getId());
        return "success";
    }
    @Transactional
    @Override
    public SysUserVO updateUser(SysUserVO user) {
        log.info("更新用户信息");
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(user, sysUser);
        this.updateById(sysUser);
        log.info("删除用户角色信息");
        List<Long> roleIds = user.getRoleList().stream().map(SysRole::getId).collect(Collectors.toList());
//        sysUserRoleService.remove(new LambdaQueryWrapper<SysUserRole>()
//                .eq(SysUserRole::getUserId, sysUser.getId()).in(CollectionUtil.isNotEmpty(roleIds), SysUserRole::getRoleId, roleIds));
        SysUserRole sysUserRole = new SysUserRole(sysUser.getId(),roleIds.get(0));
        sysUserRoleMapper.updateById(sysUserRole);
//        log.info("保存用户角色信息");
//        saveUserRole(user.getRoleList(), sysUser.getId());
        return user;
    }
    @Override
    public String resetPassword(Long userId) {
        log.info("重置密码为{}", Const.DEFULT_PASSWORD);
        SysUser sysUser = new SysUser();
        sysUser.setId(userId);
        String password = passwordEncoder.encode(Const.DEFULT_PASSWORD);
        sysUser.setPassword(password);
        this.updateById(sysUser);
        return "success";
    }
    @Override
    public SysUser queryByUserName(String userName) {
        return baseMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, userName));
    }
    @Override
    public List<SysUserVO> listByUserName(GeneralRequest request) {
        MPJLambdaWrapper<SysUser> wrapper = new MPJLambdaWrapper<>();
        wrapper.selectAll(SysUser.class)
                .selectCollection(SysRole.class, SysUserVO::getRoleList)
                .leftJoin(SysUserRole.class, SysUserRole::getUserId, SysUser::getId)
                .leftJoin(SysRole.class, SysRole::getId, SysUserRole::getRoleId)
                .like(StringUtils.hasText(request.getKey()), SysUser::getUserName, request.getKey());
        return baseMapper.selectJoinList(SysUserVO.class, wrapper);
    }
    @Transactional
    @Override
    public String deleteUser(List<Long> ids) {
        this.removeByIds(ids);
        sysUserRoleService.remove(new QueryWrapper<SysUserRole>().in("user_id", ids));
        return "success";
    }
    @Override
    public List<String> getUserAuthorityInfo(Long userId) {
        SysUser sysUser = baseMapper.selectById(userId);
        //  ROLE_admin,ROLE_normal,sys:user:list,....
        String authority = "";
        if (redisUtil.hasKey("GrantedAuthority:" + sysUser.getUserName())) {
            authority = redisUtil.getCacheObject("GrantedAuthority:" + sysUser.getUserName());
        } else {
            // 获取角色编码
            List<SysRole> roles = sysRoleService.list(new QueryWrapper<SysRole>()
                    .inSql("id", "select role_id from sys_user_role where user_id = " + userId));
            if (roles.size() > 0) {
                String roleCodes = roles.stream().map(r -> "ROLE_" + r.getRoleKey()).collect(Collectors.joining(","));
                authority = roleCodes.concat(",");
            }
            // 获取菜单操作编码
            List<String> perms = sysMenuMapper.selectPermsByUserId(userId);
            if (perms.size() > 0) {
                String menuPerms = String.join(",", perms);
                authority = authority.concat(menuPerms);
            }
            redisUtil.setCacheObject("GrantedAuthority:" + sysUser.getUserName(), authority, 60 * 60, TimeUnit.SECONDS);
        }
        return Arrays.stream(authority.split(",")).collect(Collectors.toList());
    }
    @Override
    public void clearUserAuthorityInfo(String userName) {
        redisUtil.deleteObject("GrantedAuthority:" + userName);
    }
    @Override
    public void clearUserAuthorityInfoByRoleId(Long roleId) {
        List<SysUser> sysUsers = this.list(new QueryWrapper<SysUser>()
                .inSql("id", "select user_id from sys_user_role where role_id = " + roleId));
        sysUsers.forEach(u -> {
            this.clearUserAuthorityInfo(u.getUserName());
        });
    }
    @Override
    public void clearUserAuthorityInfoByMenuId(Long menuId) {
        MPJLambdaWrapper<SysUserRole> wrapper = new MPJLambdaWrapper<SysUserRole>().selectAll(SysUser.class).distinct()
                .leftJoin(SysUser.class, SysUser::getId, SysUserRole::getUserId)
                .leftJoin(SysRoleMenu.class, SysRoleMenu::getRoleId, SysUserRole::getRoleId)
                .eq(SysRoleMenu::getMenuId, menuId);
        List<SysUser> sysUsers = sysUserRoleService.selectJoinList(SysUser.class, wrapper);
        sysUsers.forEach(u -> {
            this.clearUserAuthorityInfo(u.getUserName());
        });
    }
    /**
     * 实现UserDetailsService接口,从数据库内获取用户及权限信息
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysUser::getUserName, username);
        SysUser user = this.baseMapper.selectOne(lqw);
        //判断是否为空
        if (Objects.isNull(user)) {
            throw new RuntimeException("用户名或密码错误");
        }
        //查询权限信息
        List<String> perms = sysMenuMapper.selectPermsByUserId(user.getId());
        return new LoginUser(user, perms);
    }
    private void saveUserRole(List<SysRole> roles, Long userId) {
        log.info("保存用户角色信息");
        List<SysUserRole> userRoles = new ArrayList<>();
        if (CollectionUtils.isEmpty(roles)) {
            log.info("保存用户角色信息为空,给默认普通用户角色");
            userRoles.add(new SysUserRole(userId, Const.DEFULT_ROLE));
        } else {
            log.info("保存用户角色信息");
            userRoles = roles.stream().map(e -> new SysUserRole(userId, e.getId())).collect(Collectors.toList());
        }
        sysUserRoleService.saveBatch(userRoles);
    }
}
ShangHaiMesParent/common/springsecurity/src/main/resources/application-dev.yml
New file
@@ -0,0 +1,15 @@
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/jiumumes?serverTimezone=GMT%2b8&characterEncoding=utf-8&useSSL=false
    username: root
    password: beibo.123/
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  redis:
    database: 0
    host: localhost
    port: 6379
    password: 123456
ShangHaiMesParent/common/springsecurity/src/main/resources/application-loc.yml
New file
@@ -0,0 +1,15 @@
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/jiumumes?serverTimezone=GMT%2b8&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    password: 123456
ShangHaiMesParent/common/springsecurity/src/main/resources/application-prod.yml
New file
@@ -0,0 +1,15 @@
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/jiumumes?serverTimezone=GMT%2b8&characterEncoding=utf-8&useSSL=false
    username: root
    password: beibo.123/
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  redis:
    database: 0
    host: localhost
    port: 6379
    password: 123456
ShangHaiMesParent/common/springsecurity/src/main/resources/mapper/SysMenuMapper.xml
New file
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mes.menu.mapper.SysMenuMapper">
    <select id="selectPermsByUserId" resultType="java.lang.String">
        SELECT DISTINCT m.perms
        FROM sys_user_role ur
                 LEFT JOIN sys_role r ON ur.role_id = r.id
                 LEFT JOIN sys_role_menu rm ON ur.role_id = rm.role_id
                 LEFT JOIN sys_menu m ON m.id = rm.menu_id
        WHERE user_id = #{userid}
          AND r.status = 0
          AND m.status = 0
    </select>
</mapper>
ShangHaiMesParent/gateway/gateway1.iml
New file
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
</module>
ShangHaiMesParent/gateway/pom.xml
New file
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ShangHaiMesParent</artifactId>
        <groupId>com.mes</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>gateway</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!--        服务注册/发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
ShangHaiMesParent/gateway/src/main/java/com/mes/GateWayApplication.java
New file
@@ -0,0 +1,20 @@
package com.mes;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
 * @Author : yanzhixin
 * @Date: 2024/3/28 11:21
 * @Description:
 */
@SpringBootApplication
@EnableDiscoveryClient
public class GateWayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GateWayApplication.class, args);
    }
}
ShangHaiMesParent/gateway/src/main/java/com/mes/config/MyCorsConfig.java
New file
@@ -0,0 +1,34 @@
package com.mes.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
/**
 * @Author : yanzhixin
 * @Date: 2024/3/25 14:13
 * @Description:
 */
@Configuration
public class MyCorsConfig {
    @Bean
    public CorsWebFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //允许哪些头跨域
        corsConfiguration.addAllowedHeader("*");
        // 允许哪些方式跨域   get  post  delete 等方式
        corsConfiguration.addAllowedMethod("*");
        //允许哪些请求来源跨域    *  任意来源
        corsConfiguration.addAllowedOrigin("*");
        // 是否允许携带cooker跨域
        corsConfiguration.setAllowCredentials(true);
        //注册跨越配置       /**配置请求路径
        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsWebFilter(source);
    }
}
ShangHaiMesParent/gateway/src/main/resources/application.yml
New file
@@ -0,0 +1,20 @@
server:
  port: 88
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: deviceInteraction
          uri: lb://deviceInteraction
          predicates:
            - Path=/api/deviceInteraction/**
          filters:
            - StripPrefix=2
ShangHaiMesParent/moduleService/plcConnectModule/pom.xml
New file
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>moduleService</artifactId>
        <groupId>com.mes</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>plcConnect</artifactId>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.samba.jcifs</groupId>
            <artifactId>jcifs</artifactId>
            <version>1.2.19</version>
        </dependency>
        <dependency>
            <groupId>com.github.s7connector</groupId>
            <artifactId>s7connector</artifactId>
            <version>2.1</version>
        </dependency>
<!--        <dependency>-->
<!--            <groupId>com.github.yulichang</groupId>-->
<!--            <artifactId>mybatis-plus-join-boot-starter</artifactId>-->
<!--            <version>1.4.12</version>-->
<!--        </dependency>-->
    </dependencies>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
</project>
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/AppRunnerConfig.java
New file
@@ -0,0 +1,48 @@
package com.mes;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.mes.connect.IndustrialInterface.Api;
import com.mes.connect.Thread.MachineThread;
import com.mes.model.entity.Machine;
import com.mes.model.mapper.MachineMapper;
import com.mes.model.service.MachineService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Component
@Order(1)
public class AppRunnerConfig implements ApplicationRunner {
    @Autowired
    Api api;
    @Autowired
    MachineService machineService;
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // TODO Auto-generated method stub
        //1.根据数据库设备表加载数据  得到全部 设备信息
        List<Machine> listMachine = machineService.getMachineConfig();
        //2.根据设备配置进行加载多线程
        for (int i = 1; i < listMachine.size(); i++)
            try {
                Machine machine = listMachine.get(i);
                Thread thread = new Thread(new MachineThread(machine, api));
                thread.start();
                thread.setName(machine.getName());
            } catch (Exception e) {
                // TODO: handle exception
                System.out.println("多线程异常!!");
            }
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/common/JsonConversion.java
New file
@@ -0,0 +1,18 @@
package com.mes.common;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonConversion {
    /**
     * 使用Jackson将JSON字符串转换为实体类
     */
    public static <T> T jsonToObjectByJackson(String json, Class<T> clazz) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            return mapper.readValue(json, clazz);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/common/ReadFile.java
New file
@@ -0,0 +1,40 @@
package com.mes.common;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class ReadFile {
    // 读取Json文件内容
    public static JSONObject readJson(String fileName) throws IOException {
        // 资源路径(相对于resources根目录)
        String resourcePath = "jsonFile/"+fileName;
        // 获取类加载器
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // 读取资源
        try (InputStream inputStream = classLoader.getResourceAsStream(resourcePath)) {
            if (inputStream == null) {
                throw new IOException("资源未找到: " + resourcePath);
            }
            StringBuilder content = new StringBuilder();
            // 读取文本内容
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String line;
            while ((line = reader.readLine()) != null) {
                content.append(line);
            }
            String str = content.toString();
            return JSONObject.parseObject(str);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        return null;
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/common/RestTemplateConfig.java
New file
@@ -0,0 +1,13 @@
package com.mes.common;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/ExampleDataHandler.java
New file
@@ -0,0 +1,169 @@
package com.mes.connect;
import com.mes.connect.IndustrialInterface.IndustrialDataHandler;
import com.mes.connect.addressParser.ModbusAddressParser;
import com.mes.connect.protocol.ProtocolAddress;
public class ExampleDataHandler implements IndustrialDataHandler {
    private final boolean[] coils = new boolean[1000];
    private final boolean[] discreteInputs = new boolean[1000];
    private final int[] holdingRegisters = new int[1000];
    private final int[] inputRegisters = new int[1000];
    @Override
    public boolean handleReadBit(String address) {
        ProtocolAddress parsedAddress = new ModbusAddressParser().parse(address);
        if (parsedAddress.getFunctionCode() == 1) { // 线圈
            int index = parsedAddress.getAddress();
            return coils[index];
        } else if (parsedAddress.getFunctionCode() == 2) { // 离散输入
            int index = parsedAddress.getAddress();
            return discreteInputs[index];
        }
        return false;
    }
    @Override
    public void handleWriteBit(String address, boolean value) {
        ProtocolAddress parsedAddress = new ModbusAddressParser().parse(address);
        if (parsedAddress.getFunctionCode() == 1) { // 线圈
            int index = parsedAddress.getAddress();
            coils[index] = value;
            System.out.println("写入线圈 " + address + " 值: " + value);
        }
    }
    @Override
    public int handleReadRegister(String address) {
        ProtocolAddress parsedAddress = new ModbusAddressParser().parse(address);
        if (parsedAddress.getFunctionCode() == 3) { // 保持寄存器
            int index = parsedAddress.getAddress();
            return holdingRegisters[index];
        } else if (parsedAddress.getFunctionCode() == 4) { // 输入寄存器
            int index = parsedAddress.getAddress();
            return inputRegisters[index];
        }
        return 0;
    }
    @Override
    public void handleWriteRegister(String address, int value) {
        ProtocolAddress parsedAddress = new ModbusAddressParser().parse(address);
        if (parsedAddress.getFunctionCode() == 3) { // 保持寄存器
            int index = parsedAddress.getAddress();
            holdingRegisters[index] = value;
            System.out.println("写入寄存器 " + address + " 值: " + value);
        }
    }
    @Override
    public void handleWriteRegisters(String address, int[] values) {
        ProtocolAddress parsedAddress = new ModbusAddressParser().parse(address);
        if (parsedAddress.getFunctionCode() == 16) { // 写多个寄存器
            int index = parsedAddress.getAddress();
            System.arraycopy(values, 0, holdingRegisters, index, values.length);
            System.out.println("写入寄存器 " + address + " 数量: " + values.length);
        }
    }
    @Override
    public int[] handleReadRegisters(String address, int quantity) {
        ProtocolAddress parsedAddress = new ModbusAddressParser().parse(address);
        if (parsedAddress.getFunctionCode() == 3) { // 保持寄存器
            int startIndex = parsedAddress.getAddress();
            int[] result = new int[quantity];
            System.arraycopy(holdingRegisters, startIndex, result, 0, Math.min(quantity, holdingRegisters.length - startIndex));
            return result;
        } else if (parsedAddress.getFunctionCode() == 4) { // 输入寄存器
            int startIndex = parsedAddress.getAddress();
            int[] result = new int[quantity];
            System.arraycopy(inputRegisters, startIndex, result, 0, Math.min(quantity, inputRegisters.length - startIndex));
            return result;
        } else if (address.startsWith("S7.")) {
            return handleS7ReadRegisters(address, quantity);
        }
        return new int[0];
    }
    private int[] handleS7ReadRegisters(String address, int quantity) {
        // 解析S7地址格式并读取多个寄存器
        String[] parts = address.split("\\.");
        if (parts.length >= 3 && parts[0].equals("S7") && parts[1].startsWith("DB")) {
            try {
                int dbNumber = Integer.parseInt(parts[1].substring(2));
                String type = parts[2].substring(0, 3);
                int startIndex = Integer.parseInt(parts[2].substring(3));
                int baseIndex = dbNumber * 1000 + startIndex;
                int[] result = new int[quantity];
                if (type.equals("DBW")) {
                    // 字(16位)数组
                    for (int i = 0; i < quantity && baseIndex + i < holdingRegisters.length; i++) {
                        result[i] = holdingRegisters[baseIndex + i];
                    }
                } else if (type.equals("DBD")) {
                    // 双字(32位)数组,每个双字占两个寄存器位置
                    for (int i = 0; i < quantity && baseIndex + i * 2 + 1 < holdingRegisters.length; i++) {
                        result[i] = (holdingRegisters[baseIndex + i * 2] << 16) |
                                (holdingRegisters[baseIndex + i * 2 + 1] & 0xFFFF);
                    }
                }
                return result;
            } catch (NumberFormatException e) {
                System.err.println("地址解析错误: " + address);
            }
        }
        return new int[0];
    }
    @Override
    public float handleReadFloat(String address) {
        int[] registers = handleReadRegisters(address, 2);
        if (registers.length >= 2) {
            int intBits = (registers[0] << 16) | registers[1];
            return Float.intBitsToFloat(intBits);
        }
        return 0.0f;
    }
    @Override
    public void handleWriteFloat(String address, float value) {
        int intBits = Float.floatToIntBits(value);
        int highWord = (intBits >> 16) & 0xFFFF;
        int lowWord = intBits & 0xFFFF;
        handleWriteRegisters(address, new int[]{highWord, lowWord});
    }
    @Override
    public String handleReadString(String address, int length) {
        int[] registers = handleReadRegisters(address, (length + 1) / 2);
        byte[] bytes = new byte[registers.length * 2];
        for (int i = 0; i < registers.length; i++) {
            bytes[i * 2] = (byte) ((registers[i] >> 8) & 0xFF);
            bytes[i * 2 + 1] = (byte) (registers[i] & 0xFF);
        }
        return new String(bytes, 0, length);
    }
    @Override
    public void handleWriteString(String address, String value) {
        byte[] bytes = value.getBytes();
        int[] registers = new int[(bytes.length + 1) / 2];
        for (int i = 0; i < bytes.length; i++) {
            int regIndex = i / 2;
            int byteIndex = i % 2;
            if (byteIndex == 0) {
                registers[regIndex] = (bytes[i] & 0xFF) << 8;
            } else {
                registers[regIndex] |= (bytes[i] & 0xFF);
            }
        }
        handleWriteRegisters(address, registers);
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/IndustrialInterface/AddressParser.java
New file
@@ -0,0 +1,10 @@
package com.mes.connect.IndustrialInterface;
import com.mes.connect.protocol.ProtocolAddress;
/**
 * 地址解析器接口
 */
public interface AddressParser {
    ProtocolAddress parse(String address);
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/IndustrialInterface/Api.java
New file
@@ -0,0 +1,232 @@
package com.mes.connect.IndustrialInterface;
import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class Api implements ApiService {
    private final RestTemplate restTemplate;
    private final JdbcTemplate jdbcTemplate;
    @Autowired
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    // 使用构造函数注入
    @Autowired
    public Api(RestTemplate restTemplate, JdbcTemplate jdbcTemplate) {
        this.restTemplate = restTemplate;
        this.jdbcTemplate = jdbcTemplate;
    }
    /**
     * 发送HTTP请求,支持GET和POST方法
     *
     * @param url 请求URL
     * @param data 请求参数或请求体
     * @return 响应内容按行分割的数组
     */
    @DS("mes_machine")
    @Override
    public List<String> httpApi(String url,Map<String, Object> data) {
        try {
            // 构建URL
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
            // 处理响应
            String responseBody;
            String method=data.get("method").toString();
            data.remove("method");
            if ("GET".equals(method)) {
                // GET请求:将参数添加到URL查询参数中
                if (data != null) {
                    data.forEach(builder::queryParam);
                }
                // 发送GET请求
                ResponseEntity<String> response = restTemplate.exchange(
                        builder.toUriString(),
                        HttpMethod.GET,
                        null,
                        String.class
                );
                responseBody = response.getBody();
            } else if ("POST".equals(method)) {
                // POST请求:将参数作为请求体
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                HttpEntity<?> entity = new HttpEntity<>(data, headers);
                // 发送POST请求
                ResponseEntity<String> response = restTemplate.exchange(
                        builder.toUriString(),
                        HttpMethod.POST,
                        entity,
                        String.class
                );
                responseBody = response.getBody();
            } else {
                throw new IllegalArgumentException("不支持的HTTP方法: " + method);
            }
            // 直接提取data数组
            List<String> dataList = JSON.parseObject(responseBody)
                    .getJSONArray("data")
                    .toJavaList(String.class);
            return dataList;
            //return responseBody != null ? responseBody.split("\n") : new String[0];
        } catch (Exception e) {
            // 异常处理
            e.printStackTrace();
            return null;
        }
    }
    @DS("mes_machine")
    @Override
    public List<String> viewApi(String viewName, Map<String, Object> params) {
        // 验证视图名是否合法,防止SQL注入
        if (!isValidViewName(viewName)) {
            throw new IllegalArgumentException("无效的视图名称");
        }
        // 使用预编译语句构建查询
        StringBuilder sql = new StringBuilder("SELECT * FROM " + viewName);
        MapSqlParameterSource paramSource = new MapSqlParameterSource();
        if (params != null && !params.isEmpty()) {
            sql.append(" WHERE ");
            boolean first = true;
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                if (!first) {
                    sql.append(" AND ");
                }
                sql.append(entry.getKey()).append(" = :").append(entry.getKey());
                paramSource.addValue(entry.getKey(), entry.getValue());
                first = false;
            }
        }
        // 使用Map参数执行查询并转换结果
        List<Map<String, Object>> resultList = namedParameterJdbcTemplate.queryForList(
                sql.toString(),
                paramSource.getValues()
        );
        return convertResultToList(resultList);
    }
    @DS("jiumumes")
    @Override
    public List<String> procedureAPI(String procedureName, Map<String, Object> params,Map<String, Object> outParams) {
        try {
            if (!isValidProcedureName(procedureName)) {
                throw new IllegalArgumentException("无效的存储过程名称");
            }
            SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate)
                    .withProcedureName(procedureName)
                    .withoutProcedureColumnMetaDataAccess();
            if (params != null) {
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    // 确定参数类型
                    int sqlType = getSqlType(entry.getValue());
                    // 检查是否为输出参数
                    if (outParams != null && outParams.containsKey(entry.getKey())) {
                        Object outParamInfo = outParams.get(entry.getKey());
                        int outSqlType;
                        // 从输出参数信息中获取SQL类型
                        if (outParamInfo instanceof Integer) {
                            outSqlType = (Integer) outParamInfo;
                        } else if (outParamInfo instanceof Map) {
                            // 假设Map中包含"sqlType"键
                            Map<String, Object> outParamMap = (Map<String, Object>) outParamInfo;
                            outSqlType = (Integer) outParamMap.getOrDefault("sqlType", sqlType);
                        } else {
                            // 默认使用输入参数的SQL类型
                            outSqlType = sqlType;
                        }
                        // 使用指定的SQL类型作为输出参数
                        jdbcCall.declareParameters(
                                new SqlOutParameter(entry.getKey(), outSqlType)
                        );
                    } else {
                        // 作为输入参数
                        jdbcCall.declareParameters(
                                new SqlParameter(entry.getKey(), sqlType)
                        );
                    }
                }
            }
            // 执行存储过程并获取结果
            Map<String, Object> result = jdbcCall.execute(params);
            // 处理输出参数
            if (outParams != null) {
                for (String paramName : outParams.keySet()) {
                    if (result.containsKey(paramName)) {
                        // 将输出参数的值放回原参数Map中
                        params.put(paramName, result.get(paramName));
                    }
                }
            }
            // 返回结果信息
            return null;
        } catch (Exception e) {
            return null;
        }
    }
    // 将查询结果转换为字符串数组
    private List<String> convertResultToList(List<Map<String, Object>> resultList) {
        List<String> resultStrings = new ArrayList<>();
        for (Map<String, Object> row : resultList) {
            for (String key : row.keySet()) {
                resultStrings.add(row.get(key).toString());
            }
            return resultStrings;
        }
        //return resultStrings.toArray(new String[0]);
        return resultStrings;
    }
    // 类型映射方法
    private int getSqlType(Object value) {
        if (value instanceof String) return Types.VARCHAR;
        if (value instanceof Integer) return Types.INTEGER;
        if (value instanceof Double) return Types.DOUBLE;
        if (value instanceof java.util.Date) return Types.TIMESTAMP;
        if (value instanceof Boolean) return Types.BOOLEAN;
        return Types.VARCHAR;
    }
    // 验证视图名称(防止SQL注入)
    private boolean isValidViewName(String viewName) {
        // 简单验证:只允许字母、数字和下划线,且长度不超过50
        return viewName.matches("^[a-zA-Z0-9_]{1,50}$");
    }
    // 验证存储过程名称
    private boolean isValidProcedureName(String procedureName) {
        return procedureName.matches("^[a-zA-Z0-9_]{1,50}$");
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/IndustrialInterface/ApiService.java
New file
@@ -0,0 +1,44 @@
package com.mes.connect.IndustrialInterface;
import com.baomidou.dynamic.datasource.annotation.DS;
import java.util.List;
import java.util.Map;
/**
 * <p>
 * 账户表 服务类
 * </p>
 *
 * @author wu
 * @since 2024-08-28
 */
public interface ApiService {
    /**
     * 调用HTTP接口
     * @param url HTTP请求地址
     * @param data 请求参数
     * @return 响应结果
     */
    List<String> httpApi(String url, Map<String, Object> data);
    /**
     * 调用视图API
     * @param viewName 视图名称
     * @param data 请求参数
     * @return 视图渲染结果
     */
    List<String> viewApi(String viewName, Map<String, Object> data);
    /**
     * 调用存储过程
     * @param procedureName 存储过程名称
     * @param params 输入参数
     * @param outParams 输出参数
     * @return 存储过程执行结果
     */
    List<String> procedureAPI(String procedureName, Map<String, Object> params,Map<String, Object> outParams);
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/IndustrialInterface/IndustrialClient.java
New file
@@ -0,0 +1,27 @@
package com.mes.connect.IndustrialInterface;
import java.io.IOException;
/**
 * 工业通信统一接口 - 客户端模式
 */
public interface IndustrialClient extends AutoCloseable {
    void connect() throws IOException;
    void disconnect();
    boolean isConnected();
    // 数据读写方法
    boolean readBit(String address) throws IOException;
    void writeBit(String address, boolean value) throws IOException;
    int readRegister(String address) throws IOException;
    void writeRegister(String address, int value) throws IOException;
    int[] readRegisters(String address, int quantity) throws IOException;
    void writeRegisters(String address, int[] values) throws IOException;
    float readFloat(String address) throws IOException;
    void writeFloat(String address, float value) throws IOException;
    String readString(String address, int length) throws IOException;
    void writeString(String address, String value) throws IOException;
    @Override
    void close() throws IOException;
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/IndustrialInterface/IndustrialDataHandler.java
New file
@@ -0,0 +1,17 @@
package com.mes.connect.IndustrialInterface;
/**
 * 工业通信数据处理器接口
 */
public interface IndustrialDataHandler {
    boolean handleReadBit(String address);
    void handleWriteBit(String address, boolean value);
    int handleReadRegister(String address);
    void handleWriteRegister(String address, int value);
    int[] handleReadRegisters(String address, int quantity);
    void handleWriteRegisters(String address, int[] values);
    float handleReadFloat(String address);
    void handleWriteFloat(String address, float value);
    String handleReadString(String address, int length);
    void handleWriteString(String address, String value);
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/IndustrialInterface/IndustrialServer.java
New file
@@ -0,0 +1,16 @@
package com.mes.connect.IndustrialInterface;
import java.io.IOException;
/**
 * 工业通信统一接口 - 服务器模式
 */
public interface IndustrialServer extends AutoCloseable {
    void start() throws IOException;
    void stop();
    boolean isRunning();
    void setDataHandler(IndustrialDataHandler handler);
    @Override
    void close() throws IOException;
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/Thread/MachineThread.java
New file
@@ -0,0 +1,394 @@
package com.mes.connect.Thread;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mes.common.JsonConversion;
import com.mes.common.ReadFile;
import com.mes.connect.IndustrialInterface.Api;
import com.mes.connect.IndustrialInterface.IndustrialClient;
import com.mes.connect.entity.*;
import com.mes.connect.modbus.ModbusIpClient;
import com.mes.connect.modbus.ModbusTcpClient;
import com.mes.connect.protocol.ProtocolType;
import com.mes.connect.s7.S7Client;
import com.mes.connect.s7.S7ClientOld;
import com.mes.model.entity.Machine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@Slf4j
public class MachineThread extends Thread {
    //当前设备的参数
    private Machine machine;
    private ProtocolType protocolType;
    private IndustrialClient client;
    private PlcParameters plcParameters;
    private LogicConfig logicConfig;
    private Api api;
    // 存储所有逻辑线程
    private Map<String, Thread> logicThreads = new ConcurrentHashMap<>();
    // 控制逻辑线程运行的标志
    private Map<String, Boolean> logicRunningFlags = new ConcurrentHashMap<>();
    // 主线程运行标志
    private boolean running = true;
    // 主线程执行间隔
    private int mainThreadInterval = 1000;
    public MachineThread(Machine machine, Api api) throws IOException {
        this.machine = machine;
        this.api = api;
        this.logicConfig = JsonConversion.jsonToObjectByJackson(ReadFile.readJson(machine.getLogicFile()).toString(), LogicConfig.class);
        this.plcParameters = JsonConversion.jsonToObjectByJackson(ReadFile.readJson(machine.getMachineFile()).toString(), PlcParameters.class);
        switch (machine.getProtocolType().getName()) {
            case "ModbusTcp":
                client = new ModbusTcpClient(machine.getIp(), machine.getPort(), 1);
                break;
            case "ModbusIp":
                client = new ModbusIpClient(machine.getIp(), machine.getPort());
                break;
            case "S7":
                client = new S7Client(machine.getIp(), machine.getPort(), 0, 1);
                break;
            case "S7Old":
                client = new S7ClientOld(machine.getPlcType().getName(),machine.getIp(), machine.getPort(), 0, 1);;
                break;
            default:
                log.error("无效的协议类型: {}", protocolType);
                throw new IllegalArgumentException("无效的协议类型: " + protocolType);
        }
        if (client != null) {
            client.connect();
            boolean connected = client.isConnected();
            if (!connected) {
                log.error("连接PLC失败: {}", machine.getIp());
            }
        }
    }
    @Override
    public void run() {
        log.info("MachineThread启动,设备IP: {}", machine.getIp());
        if (client == null || !client.isConnected()) {
            log.error("PLC客户端未连接,线程退出");
            return;
        }
        plcParameters.Initialization();
        try {
            // 初始化读取PLC参数
            readPlcParameter();
        } catch (Exception e) {
            log.error("初始化读取PLC参数失败: {}", e.getMessage(), e);
            return;
        }
        // 为每个逻辑项创建并启动子线程
        //startLogicThread(logicConfig.getLogics().get(0));
        for (LogicItem logicItem : logicConfig.getLogics()) {
            startLogicThread(logicItem);
            //startLogicThread(logicConfig.getLogics().get(0));
        }
        // 主线程持续运行,定期读取PLC参数并监控连接状态
        while (running) {
            try {
                // 读取PLC参数,为逻辑处理提供最新数据
                readPlcParameter();
                // 检查PLC连接状态
                if (!client.isConnected()) {
                    log.warn("PLC连接断开,尝试重新连接");
                    tryReconnect();
                }
                // 检查逻辑线程状态,重启已终止的线程
                checkLogicThreadsStatus();
                // 等待下一个执行周期
                Thread.sleep(mainThreadInterval);
            } catch (InterruptedException e) {
                log.info("主线程被中断,准备退出");
                running = false;
                Thread.currentThread().interrupt();
            } catch (Exception e) {
                log.error("执行过程中发生错误: {}", e.getMessage(), e);
                // 尝试重新连接
                tryReconnect();
                // 等待一段时间再继续执行
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException ie) {
                    log.info("主线程被中断,准备退出");
                    running = false;
                    Thread.currentThread().interrupt();
                }
            }
        }
        // 线程退出前关闭所有资源
        shutdown();
        log.info("MachineThread已退出,设备IP: {}", machine.getIp());
    }
    // 为指定逻辑项创建并启动子线程
    private void startLogicThread(LogicItem logicItem) {
        String logicId = logicItem.getName(); // 假设每个LogicItem有唯一ID
        if (logicThreads.containsKey(logicId) && logicThreads.get(logicId).isAlive()) {
            log.warn("逻辑项线程已在运行: {}", logicId);
            return;
        }
        // 设置运行标志
        logicRunningFlags.put(logicId, true);
        // 创建并启动线程
        Thread thread = new Thread(() -> {
            log.info("逻辑项线程启动: {}", logicId);
            // 逻辑项子线程持续运行的循环
            while (logicRunningFlags.getOrDefault(logicId, false)) {
                try {
                    // 执行实际业务逻辑
                    basicsLogic(logicItem);
                    // 根据逻辑项的执行频率设置等待时间,默认1000ms
                    int logicInterval = 1000;
                    Thread.sleep(logicInterval);
                } catch (InterruptedException e) {
                    log.info("逻辑项线程被中断,准备退出: {}", logicId);
                    logicRunningFlags.put(logicId, false);
                    Thread.currentThread().interrupt();
                } catch (Exception e) {
                    log.error("执行逻辑项失败: {}, 错误: {}", logicId, e.getMessage(), e);
                    // 等待一段时间再继续执行
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException ie) {
                        log.info("逻辑项线程被中断,准备退出: {}", logicId);
                        logicRunningFlags.put(logicId, false);
                        Thread.currentThread().interrupt();
                    }
                }
            }
            log.info("逻辑项线程已退出: {}", logicId);
        });
        // 设置线程名称
        thread.setName("Logic-" + logicId);
        // 存储线程引用
        logicThreads.put(logicId, thread);
        // 启动线程
        thread.start();
        log.info("已启动逻辑项线程: {}", logicId);
    }
    // 检查逻辑线程状态,重启已终止的线程
    private void checkLogicThreadsStatus() {
        for (LogicItem logicItem : logicConfig.getLogics()) {
            String logicId = logicItem.getName();
            Thread thread = logicThreads.get(logicId);
            // 如果线程不存在或已终止且运行标志为true,则重启线程
            if ((thread == null || !thread.isAlive()) &&
                    logicRunningFlags.getOrDefault(logicId, false)) {
                log.warn("逻辑项线程已终止,准备重启: {}", logicId);
                startLogicThread(logicItem);
            }
        }
    }
    // 尝试重新连接PLC
    private void tryReconnect() {
        if (client != null) {
            try {
                log.info("尝试重新连接PLC: {}", machine.getIp());
                client.disconnect();
                Thread.sleep(2000);
                boolean reconnected = client.isConnected();
                if (reconnected) {
                    log.info("PLC重新连接成功: {}", machine.getIp());
                } else {
                    log.error("PLC重新连接失败: {}", machine.getIp());
                }
            } catch (Exception e) {
                log.error("重新连接PLC异常: {}", e.getMessage(), e);
            }
        }
    }
    // 关闭线程前的清理工作
    public void shutdown() {
        running = false;
        // 停止所有逻辑线程
        for (String logicId : logicRunningFlags.keySet()) {
            logicRunningFlags.put(logicId, false);
            Thread thread = logicThreads.get(logicId);
            if (thread != null && thread.isAlive()) {
                thread.interrupt();
            }
        }
        // 等待所有逻辑线程结束
        for (String logicId : logicThreads.keySet()) {
            Thread thread = logicThreads.get(logicId);
            if (thread != null && thread.isAlive()) {
                try {
                    thread.join(1000); // 等待最多1秒
                } catch (InterruptedException e) {
                    log.error("等待逻辑线程结束时被中断: {}", e.getMessage());
                    Thread.currentThread().interrupt();
                }
            }
        }
        // 清空线程映射
        logicThreads.clear();
        logicRunningFlags.clear();
        // 关闭PLC连接
        if (client != null) {
            try {
                client.disconnect();
                log.info("PLC连接已关闭: {}", machine.getIp());
            } catch (Exception e) {
                log.error("关闭PLC连接异常: {}", e.getMessage(), e);
            }
        }
    }
    //示例   解读配置 根据接口返内容给PLC
    public void basicsLogic(LogicItem logicItem) throws JSONException, IOException {
        //1.读取PLC当前参数
        try {
            //遍历逻辑
            boolean isEqual=true;
            for (Logic logic:logicItem.getLogic()){
                String plcValue=plcParameters.getMap().get(logic.getCodeId()).getReadValue().toString();
                if (!logic.getValue().contains(plcValue)){
                    isEqual=false;
                    logic.setEquals(false);
                    logicItem.setEquals(false);
                    break;
                }
            }
            if (isEqual){
                List<String> result=new ArrayList<>();
                //3.查询此逻辑下需要返回给PLC的数据 result可接收  HTTP接口,视图,存储过程 等  如下
                try{
                    String connectType=logicItem.getConnectType();
                    String connectAddress=logicItem.getConnectAddress();
                    Map map=new HashMap();
                    switch (connectType) {
                        case "Http":
                            map.put("method","POST");
                            map.put("plcParameter",plcParameters);
                            result= api.httpApi(connectAddress,map);
                            log.info("接口返回内容:{}",result);
                            break;
                        case "View": // 视图/表
                            result= api.viewApi(connectAddress,map);
                            break;
                        case "Procedure": // 存储过程
                            //result= api.procedureAPI(connectAddress,plcParameter);
                            break;
                        default:
                            log.warn("不支持的连接类型: {}", connectType);
                            return; // 不支持的方式
                    }
                }catch (Exception e){
                    log.error("调用接口失败: {}", e.getMessage(), e);
                }
                //4.返回PLC内容
                if (result != null&&!result.isEmpty()) {
                    basicsResult(result,logicItem.getReturnValue());
                }
            }
        }  catch (Exception e) {
            log.error("执行basicsLogic失败: {}", e.getMessage(), e);
        }
    }
    //传入需要发送的数据
    public boolean basicsResult(List<String> sendData, List<ReturnValue> returnValue) throws JSONException, IOException {
        for (ReturnValue itemReturnValue:returnValue){
            //需要返回PLC的值
            String values ="";
            if (itemReturnValue.isFixed()){
                //固定值
                values= itemReturnValue.getValue();
            }else{
                //按传递的参数值
                values= sendData.get(Integer.valueOf(itemReturnValue.getValue())-1);
            }
            if (values!=null && !values.equals("")){
                //还需增添  不同类型调用不同方法
                switch (itemReturnValue.getPlcDataType()) {
                    case "int":
                        client.writeRegister(itemReturnValue.getAddress(),(int)Double.parseDouble(values));
                        break;
                    case "string":
                        client.writeString(itemReturnValue.getAddress(),values);
                        break;
                    case "float":
                        client.writeFloat(itemReturnValue.getAddress(),Float.valueOf(values));
                        break;
                    default:
                        log.error("不支持的数据类型: {}", itemReturnValue.getPlcDataType());
                        return false;
                }
            }
        }
        return true;
    }
    // 按照json文件读取plc内容
    private PlcParameters readPlcParameter() throws IOException, JSONException {
        List<Parameters> parametersList=plcParameters.getParameters();
        for (int i=0;i<parametersList.size();i++){
            //根据类型读取
            switch (parametersList.get(i).getPlcDataType()) {
                case "Word":
                    int value=client.readRegister(parametersList.get(i).getAddress());
                    parametersList.get(i).setReadValue(value);
                    break;
                case "string":
                    //多寄存器    传递数量
                    String strValue = client.readString(parametersList.get(i).getAddress(), 2);
                    parametersList.get(i).setReadValue(strValue);
                    break;
                case "bit":
                    //读线圈
                    boolean bitValue = client.readBit(parametersList.get(i).getAddress());
                    parametersList.get(i).setReadValue(bitValue);
                    break;
                default:
                    log.error("不支持的数据类型: {}", parametersList.get(i).getPlcDataType());
                    return null;
            }
        }
        plcParameters.setParameters(parametersList);
        return plcParameters;
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/addressParser/ModbusAddressParser.java
New file
@@ -0,0 +1,54 @@
package com.mes.connect.addressParser;
import com.mes.connect.IndustrialInterface.AddressParser;
import com.mes.connect.protocol.ProtocolAddress;
import com.mes.connect.protocol.ProtocolType;
/**
 * Modbus地址解析器
 */
public class ModbusAddressParser implements AddressParser {
    @Override
    public ProtocolAddress parse(String address) {
        // 格式示例: "MB.4x0001" 或 "MB.0x100.2"
        if (!address.startsWith("MB.")) {
            throw new IllegalArgumentException("Invalid Modbus address format: " + address);
        }
        String[] parts = address.substring(3).split("\\.");
        if (parts.length < 1) {
            throw new IllegalArgumentException("Invalid Modbus address format: " + address);
        }
        // 解析区域
        String areaStr = parts[0];
        int functionCode;
        if (areaStr.startsWith("0x")) {
            functionCode = 1; // 1读线圈 5写单个线圈
        } else if (areaStr.startsWith("1x")) {
            functionCode = 2; // 读离散输入
        } else if (areaStr.startsWith("3x")) {
            functionCode = 4; // 读输入寄存器
        } else if (areaStr.startsWith("4x")) {
            functionCode = 3; // 读保持寄存器
        } else {
            throw new IllegalArgumentException("Invalid Modbus area: " + areaStr);
        }
        // 解析地址
        int addressValue = Integer.parseInt(areaStr.substring(2));
        if (functionCode == 3 || functionCode == 4) {
            addressValue--; // Modbus保持寄存器和输入寄存器地址从0开始
        }
        // 解析位地址(如果有)
        int bit = 0;
        if (parts.length > 1) {
            bit = Integer.parseInt(parts[1]);
        }
        return new ProtocolAddress(ProtocolType.MODBUS_TCP, functionCode, 0, addressValue, bit);
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/addressParser/ModbusIpAddressParser.java
New file
@@ -0,0 +1,20 @@
package com.mes.connect.addressParser;
import com.mes.connect.IndustrialInterface.AddressParser;
import com.mes.connect.protocol.ProtocolAddress;
/**
 * Modbus IP地址解析器
 */
public class ModbusIpAddressParser implements AddressParser {
    @Override
    public ProtocolAddress parse(String address) {
        // 格式示例: "MBIP.4x0001" 或 "MBIP.0x100.2"
        if (!address.startsWith("MBIP.")) {
            throw new IllegalArgumentException("Invalid Modbus IP address format: " + address);
        }
        // 复用Modbus地址解析逻辑
        return new ModbusAddressParser().parse("MB." + address.substring(5));
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/addressParser/ModbusRtuAddressParser.java
New file
@@ -0,0 +1,15 @@
package com.mes.connect.addressParser;
import com.mes.connect.IndustrialInterface.AddressParser;
import com.mes.connect.protocol.ProtocolAddress;
/**
 * Modbus RTU地址解析器
 */
class ModbusRtuAddressParser implements AddressParser {
    @Override
    public ProtocolAddress parse(String address) {
        // 复用Modbus地址解析逻辑
        return new ModbusAddressParser().parse(address);
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/addressParser/S7AddressParser.java
New file
@@ -0,0 +1,82 @@
package com.mes.connect.addressParser;
import com.mes.connect.IndustrialInterface.AddressParser;
import com.mes.connect.protocol.ProtocolAddress;
import com.mes.connect.protocol.ProtocolType;
/**
 * S7地址解析器
 */
public class S7AddressParser implements AddressParser {
    @Override
    public ProtocolAddress parse(String address) {
        // 格式示例: "S7.DB1.DBX10.2" 或 "S7.M100"
        //位地址:S7.DB1.DBX0.0 (DB1 块中的字节 0 的位 0)
        //字节地址:S7.DB1.DBB0 (DB1 块中的字节 0)
        //字地址:S7.DB1.DBW0 (DB1 块中的字 0)
        //双字地址:S7.DB1.DBD0 (DB1 块中的双字 0)
        if (!address.startsWith("S7.")) {
            throw new IllegalArgumentException("Invalid S7 address format: " + address);
        }
        String[] parts = address.substring(3).split("\\.");
        if (parts.length < 2) {
            throw new IllegalArgumentException("Invalid S7 address format: " + address);
        }
        // 解析DB号
        int dbNumber = 0;
        int area = 0x84; // 默认DB区域
        if (parts[0].startsWith("DB")) {
            dbNumber = Integer.parseInt(parts[0].substring(2));
        } else if (parts[0].equals("I")) {
            area = 0x81; // 输入区域
        } else if (parts[0].equals("Q")) {
            area = 0x82; // 输出区域
        } else if (parts[0].equals("M")) {
            area = 0x83; // 内存区域
        } else {
            throw new IllegalArgumentException("Invalid S7 area: " + parts[0]);
        }
        // 解析地址类型和地址值
        String addressPart = parts[1];
        int addressValue = 0;
        int bit = 0;
        if (area == 0x84) { // DB区域
            if (addressPart.startsWith("DBX")) {
                // 位地址
                String[] bitParts = addressPart.substring(3).split("\\.");
                addressValue = Integer.parseInt(bitParts[0]);
                if (bitParts.length > 1) {
                    bit = Integer.parseInt(bitParts[1]);
                }
            } else if (addressPart.startsWith("DBW")) {
                // 字地址
                addressValue = Integer.parseInt(addressPart.substring(3));
            } else if (addressPart.startsWith("DBD")) {
                // 双字地址
                addressValue = Integer.parseInt(addressPart.substring(3));
            } else {
                throw new IllegalArgumentException("Invalid S7 DB address type: " + addressPart);
            }
        } else { // I/Q/M区域
            if (addressPart.startsWith("X")) {
                // 位地址
                String[] bitParts = addressPart.substring(1).split("\\.");
                addressValue = Integer.parseInt(bitParts[0]);
                if (bitParts.length > 1) {
                    bit = Integer.parseInt(bitParts[1]);
                }
            } else {
                // 字地址
                addressValue = Integer.parseInt(addressPart);
            }
        }
        return new ProtocolAddress(ProtocolType.S7, area, dbNumber, addressValue, bit);
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/addressParser/S7OldAddressParser.java
New file
@@ -0,0 +1,82 @@
package com.mes.connect.addressParser;
import com.mes.connect.IndustrialInterface.AddressParser;
import com.mes.connect.protocol.ProtocolAddress;
import com.mes.connect.protocol.ProtocolType;
/**
 * S7地址解析器
 */
public class S7OldAddressParser implements AddressParser {
    @Override
    public ProtocolAddress parse(String address) {
        // 格式示例: "S7.DB1.DBX10.2" 或 "S7.M100"
        //位地址:S7.DB1.DBX0.0 (DB1 块中的字节 0 的位 0)
        //字节地址:S7.DB1.DBB0 (DB1 块中的字节 0)
        //字地址:S7.DB1.DBW0 (DB1 块中的字 0)
        //双字地址:S7.DB1.DBD0 (DB1 块中的双字 0)
        if (!address.startsWith("S7.")) {
            throw new IllegalArgumentException("Invalid S7 address format: " + address);
        }
        String[] parts = address.substring(3).split("\\.");
        if (parts.length < 2) {
            throw new IllegalArgumentException("Invalid S7 address format: " + address);
        }
        // 解析DB号
        int dbNumber = 0;
        int area = 0x84; // 默认DB区域
        if (parts[0].startsWith("DB")) {
            dbNumber = Integer.parseInt(parts[0].substring(2));
        } else if (parts[0].equals("I")) {
            area = 0x81; // 输入区域
        } else if (parts[0].equals("Q")) {
            area = 0x82; // 输出区域
        } else if (parts[0].equals("M")) {
            area = 0x83; // 内存区域
        } else {
            throw new IllegalArgumentException("Invalid S7 area: " + parts[0]);
        }
        // 解析地址类型和地址值
        String addressPart = parts[1];
        int addressValue = 0;
        int bit = 0;
        if (area == 0x84) { // DB区域
            if (addressPart.startsWith("DBX")) {
                // 位地址
                String[] bitParts = addressPart.substring(3).split("\\.");
                addressValue = Integer.parseInt(bitParts[0]);
                if (bitParts.length > 1) {
                    bit = Integer.parseInt(bitParts[1]);
                }
            } else if (addressPart.startsWith("DBW")) {
                // 字地址
                addressValue = Integer.parseInt(addressPart.substring(3));
            } else if (addressPart.startsWith("DBD")) {
                // 双字地址
                addressValue = Integer.parseInt(addressPart.substring(3));
            } else {
                throw new IllegalArgumentException("Invalid S7 DB address type: " + addressPart);
            }
        } else { // I/Q/M区域
            if (addressPart.startsWith("X")) {
                // 位地址
                String[] bitParts = addressPart.substring(1).split("\\.");
                addressValue = Integer.parseInt(bitParts[0]);
                if (bitParts.length > 1) {
                    bit = Integer.parseInt(bitParts[1]);
                }
            } else {
                // 字地址
                addressValue = Integer.parseInt(addressPart);
            }
        }
        return new ProtocolAddress(ProtocolType.S7, area, dbNumber, addressValue, bit);
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/entity/Logic.java
New file
@@ -0,0 +1,20 @@
package com.mes.connect.entity;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Data
public class Logic {
    private String codeId;
    private String address;
    private List<String> value;
    private String plcDataType;
    private int length;
    @Getter
    @Setter
    private boolean equals;
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/entity/LogicConfig.java
New file
@@ -0,0 +1,19 @@
package com.mes.connect.entity;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mes.common.JsonConversion;
import com.mes.common.ReadFile;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.List;
@Slf4j
@Data
public class LogicConfig {
    private List<LogicItem> logics;
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/entity/LogicItem.java
New file
@@ -0,0 +1,22 @@
package com.mes.connect.entity;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Data
public class LogicItem {
    private String name;
    private String sequence;
    private String connectType;
    private String method;
    private String connectAddress;
    private List<Logic> logic;
    private List<ReturnValue> returnValue;
    @Getter
    @Setter
    private boolean equals;
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/entity/Parameters.java
New file
@@ -0,0 +1,23 @@
package com.mes.connect.entity;
import lombok.Data;
import java.util.stream.Collectors;
@Data
public class Parameters {
    private String serialNumber;
    private String content;
    private String codeId;
    private String plcDataType;
    private int fontLocation;
    private int length;
    private String ratio;
    private String scale;
    private String address;
    private byte[] readByte;
    private Object readValue;
    private String remarks;
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/entity/PlcParameters.java
New file
@@ -0,0 +1,20 @@
package com.mes.connect.entity;
import com.alibaba.fastjson.JSONException;
import lombok.Data;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Data
public class PlcParameters {
    private List<Parameters> parameters;
    private Map<String, Parameters> map;
    public void Initialization() {
        this.map=parameters.stream().collect(Collectors.toMap(Parameters::getCodeId, item -> item));
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/entity/ReturnValue.java
New file
@@ -0,0 +1,13 @@
package com.mes.connect.entity;
import lombok.Data;
@Data
public class ReturnValue {
    private String codeId;
    private String address;
    private boolean fixed;
    private String value;
    private String plcDataType;
    private int length;
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/modbus/ModbusIpClient.java
New file
@@ -0,0 +1,461 @@
package com.mes.connect.modbus;
import com.mes.connect.IndustrialInterface.AddressParser;
import com.mes.connect.IndustrialInterface.IndustrialClient;
import com.mes.connect.addressParser.ModbusIpAddressParser;
import com.mes.connect.protocol.ProtocolAddress;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.logging.Logger;
/**
 * Modbus IP客户端实现(基于UDP)
 */
public class ModbusIpClient implements IndustrialClient {
    private static final Logger logger = Logger.getLogger(ModbusIpClient.class.getName());
    private DatagramSocket socket;
    private final String host;
    private final int port;
    private boolean connected;
    private int transactionId = 0;
    private final AddressParser addressParser = new ModbusIpAddressParser();
    public ModbusIpClient(String host, int port) {
        this.host = host;
        this.port = port;
    }
    @Override
    public synchronized void connect() throws IOException {
        if (!connected) {
            socket = new DatagramSocket();
            socket.setSoTimeout(5000); // 5秒超时
            connected = true;
            logger.info("Connected to Modbus IP server: " + host + ":" + port);
        }
    }
    @Override
    public synchronized void disconnect() {
        if (connected) {
            try {
                if (socket != null) {
                    socket.close();
                }
            } finally {
                socket = null;
                connected = false;
                logger.info("Disconnected from Modbus IP server");
            }
        }
    }
    @Override
    public boolean isConnected() {
        return connected && socket != null && !socket.isClosed();
    }
    @Override
    public boolean readBit(String address) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        String[] parts = address.split("\\.");
        String strAddress ="";
        if (parts.length >1) {
            strAddress = parts[0]+"."+parts[1];
        }
        int[] data = readRegisters(strAddress, 1);
        int byteValue = data[0];
        return (byteValue & (1 << parsedAddress.getBit())) != 0;
    }
    @Override
    public void writeBit(String address, boolean value) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        String[] parts = address.split("\\.");
        String strAddress ="";
        if (parts.length >1) {
            strAddress = parts[0]+"."+parts[1];
        }
        int[] currentData = readRegisters(strAddress, 1);
        int byteValue = currentData[0];
        if (value) {
            byteValue |= (1 << parsedAddress.getBit());
        } else {
            byteValue &= ~(1 << parsedAddress.getBit());
        }
        writeRegister(strAddress, byteValue);
    }
//    @Override
//    public boolean readBit(String address) throws IOException {
//        ProtocolAddress parsedAddress = addressParser.parse(address);
//        int functionCode = parsedAddress.getFunctionCode();
//        int startAddress = parsedAddress.getAddress();
//        int bit = parsedAddress.getBit();
//
//        if (functionCode != 1 && functionCode != 2) {
//            throw new IllegalArgumentException("Invalid function code for bit operation: " + functionCode);
//        }
//
//        byte[] request = buildReadRequest(functionCode, startAddress, 1);
//        byte[] response = sendRequest(request);
//
//        if (response[7] == functionCode) {
//            int byteCount = response[8] & 0xFF;
//            if (byteCount >= 1) {
//                byte data = response[9];
//                return (data & (1 << bit)) != 0;
//            }
//        } else if (response[7] == functionCode + 0x80) {
//            int exceptionCode = response[8] & 0xFF;
//            throw new IOException("Modbus exception: " + exceptionCode);
//        }
//
//        throw new IOException("Invalid Modbus response");
//    }
//
//    @Override
//    public void writeBit(String address, boolean value) throws IOException {
//        ProtocolAddress parsedAddress = addressParser.parse(address);
//        int functionCode = parsedAddress.getFunctionCode();
//        int startAddress = parsedAddress.getAddress();
//
//        if (functionCode != 5) {
//            throw new IllegalArgumentException("Invalid function code for write bit operation: " + functionCode);
//        }
//
//        int writeValue = value ? 0xFF00 : 0x0000;
//        byte[] request = buildWriteSingleCoilRequest(startAddress, writeValue);
//        byte[] response = sendRequest(request);
//
//        if (response[7] != functionCode) {
//            if (response[7] == functionCode + 0x80) {
//                int exceptionCode = response[8] & 0xFF;
//                throw new IOException("Modbus exception: " + exceptionCode);
//            }
//            throw new IOException("Invalid Modbus response");
//        }
//    }
    @Override
    public int readRegister(String address) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int functionCode = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        if (functionCode != 3 && functionCode != 4) {
            throw new IllegalArgumentException("Invalid function code for register operation: " + functionCode);
        }
        byte[] request = buildReadRequest(functionCode, startAddress, 1);
        byte[] response = sendRequest(request);
        if (response[7] == functionCode) {
            int byteCount = response[8] & 0xFF;
            if (byteCount >= 2) {
                return ((response[9] & 0xFF) << 8) | (response[10] & 0xFF);
            }
        } else if (response[7] == functionCode + 0x80) {
            int exceptionCode = response[8] & 0xFF;
            throw new IOException("Modbus exception: " + exceptionCode);
        }
        throw new IOException("Invalid Modbus response");
    }
    @Override
    public void writeRegister(String address, int value) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int functionCode = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        if (functionCode != 6) {
            throw new IllegalArgumentException("Invalid function code for write register operation: " + functionCode);
        }
        byte[] request = buildWriteSingleRegisterRequest(startAddress, value);
        byte[] response = sendRequest(request);
        if (response[7] != functionCode) {
            if (response[7] == functionCode + 0x80) {
                int exceptionCode = response[8] & 0xFF;
                throw new IOException("Modbus exception: " + exceptionCode);
            }
            throw new IOException("Invalid Modbus response");
        }
    }
    @Override
    public int[] readRegisters(String address, int quantity) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int functionCode = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        if (functionCode != 3 && functionCode != 4) {
            throw new IllegalArgumentException("Invalid function code for register operation: " + functionCode);
        }
        byte[] request = buildReadRequest(functionCode, startAddress, quantity);
        byte[] response = sendRequest(request);
        if (response[7] == functionCode) {
            int byteCount = response[8] & 0xFF;
            if (byteCount == quantity * 2) {
                int[] result = new int[quantity];
                for (int i = 0; i < quantity; i++) {
                    result[i] = ((response[9 + i*2] & 0xFF) << 8) | (response[10 + i*2] & 0xFF);
                }
                return result;
            }
        } else if (response[7] == functionCode + 0x80) {
            int exceptionCode = response[8] & 0xFF;
            throw new IOException("Modbus exception: " + exceptionCode);
        }
        throw new IOException("Invalid Modbus response");
    }
    @Override
    public void writeRegisters(String address, int[] values) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int functionCode = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        if (functionCode != 16) {
            throw new IllegalArgumentException("Invalid function code for write registers operation: " + functionCode);
        }
        byte[] request = buildWriteMultipleRegistersRequest(startAddress, values);
        byte[] response = sendRequest(request);
        if (response[7] != functionCode) {
            if (response[7] == functionCode + 0x80) {
                int exceptionCode = response[8] & 0xFF;
                throw new IOException("Modbus exception: " + exceptionCode);
            }
            throw new IOException("Invalid Modbus response");
        }
    }
    @Override
    public float readFloat(String address) throws IOException {
        int[] registers = readRegisters(address, 2);
        int intBits = (registers[0] << 16) | registers[1];
        return Float.intBitsToFloat(intBits);
    }
    @Override
    public void writeFloat(String address, float value) throws IOException {
        int intBits = Float.floatToIntBits(value);
        int highWord = (intBits >> 16) & 0xFFFF;
        int lowWord = intBits & 0xFFFF;
        writeRegisters(address, new int[]{highWord, lowWord});
    }
    @Override
    public String readString(String address, int length) throws IOException {
        int[] registers = readRegisters(address, (length + 1) / 2);
        byte[] bytes = new byte[registers.length * 2];
        for (int i = 0; i < registers.length; i++) {
            bytes[i * 2] = (byte) ((registers[i] >> 8) & 0xFF);
            bytes[i * 2 + 1] = (byte) (registers[i] & 0xFF);
        }
        return new String(bytes, 0, length);
    }
    @Override
    public void writeString(String address, String value) throws IOException {
        byte[] bytes = value.getBytes();
        int[] registers = new int[(bytes.length + 1) / 2];
        for (int i = 0; i < bytes.length; i++) {
            int regIndex = i / 2;
            int byteIndex = i % 2;
            if (byteIndex == 0) {
                registers[regIndex] = (bytes[i] & 0xFF) << 8;
            } else {
                registers[regIndex] |= (bytes[i] & 0xFF);
            }
        }
        writeRegisters(address, registers);
    }
    @Override
    public void close() throws IOException {
        disconnect();
    }
    private byte[] buildReadRequest(int functionCode, int startAddress, int quantity) {
        byte[] request = new byte[12];
        // 事务标识符
        request[0] = (byte) (transactionId >> 8);
        request[1] = (byte) transactionId;
        // 协议标识符 (0)
        request[2] = 0;
        request[3] = 0;
        // 长度 (6)
        request[4] = 0;
        request[5] = 6;
        // 单元标识符 (1)
        request[6] = 1;
        // 功能码
        request[7] = (byte) functionCode;
        // 起始地址
        request[8] = (byte) (startAddress >> 8);
        request[9] = (byte) startAddress;
        // 数量
        request[10] = (byte) (quantity >> 8);
        request[11] = (byte) quantity;
        transactionId = (transactionId + 1) % 65536;
        return request;
    }
    private byte[] buildWriteSingleCoilRequest(int address, int value) {
        byte[] request = new byte[12];
        // 事务标识符
        request[0] = (byte) (transactionId >> 8);
        request[1] = (byte) transactionId;
        // 协议标识符 (0)
        request[2] = 0;
        request[3] = 0;
        // 长度 (6)
        request[4] = 0;
        request[5] = 6;
        // 单元标识符 (1)
        request[6] = 1;
        // 功能码 (5)
        request[7] = 5;
        // 地址
        request[8] = (byte) (address >> 8);
        request[9] = (byte) address;
        // 值
        request[10] = (byte) (value >> 8);
        request[11] = (byte) value;
        transactionId = (transactionId + 1) % 65536;
        return request;
    }
    private byte[] buildWriteSingleRegisterRequest(int address, int value) {
        byte[] request = new byte[12];
        // 事务标识符
        request[0] = (byte) (transactionId >> 8);
        request[1] = (byte) transactionId;
        // 协议标识符 (0)
        request[2] = 0;
        request[3] = 0;
        // 长度 (6)
        request[4] = 0;
        request[5] = 6;
        // 单元标识符 (1)
        request[6] = 1;
        // 功能码 (6)
        request[7] = 6;
        // 地址
        request[8] = (byte) (address >> 8);
        request[9] = (byte) address;
        // 值
        request[10] = (byte) (value >> 8);
        request[11] = (byte) value;
        transactionId = (transactionId + 1) % 65536;
        return request;
    }
    private byte[] buildWriteMultipleRegistersRequest(int address, int[] values) {
        int byteCount = values.length * 2;
        byte[] request = new byte[13 + byteCount];
        // 事务标识符
        request[0] = (byte) (transactionId >> 8);
        request[1] = (byte) transactionId;
        // 协议标识符 (0)
        request[2] = 0;
        request[3] = 0;
        // 长度 (7 + byteCount)
        request[4] = 0;
        request[5] = (byte) (7 + byteCount);
        // 单元标识符 (1)
        request[6] = 1;
        // 功能码 (16)
        request[7] = 16;
        // 地址
        request[8] = (byte) (address >> 8);
        request[9] = (byte) address;
        // 寄存器数量
        request[10] = (byte) (values.length >> 8);
        request[11] = (byte) values.length;
        // 字节数
        request[12] = (byte) byteCount;
        // 值
        for (int i = 0; i < values.length; i++) {
            request[13 + i*2] = (byte) (values[i] >> 8);
            request[14 + i*2] = (byte) values[i];
        }
        transactionId = (transactionId + 1) % 65536;
        return request;
    }
    private byte[] sendRequest(byte[] request) throws IOException {
        if (!isConnected()) {
            connect();
        }
        InetAddress address = InetAddress.getByName(host);
        DatagramPacket sendPacket = new DatagramPacket(request, request.length, address, port);
        // 发送请求
        socket.send(sendPacket);
        // 接收响应
        byte[] receiveBuffer = new byte[1024];
        DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
        socket.receive(receivePacket);
        return Arrays.copyOf(receiveBuffer, receivePacket.getLength());
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/modbus/ModbusIpServer.java
New file
@@ -0,0 +1,393 @@
package com.mes.connect.modbus;
import com.mes.connect.IndustrialInterface.AddressParser;
import com.mes.connect.IndustrialInterface.IndustrialDataHandler;
import com.mes.connect.IndustrialInterface.IndustrialServer;
import com.mes.connect.addressParser.ModbusIpAddressParser;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Logger;
/**
 * Modbus IP服务器实现(基于UDP)
 */
public class ModbusIpServer implements IndustrialServer {
    private static final Logger logger = Logger.getLogger(ModbusIpServer.class.getName());
    private DatagramSocket serverSocket;
    private Thread serverThread;
    private boolean running;
    private IndustrialDataHandler handler;
    private final int port;
    private final ExecutorService threadPool = Executors.newFixedThreadPool(10);
    private final AddressParser addressParser = new ModbusIpAddressParser();
    public ModbusIpServer(int port) {
        this.port = port;
    }
    @Override
    public synchronized void start() throws IOException {
        if (!running) {
            serverSocket = new DatagramSocket(port);
            serverThread = new Thread(this::serverLoop);
            serverThread.setDaemon(true);
            serverThread.start();
            running = true;
            logger.info("Modbus IP (UDP) server started on port " + port);
        }
    }
    @Override
    public synchronized void stop() {
        if (running) {
            running = false;
            try {
                if (serverSocket != null) {
                    serverSocket.close();
                }
                if (serverThread != null) {
                    serverThread.interrupt();
                    serverThread.join(1000);
                }
                threadPool.shutdownNow();
            } catch (InterruptedException e) {
                logger.warning("Error stopping Modbus IP server: " + e.getMessage());
            } finally {
                serverSocket = null;
                serverThread = null;
                logger.info("Modbus IP (UDP) server stopped");
            }
        }
    }
    @Override
    public boolean isRunning() {
        return running;
    }
    @Override
    public void setDataHandler(IndustrialDataHandler handler) {
        this.handler = handler;
    }
    @Override
    public void close() throws IOException {
        stop();
    }
    private void serverLoop() {
        byte[] receiveBuffer = new byte[1024];
        while (running) {
            try {
                DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
                serverSocket.receive(receivePacket);
                threadPool.submit(() -> handleRequest(receivePacket));
            } catch (IOException e) {
                if (running) {
                    logger.warning("Error receiving packet: " + e.getMessage());
                }
            }
        }
    }
    private void handleRequest(DatagramPacket requestPacket) {
        byte[] requestData = new byte[requestPacket.getLength()];
        System.arraycopy(requestPacket.getData(), requestPacket.getOffset(), requestData, 0, requestPacket.getLength());
        try {
            byte[] responseData = processRequest(requestData);
            DatagramPacket responsePacket = new DatagramPacket(
                    responseData,
                    responseData.length,
                    requestPacket.getAddress(),
                    requestPacket.getPort()
            );
            serverSocket.send(responsePacket);
        } catch (Exception e) {
            logger.warning("Error processing request: " + e.getMessage());
        }
    }
    private byte[] processRequest(byte[] request) {
        int transactionId = ((request[0] & 0xFF) << 8) | (request[1] & 0xFF);
        int unitId = request[6] & 0xFF;
        int functionCode = request[7] & 0xFF;
        try {
            switch (functionCode) {
                case 1: // 读线圈
                    return handleReadCoils(request, transactionId, unitId);
                case 2: // 读离散输入
                    return handleReadDiscreteInputs(request, transactionId, unitId);
                case 3: // 读保持寄存器
                    return handleReadHoldingRegisters(request, transactionId, unitId);
                case 4: // 读输入寄存器
                    return handleReadInputRegisters(request, transactionId, unitId);
                case 5: // 写单个线圈
                    return handleWriteSingleCoil(request, transactionId, unitId);
                case 6: // 写单个寄存器
                    return handleWriteSingleRegister(request, transactionId, unitId);
                case 15: // 写多个线圈
                    return handleWriteMultipleCoils(request, transactionId, unitId);
                case 16: // 写多个寄存器
                    return handleWriteMultipleRegisters(request, transactionId, unitId);
                default:
                    return buildExceptionResponse(transactionId, unitId, functionCode, 1); // 不支持的功能码
            }
        } catch (Exception e) {
            logger.warning("Error processing request: " + e.getMessage());
            return buildExceptionResponse(transactionId, unitId, functionCode, 4); // 服务器设备故障
        }
    }
    private byte[] handleReadCoils(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int quantity = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        if (quantity > 2000) {
            return buildExceptionResponse(transactionId, unitId, 1, 3); // 请求数量过大
        }
        byte[] response = new byte[9 + (quantity + 7) / 8];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = (byte) (response.length - 6); // 长度低字节
        response[6] = (byte) unitId;
        response[7] = 1; // 功能码
        response[8] = (byte) ((quantity + 7) / 8); // 字节数
        // 填充线圈数据
        for (int i = 0; i < quantity; i++) {
            String addressStr = String.format("MB.0x%04d.%d", address + i, 0);
            boolean value = handler.handleReadBit(addressStr);
            int byteIndex = 9 + i / 8;
            int bitIndex = i % 8;
            if (value) {
                response[byteIndex] |= (1 << bitIndex);
            }
        }
        return response;
    }
    private byte[] handleReadDiscreteInputs(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int quantity = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        if (quantity > 2000) {
            return buildExceptionResponse(transactionId, unitId, 2, 3); // 请求数量过大
        }
        byte[] response = new byte[9 + (quantity + 7) / 8];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = (byte) (response.length - 6); // 长度低字节
        response[6] = (byte) unitId;
        response[7] = 2; // 功能码
        response[8] = (byte) ((quantity + 7) / 8); // 字节数
        // 填充离散输入数据
        for (int i = 0; i < quantity; i++) {
            String addressStr = String.format("MB.1x%04d.%d", address + i, 0);
            boolean value = handler.handleReadBit(addressStr);
            int byteIndex = 9 + i / 8;
            int bitIndex = i % 8;
            if (value) {
                response[byteIndex] |= (1 << bitIndex);
            }
        }
        return response;
    }
    private byte[] handleReadInputRegisters(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int quantity = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        if (quantity > 125) {
            return buildExceptionResponse(transactionId, unitId, 4, 3); // 请求数量过大
        }
        byte[] response = new byte[9 + quantity * 2];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = (byte) (response.length - 6); // 长度低字节
        response[6] = (byte) unitId;
        response[7] = 4; // 功能码
        response[8] = (byte) (quantity * 2); // 字节数
        // 填充输入寄存器数据
        for (int i = 0; i < quantity; i++) {
            String addressStr = String.format("MB.3x%04d", address + i);
            int value = handler.handleReadRegister(addressStr);
            int byteIndex = 9 + i * 2;
            response[byteIndex] = (byte) (value >> 8);
            response[byteIndex + 1] = (byte) value;
        }
        return response;
    }
    private byte[] handleReadHoldingRegisters(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int quantity = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        if (quantity > 125) {
            return buildExceptionResponse(transactionId, unitId, 3, 3); // 请求数量过大
        }
        byte[] response = new byte[9 + quantity * 2];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = (byte) (response.length - 6); // 长度低字节
        response[6] = (byte) unitId;
        response[7] = 3; // 功能码
        response[8] = (byte) (quantity * 2); // 字节数
        // 填充保持寄存器数据
        for (int i = 0; i < quantity; i++) {
            String addressStr = String.format("MB.4x%04d", address + i);
            int value = handler.handleReadRegister(addressStr);
            int byteIndex = 9 + i * 2;
            response[byteIndex] = (byte) (value >> 8);
            response[byteIndex + 1] = (byte) value;
        }
        return response;
    }
    private byte[] handleWriteSingleCoil(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int value = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        boolean coilValue = (value == 0xFF00);
        String addressStr = String.format("MB.0x%04d.%d", address, 0);
        handler.handleWriteBit(addressStr, coilValue);
        // 返回与请求相同的数据作为确认
        byte[] response = new byte[12];
        System.arraycopy(request, 0, response, 0, 12);
        return response;
    }
    private byte[] handleWriteSingleRegister(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int value = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        String addressStr = String.format("MB.4x%04d", address);
        handler.handleWriteRegister(addressStr, value);
        // 返回与请求相同的数据作为确认
        byte[] response = new byte[12];
        System.arraycopy(request, 0, response, 0, 12);
        return response;
    }
    private byte[] handleWriteMultipleCoils(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int quantity = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        int byteCount = request[12] & 0xFF;
        if (quantity > 1968) {
            return buildExceptionResponse(transactionId, unitId, 15, 3); // 请求数量过大
        }
        // 处理线圈值
        for (int i = 0; i < quantity; i++) {
            int byteIndex = 13 + i / 8;
            int bitIndex = i % 8;
            boolean value = ((request[byteIndex] & (1 << bitIndex)) != 0);
            String addressStr = String.format("MB.0x%04d.%d", address + i, 0);
            handler.handleWriteBit(addressStr, value);
        }
        // 构建响应
        byte[] response = new byte[12];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = 6; // 长度低字节
        response[6] = (byte) unitId;
        response[7] = 15; // 功能码
        response[8] = (byte) (address >> 8); // 起始地址高字节
        response[9] = (byte) address; // 起始地址低字节
        response[10] = (byte) (quantity >> 8); // 数量高字节
        response[11] = (byte) quantity; // 数量低字节
        return response;
    }
    private byte[] handleWriteMultipleRegisters(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int quantity = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        int byteCount = request[12] & 0xFF;
        if (quantity > 123) {
            return buildExceptionResponse(transactionId, unitId, 16, 3); // 请求数量过大
        }
        int[] values = new int[quantity];
        // 解析寄存器值
        for (int i = 0; i < quantity; i++) {
            int byteIndex = 13 + i * 2;
            values[i] = ((request[byteIndex] & 0xFF) << 8) | (request[byteIndex + 1] & 0xFF);
        }
        // 处理写入请求
        String addressStr = String.format("MB.4x%04d", address);
        handler.handleWriteRegisters(addressStr, values);
        // 构建响应
        byte[] response = new byte[12];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = 6; // 长度低字节
        response[6] = (byte) unitId;
        response[7] = 16; // 功能码
        response[8] = (byte) (address >> 8); // 起始地址高字节
        response[9] = (byte) address; // 起始地址低字节
        response[10] = (byte) (quantity >> 8); // 数量高字节
        response[11] = (byte) quantity; // 数量低字节
        return response;
    }
    private byte[] buildExceptionResponse(int transactionId, int unitId, int functionCode, int exceptionCode) {
        byte[] response = new byte[9];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = 3; // 长度低字节
        response[6] = (byte) unitId;
        response[7] = (byte) (functionCode + 0x80); // 异常功能码
        response[8] = (byte) exceptionCode; // 异常码
        return response;
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/modbus/ModbusTcpClient.java
New file
@@ -0,0 +1,374 @@
package com.mes.connect.modbus;
import com.mes.connect.IndustrialInterface.AddressParser;
import com.mes.connect.IndustrialInterface.IndustrialClient;
import com.mes.connect.addressParser.ModbusAddressParser;
import com.mes.connect.protocol.ProtocolAddress;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.logging.Logger;
/**
 * Modbus TCP客户端实现
 */
public class ModbusTcpClient implements IndustrialClient {
    private static final Logger logger = Logger.getLogger(ModbusTcpClient.class.getName());
    private Socket socket;
    private DataInputStream inputStream;
    private DataOutputStream outputStream;
    private final String host;
    private final int port;
    private final int unitId;
    private int transactionId = 0;
    private boolean connected;
    private final AddressParser addressParser = new ModbusAddressParser();
    public ModbusTcpClient(String host, int port, int unitId) {
        this.host = host;
        this.port = port;
        this.unitId = unitId;
    }
    @Override
    public synchronized void connect() throws IOException {
        if (!connected) {
            socket = new Socket(host, port);
            socket.setSoTimeout(5000); // 5秒超时
            inputStream = new DataInputStream(socket.getInputStream());
            outputStream = new DataOutputStream(socket.getOutputStream());
            connected = true;
            logger.info("Connected to Modbus TCP server: " + host + ":" + port);
        }
    }
    @Override
    public synchronized void disconnect() {
        if (connected) {
            try {
                if (outputStream != null) outputStream.close();
                if (inputStream != null) inputStream.close();
                if (socket != null) socket.close();
            } catch (IOException e) {
                logger.warning("Error closing Modbus TCP connection: " + e.getMessage());
            } finally {
                outputStream = null;
                inputStream = null;
                socket = null;
                connected = false;
                logger.info("Disconnected from Modbus TCP server");
            }
        }
    }
    @Override
    public boolean isConnected() {
        return connected && socket != null && socket.isConnected() && !socket.isClosed();
    }
    @Override
    public boolean readBit(String address) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        String[] parts = address.split("\\.");
        String strAddress ="";
        if (parts.length >1) {
            strAddress = parts[0]+"."+parts[1];
        }
        int[] data = readRegisters(strAddress, 1);
        int byteValue = data[0];
        return (byteValue & (1 << parsedAddress.getBit())) != 0;
    }
    @Override
    public void writeBit(String address, boolean value) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        String[] parts = address.split("\\.");
        String strAddress ="";
        if (parts.length >1) {
            strAddress = parts[0]+"."+parts[1];
        }
        int[] currentData = readRegisters(strAddress, 1);
        int byteValue = currentData[0];
        if (value) {
            byteValue |= (1 << parsedAddress.getBit());
        } else {
            byteValue &= ~(1 << parsedAddress.getBit());
        }
        writeRegister(strAddress, byteValue);
    }
//    @Override
//    public boolean readBit(String address) throws IOException {
//        ProtocolAddress parsedAddress = addressParser.parse(address);
//        int functionCode = parsedAddress.getFunctionCode();
//        if (functionCode != 1 && functionCode != 2) {
//            throw new IllegalArgumentException("Invalid function code for reading bit: " + functionCode);
//        }
//
//        byte[] request = buildReadRequest(functionCode, parsedAddress.getAddress(), 1);
//        byte[] response = sendRequest(request);
//
//        if (response[8] == 0x01) { // 1字节数据
//            return (response[9] & (1 << parsedAddress.getBit())) != 0;
//        }
//
//        throw new IOException("Unexpected response format for reading bit");
//    }
//
//    @Override
//    public void writeBit(String address, boolean value) throws IOException {
//        ProtocolAddress parsedAddress = addressParser.parse(address);
//        int functionCode = 5; // 写单个线圈
//
//        byte[] request = new byte[12];
//        request[0] = (byte) (transactionId >> 8);    // 事务标识符高字节
//        request[1] = (byte) transactionId++;         // 事务标识符低字节
//        request[2] = 0;                            // 协议标识符高字节 (0)
//        request[3] = 0;                            // 协议标识符低字节 (0)
//        request[4] = 0;                            // 长度高字节
//        request[5] = 6;                            // 长度低字节 (6)
//        request[6] = (byte) unitId;                // 单元标识符
//        request[7] = (byte) functionCode;          // 功能码
//        request[8] = (byte) (parsedAddress.getAddress() >> 8); // 地址高字节
//        request[9] = (byte) parsedAddress.getAddress();        // 地址低字节
//        request[10] = value ? (byte) 0xFF : 0;     // 值 (0xFF00 = ON, 0x0000 = OFF)
//        request[11] = 0;                           // 值低字节
//
//        byte[] response = sendRequest(request);
//
//        // 验证响应
//        if (response[7] != functionCode) {
//            throw new IOException("Modbus exception: " + (response[7] & 0xFF));
//        }
//    }
    @Override
    public int readRegister(String address) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int functionCode = parsedAddress.getFunctionCode();
        if (functionCode != 3 && functionCode != 4) {
            throw new IllegalArgumentException("Invalid function code for reading register: " + functionCode);
        }
        byte[] request = buildReadRequest(functionCode, parsedAddress.getAddress(), 1);
        byte[] response = sendRequest(request);
        if (response[8] == 0x02) { // 2字节数据
            return ((response[9] & 0xFF) << 8) | (response[10] & 0xFF);
        }
        throw new IOException("Unexpected response format for reading register");
    }
    @Override
    public void writeRegister(String address, int value) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int functionCode = 6; // 写单个寄存器
        byte[] request = new byte[12];
        request[0] = (byte) (transactionId >> 8);    // 事务标识符高字节
        request[1] = (byte) transactionId++;         // 事务标识符低字节
        request[2] = 0;                            // 协议标识符高字节 (0)
        request[3] = 0;                            // 协议标识符低字节 (0)
        request[4] = 0;                            // 长度高字节
        request[5] = 6;                            // 长度低字节 (6)
        request[6] = (byte) unitId;                // 单元标识符
        request[7] = (byte) functionCode;          // 功能码
        request[8] = (byte) (parsedAddress.getAddress() >> 8); // 地址高字节
        request[9] = (byte) parsedAddress.getAddress();        // 地址低字节
        request[10] = (byte) (value >> 8);         // 值高字节
        request[11] = (byte) value;                // 值低字节
        byte[] response = sendRequest(request);
        // 验证响应
        if (response[7] != functionCode) {
            throw new IOException("Modbus exception: " + (response[7] & 0xFF));
        }
    }
    @Override
    public int[] readRegisters(String address, int quantity) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int functionCode = parsedAddress.getFunctionCode();
        if (functionCode != 3 && functionCode != 4) {
            throw new IllegalArgumentException("Invalid function code for reading registers: " + functionCode);
        }
        byte[] request = buildReadRequest(functionCode, parsedAddress.getAddress(), quantity);
        byte[] response = sendRequest(request);
        int byteCount = response[8] & 0xFF;
        int[] result = new int[byteCount / 2];
        for (int i = 0; i < result.length; i++) {
            int index = 9 + i * 2;
            result[i] = ((response[index] & 0xFF) << 8) | (response[index + 1] & 0xFF);
        }
        return result;
    }
    @Override
    public void writeRegisters(String address, int[] values) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int functionCode = 16; // 写多个寄存器
        int byteCount = values.length * 2;
        int requestLength = 9 + byteCount;
        byte[] request = new byte[requestLength];
        request[0] = (byte) (transactionId >> 8);    // 事务标识符高字节
        request[1] = (byte) transactionId++;         // 事务标识符低字节
        request[2] = 0;                            // 协议标识符高字节 (0)
        request[3] = 0;                            // 协议标识符低字节 (0)
        request[4] = (byte) ((requestLength - 6) >> 8); // 长度高字节
        request[5] = (byte) (requestLength - 6);         // 长度低字节
        request[6] = (byte) unitId;                // 单元标识符
        request[7] = (byte) functionCode;          // 功能码
        request[8] = (byte) (parsedAddress.getAddress() >> 8); // 地址高字节
        request[9] = (byte) parsedAddress.getAddress();        // 地址低字节
        request[10] = (byte) (values.length >> 8);  // 寄存器数量高字节
        request[11] = (byte) values.length;         // 寄存器数量低字节
        request[12] = (byte) byteCount;             // 字节数
        // 填充寄存器值
        for (int i = 0; i < values.length; i++) {
            int index = 13 + i * 2;
            request[index] = (byte) (values[i] >> 8);     // 值高字节
            request[index + 1] = (byte) values[i];        // 值低字节
        }
        byte[] response = sendRequest(request);
        // 验证响应
        if (response[7] != functionCode) {
            throw new IOException("Modbus exception: " + (response[7] & 0xFF));
        }
    }
    @Override
    public float readFloat(String address) throws IOException {
        int[] registers = readRegisters(address, 2);
        int intBits = (registers[0] << 16) | registers[1];
        return Float.intBitsToFloat(intBits);
    }
    @Override
    public void writeFloat(String address, float value) throws IOException {
        int intBits = Float.floatToIntBits(value);
        int highWord = (intBits >> 16) & 0xFFFF;
        int lowWord = intBits & 0xFFFF;
        writeRegisters(address, new int[]{highWord, lowWord});
    }
    @Override
    public String readString(String address, int length) throws IOException {
        int[] registers = readRegisters(address, (length + 1) / 2);
        byte[] bytes = new byte[registers.length * 2];
        for (int i = 0; i < registers.length; i++) {
            bytes[i * 2] = (byte) ((registers[i] >> 8) & 0xFF);
            bytes[i * 2 + 1] = (byte) (registers[i] & 0xFF);
        }
        return new String(bytes, 0, length);
    }
    @Override
    public void writeString(String address, String value) throws IOException {
        byte[] bytes = value.getBytes();
        int[] registers = new int[(bytes.length + 1) / 2];
        for (int i = 0; i < bytes.length; i++) {
            int regIndex = i / 2;
            int byteIndex = i % 2;
            if (byteIndex == 0) {
                registers[regIndex] = (bytes[i] & 0xFF) << 8;
            } else {
                registers[regIndex] |= (bytes[i] & 0xFF);
            }
        }
        writeRegisters(address, registers);
    }
    @Override
    public void close() throws IOException {
        disconnect();
    }
    private byte[] buildReadRequest(int functionCode, int address, int quantity) {
        byte[] request = new byte[12];
        request[0] = (byte) (transactionId >> 8);    // 事务标识符高字节
        request[1] = (byte) transactionId++;         // 事务标识符低字节
        request[2] = 0;                            // 协议标识符高字节 (0)
        request[3] = 0;                            // 协议标识符低字节 (0)
        request[4] = 0;                            // 长度高字节
        request[5] = 6;                            // 长度低字节 (6)
        request[6] = (byte) unitId;                // 单元标识符
        request[7] = (byte) functionCode;          // 功能码
        request[8] = (byte) (address >> 8);        // 地址高字节
        request[9] = (byte) address;               // 地址低字节
        request[10] = (byte) (quantity >> 8);      // 数量高字节
        request[11] = (byte) quantity;             // 数量低字节
        return request;
    }
    private byte[] sendRequest(byte[] request) throws IOException {
        if (!isConnected()) {
            connect();
        }
        // 发送请求
        outputStream.write(request);
        outputStream.flush();
        // 接收响应
        byte[] header = new byte[6];
        int bytesRead = 0;
        // 读取头部
        while (bytesRead < 6) {
            int count = inputStream.read(header, bytesRead, 6 - bytesRead);
            if (count == -1) {
                throw new IOException("Connection closed while reading response header");
            }
            bytesRead += count;
        }
        int length = ((header[4] & 0xFF) << 8) | (header[5] & 0xFF);
        byte[] response = new byte[6 + length];
        // 复制头部
        System.arraycopy(header, 0, response, 0, 6);
        // 读取剩余部分
        bytesRead = 0;
        while (bytesRead < length) {
            int count = inputStream.read(response, 6 + bytesRead, length - bytesRead);
            if (count == -1) {
                throw new IOException("Connection closed while reading response body");
            }
            bytesRead += count;
        }
        // 检查事务标识符
        if ((response[0] & 0xFF) != (request[0] & 0xFF) || (response[1] & 0xFF) != (request[1] & 0xFF)) {
            logger.warning("Transaction ID mismatch in response - expected: " +
                    ((request[0] & 0xFF) << 8 | (request[1] & 0xFF)) +
                    ", got: " + ((response[0] & 0xFF) << 8 | (response[1] & 0xFF)));
            // 虽然事务ID不匹配,但可能是之前请求的响应,选择继续处理而不是抛出异常
        }
        // 检查功能码(如果有异常,功能码会是0x80 + 原功能码)
        if ((response[7] & 0xFF) > 0x80) {
            int exceptionCode = response[8] & 0xFF;
            throw new IOException("Modbus exception: " + exceptionCode);
        }
        return response;
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/modbus/ModbusTcpServer.java
New file
@@ -0,0 +1,419 @@
package com.mes.connect.modbus;
import com.mes.connect.IndustrialInterface.AddressParser;
import com.mes.connect.IndustrialInterface.IndustrialDataHandler;
import com.mes.connect.IndustrialInterface.IndustrialServer;
import com.mes.connect.addressParser.ModbusAddressParser;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Logger;
/**
 * Modbus TCP服务器实现
 */
public class ModbusTcpServer implements IndustrialServer {
    private static final Logger logger = Logger.getLogger(ModbusTcpServer.class.getName());
    private ServerSocket serverSocket;
    private Thread serverThread;
    private boolean running;
    private IndustrialDataHandler handler;
    private final int port;
    private final ExecutorService threadPool = Executors.newFixedThreadPool(10);
    private final AddressParser addressParser = new ModbusAddressParser();
    public ModbusTcpServer(int port) {
        this.port = port;
    }
    @Override
    public synchronized void start() throws IOException {
        if (!running) {
            serverSocket = new ServerSocket(port);
            serverThread = new Thread(this::serverLoop);
            serverThread.setDaemon(true);
            serverThread.start();
            running = true;
            logger.info("Modbus TCP server started on port " + port);
        }
    }
    @Override
    public synchronized void stop() {
        if (running) {
            running = false;
            try {
                if (serverSocket != null) {
                    serverSocket.close();
                }
                if (serverThread != null) {
                    serverThread.interrupt();
                    serverThread.join(1000);
                }
                threadPool.shutdownNow();
            } catch (IOException | InterruptedException e) {
                logger.warning("Error stopping Modbus TCP server: " + e.getMessage());
            } finally {
                serverSocket = null;
                serverThread = null;
                logger.info("Modbus TCP server stopped");
            }
        }
    }
    @Override
    public boolean isRunning() {
        return running;
    }
    @Override
    public void setDataHandler(IndustrialDataHandler handler) {
        this.handler = handler;
    }
    @Override
    public void close() throws IOException {
        stop();
    }
    private void serverLoop() {
        while (running) {
            try {
                Socket clientSocket = serverSocket.accept();
                threadPool.submit(() -> handleClient(clientSocket));
            } catch (IOException e) {
                if (running) {
                    logger.warning("Error accepting client connection: " + e.getMessage());
                }
            }
        }
    }
    private void handleClient(Socket clientSocket) {
        try (DataInputStream input = new DataInputStream(clientSocket.getInputStream());
             DataOutputStream output = new DataOutputStream(clientSocket.getOutputStream())) {
            byte[] request = readRequest(input);
            byte[] response = processRequest(request);
            output.write(response);
        } catch (IOException e) {
            logger.warning("Error handling client: " + e.getMessage());
        }
    }
    private byte[] readRequest(DataInputStream input) throws IOException {
        // 读取Modbus TCP请求
        byte[] header = new byte[6];
        int bytesRead = 0;
        // 读取头部
        while (bytesRead < 6) {
            int count = input.read(header, bytesRead, 6 - bytesRead);
            if (count == -1) {
                throw new IOException("Connection closed while reading request header");
            }
            bytesRead += count;
        }
        int length = ((header[4] & 0xFF) << 8) | (header[5] & 0xFF);
        byte[] request = new byte[6 + length];
        // 复制头部
        System.arraycopy(header, 0, request, 0, 6);
        // 读取剩余部分
        bytesRead = 0;
        while (bytesRead < length) {
            int count = input.read(request, 6 + bytesRead, length - bytesRead);
            if (count == -1) {
                throw new IOException("Connection closed while reading request body");
            }
            bytesRead += count;
        }
        return request;
    }
    private byte[] processRequest(byte[] request) {
        int transactionId = ((request[0] & 0xFF) << 8) | (request[1] & 0xFF);
        int unitId = request[6] & 0xFF;
        int functionCode = request[7] & 0xFF;
        try {
            switch (functionCode) {
                case 1: // 读线圈
                    return handleReadCoils(request, transactionId, unitId);
                case 2: // 读离散输入
                    return handleReadDiscreteInputs(request, transactionId, unitId);
                case 3: // 读保持寄存器
                    return handleReadHoldingRegisters(request, transactionId, unitId);
                case 4: // 读输入寄存器
                    return handleReadInputRegisters(request, transactionId, unitId);
                case 5: // 写单个线圈
                    return handleWriteSingleCoil(request, transactionId, unitId);
                case 6: // 写单个寄存器
                    return handleWriteSingleRegister(request, transactionId, unitId);
                case 15: // 写多个线圈
                    return handleWriteMultipleCoils(request, transactionId, unitId);
                case 16: // 写多个寄存器
                    return handleWriteMultipleRegisters(request, transactionId, unitId);
                default:
                    return buildExceptionResponse(transactionId, unitId, functionCode, 1); // 不支持的功能码
            }
        } catch (Exception e) {
            logger.warning("Error processing request: " + e.getMessage());
            return buildExceptionResponse(transactionId, unitId, functionCode, 4); // 服务器设备故障
        }
    }
    private byte[] handleReadCoils(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int quantity = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        if (quantity > 2000) {
            return buildExceptionResponse(transactionId, unitId, 1, 3); // 请求数量过大
        }
        byte[] response = new byte[9 + (quantity + 7) / 8];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = (byte) (response.length - 6); // 长度低字节
        response[6] = (byte) unitId;
        response[7] = 1; // 功能码
        response[8] = (byte) ((quantity + 7) / 8); // 字节数
        // 填充线圈数据
        for (int i = 0; i < quantity; i++) {
            String addressStr = String.format("MB.0x%04d.%d", address + i, 0);
            boolean value = handler.handleReadBit(addressStr);
            int byteIndex = 9 + i / 8;
            int bitIndex = i % 8;
            if (value) {
                response[byteIndex] |= (1 << bitIndex);
            }
        }
        return response;
    }
    private byte[] handleReadDiscreteInputs(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int quantity = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        if (quantity > 2000) {
            return buildExceptionResponse(transactionId, unitId, 2, 3); // 请求数量过大
        }
        byte[] response = new byte[9 + (quantity + 7) / 8];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = (byte) (response.length - 6); // 长度低字节
        response[6] = (byte) unitId;
        response[7] = 2; // 功能码
        response[8] = (byte) ((quantity + 7) / 8); // 字节数
        // 填充离散输入数据
        for (int i = 0; i < quantity; i++) {
            String addressStr = String.format("MB.1x%04d.%d", address + i, 0);
            boolean value = handler.handleReadBit(addressStr);
            int byteIndex = 9 + i / 8;
            int bitIndex = i % 8;
            if (value) {
                response[byteIndex] |= (1 << bitIndex);
            }
        }
        return response;
    }
    private byte[] handleReadHoldingRegisters(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int quantity = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        if (quantity > 125) {
            return buildExceptionResponse(transactionId, unitId, 3, 3); // 请求数量过大
        }
        byte[] response = new byte[9 + quantity * 2];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = (byte) (response.length - 6); // 长度低字节
        response[6] = (byte) unitId;
        response[7] = 3; // 功能码
        response[8] = (byte) (quantity * 2); // 字节数
        // 填充保持寄存器数据
        for (int i = 0; i < quantity; i++) {
            String addressStr = String.format("MB.4x%04d", address + i);
            int value = handler.handleReadRegister(addressStr);
            int byteIndex = 9 + i * 2;
            response[byteIndex] = (byte) (value >> 8);
            response[byteIndex + 1] = (byte) value;
        }
        return response;
    }
    private byte[] handleReadInputRegisters(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int quantity = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        if (quantity > 125) {
            return buildExceptionResponse(transactionId, unitId, 4, 3); // 请求数量过大
        }
        byte[] response = new byte[9 + quantity * 2];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = (byte) (response.length - 6); // 长度低字节
        response[6] = (byte) unitId;
        response[7] = 4; // 功能码
        response[8] = (byte) (quantity * 2); // 字节数
        // 填充输入寄存器数据
        for (int i = 0; i < quantity; i++) {
            String addressStr = String.format("MB.3x%04d", address + i);
            int value = handler.handleReadRegister(addressStr);
            int byteIndex = 9 + i * 2;
            response[byteIndex] = (byte) (value >> 8);
            response[byteIndex + 1] = (byte) value;
        }
        return response;
    }
    private byte[] handleWriteSingleCoil(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int value = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        boolean coilValue = (value == 0xFF00);
        String addressStr = String.format("MB.0x%04d.%d", address, 0);
        handler.handleWriteBit(addressStr, coilValue);
        // 返回与请求相同的数据作为确认
        byte[] response = new byte[12];
        System.arraycopy(request, 0, response, 0, 12);
        return response;
    }
    private byte[] handleWriteSingleRegister(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int value = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        String addressStr = String.format("MB.4x%04d", address);
        handler.handleWriteRegister(addressStr, value);
        // 返回与请求相同的数据作为确认
        byte[] response = new byte[12];
        System.arraycopy(request, 0, response, 0, 12);
        return response;
    }
    private byte[] handleWriteMultipleCoils(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int quantity = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        int byteCount = request[12] & 0xFF;
        if (quantity > 1968) {
            return buildExceptionResponse(transactionId, unitId, 15, 3); // 请求数量过大
        }
        // 处理线圈值
        for (int i = 0; i < quantity; i++) {
            int byteIndex = 13 + i / 8;
            int bitIndex = i % 8;
            boolean value = ((request[byteIndex] & (1 << bitIndex)) != 0);
            String addressStr = String.format("MB.0x%04d.%d", address + i, 0);
            handler.handleWriteBit(addressStr, value);
        }
        // 构建响应
        byte[] response = new byte[12];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = 6; // 长度低字节
        response[6] = (byte) unitId;
        response[7] = 15; // 功能码
        response[8] = (byte) (address >> 8); // 起始地址高字节
        response[9] = (byte) address; // 起始地址低字节
        response[10] = (byte) (quantity >> 8); // 数量高字节
        response[11] = (byte) quantity; // 数量低字节
        return response;
    }
    private byte[] handleWriteMultipleRegisters(byte[] request, int transactionId, int unitId) {
        int address = ((request[8] & 0xFF) << 8) | (request[9] & 0xFF);
        int quantity = ((request[10] & 0xFF) << 8) | (request[11] & 0xFF);
        int byteCount = request[12] & 0xFF;
        if (quantity > 123) {
            return buildExceptionResponse(transactionId, unitId, 16, 3); // 请求数量过大
        }
        int[] values = new int[quantity];
        // 解析寄存器值
        for (int i = 0; i < quantity; i++) {
            int byteIndex = 13 + i * 2;
            values[i] = ((request[byteIndex] & 0xFF) << 8) | (request[byteIndex + 1] & 0xFF);
        }
        // 处理写入请求
        String addressStr = String.format("MB.4x%04d", address);
        handler.handleWriteRegisters(addressStr, values);
        // 构建响应
        byte[] response = new byte[12];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = 6; // 长度低字节
        response[6] = (byte) unitId;
        response[7] = 16; // 功能码
        response[8] = (byte) (address >> 8); // 起始地址高字节
        response[9] = (byte) address; // 起始地址低字节
        response[10] = (byte) (quantity >> 8); // 数量高字节
        response[11] = (byte) quantity; // 数量低字节
        return response;
    }
    private byte[] buildExceptionResponse(int transactionId, int unitId, int functionCode, int exceptionCode) {
        byte[] response = new byte[9];
        response[0] = (byte) (transactionId >> 8);
        response[1] = (byte) transactionId;
        response[2] = 0; // 协议标识符高字节
        response[3] = 0; // 协议标识符低字节
        response[4] = 0; // 长度高字节
        response[5] = 3; // 长度低字节
        response[6] = (byte) unitId;
        response[7] = (byte) (functionCode + 0x80); // 异常功能码
        response[8] = (byte) exceptionCode; // 异常码
        return response;
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/protocol/ProtocolAddress.java
New file
@@ -0,0 +1,38 @@
package com.mes.connect.protocol;
/**
 * 协议地址类
 */
public class ProtocolAddress {
    private final ProtocolType protocol;
    private final int functionCode;
    private final int dbNumber;
    private final int address;
    private final int bit;
    public ProtocolAddress(ProtocolType protocol, int functionCode, int dbNumber, int address, int bit) {
        this.protocol = protocol;
        this.functionCode = functionCode;
        this.dbNumber = dbNumber;
        this.address = address;
        this.bit = bit;
    }
    // Getters
    public ProtocolType getProtocol() { return protocol; }
    public int getFunctionCode() { return functionCode; }
    public int getDbNumber() { return dbNumber; }
    public int getAddress() { return address; }
    public int getBit() { return bit; }
    @Override
    public String toString() {
        return "ProtocolAddress{" +
                "protocol=" + protocol +
                ", functionCode=" + functionCode +
                ", dbNumber=" + dbNumber +
                ", address=" + address +
                ", bit=" + bit +
                '}';
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/protocol/ProtocolType.java
New file
@@ -0,0 +1,8 @@
package com.mes.connect.protocol;
/**
 * 协议类型枚举
 */
public enum ProtocolType {
    S7, MODBUS_TCP, MODBUS_IP, MODBUS_RTU
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/s7/S7Client.java
New file
@@ -0,0 +1,615 @@
package com.mes.connect.s7;
import com.mes.connect.IndustrialInterface.AddressParser;
import com.mes.connect.IndustrialInterface.IndustrialClient;
import com.mes.connect.addressParser.S7AddressParser;
import com.mes.connect.protocol.ProtocolAddress;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Random;
import java.util.logging.Logger;
/**
 * S7协议客户端实现
 */
public class S7Client implements IndustrialClient {
    private static final Logger logger = Logger.getLogger(S7Client.class.getName());
    private Socket socket;
    private DataInputStream inputStream;
    private DataOutputStream outputStream;
    private final String host;
    private final int port;
    private final int rack;
    private final int slot;
    private boolean connected;
    private int pduSize = 480;
    private int jobId = new Random().nextInt(0xFFFF);
    private final AddressParser addressParser = new S7AddressParser();
    public S7Client(String host, int port, int rack, int slot) {
        this.host = host;
        this.port = port;
        this.rack = rack;
        this.slot = slot;
    }
    @Override
    public synchronized void connect() throws IOException {
        if (!connected) {
            socket = new Socket(host, port);
            socket.setSoTimeout(5000); // 5秒超时
            inputStream = new DataInputStream(socket.getInputStream());
            outputStream = new DataOutputStream(socket.getOutputStream());
            // 建立COTP连接
            if (!establishCotpConnection()) {
                disconnect();
                throw new IOException("Failed to establish COTP connection");
            }
            // 建立ISO连接
            if (!establishIsoConnection()) {
                disconnect();
                throw new IOException("Failed to establish ISO connection");
            }
            // 建立S7连接
            if (!establishS7Connection()) {
                disconnect();
                throw new IOException("Failed to establish S7 connection");
            }
            connected = true;
            logger.info("Connected to S7 server: " + host + ":" + port);
        }
    }
    private boolean establishCotpConnection() throws IOException {
        // 打印调试信息
        logger.info("Attempting to establish COTP connection");
        // 构造COTP连接请求包(CR)
        byte[] request = new byte[11];
        request[0] = 0x02;          // 包长度(固定为2字节)
        request[1] = (byte) 0xE0;   // COTP TPDU类型: CR(连接请求)
        request[2] = 0x00;          // 目标参考号(高字节)
        request[3] = 0x01;          // 目标参考号(低字节)
        request[4] = 0x00;          // 源参考号(高字节)
        request[5] = 0x00;          // 源参考号(低字节)
        request[6] = 0x00;          // 类/选项
        request[7] = (byte) 0xC0;   // 参数代码: TPDU-size
        request[8] = 0x01;          // 参数长度
        request[9] = 0x14;          // TPDU-size(20字节,部分PLC要求此值)
        request[10] = 0x00;         // 参数结束标记
        // 发送COTP请求
        outputStream.write(request);
        outputStream.flush();
        // 打印发送的请求包(16进制)
        logger.info("Sent COTP CR: " + bytesToHex(request));
        // 读取响应包
        byte[] response = new byte[256];
        int bytesRead = 0;
        try {
            // 增加读取超时处理
            socket.setSoTimeout(2000); // 延长读取超时为2秒
            bytesRead = inputStream.read(response);
        } catch (IOException e) {
            logger.warning("COTP response read timeout: " + e.getMessage());
            return false;
        } finally {
            socket.setSoTimeout(5000); // 恢复默认超时
        }
        // 打印接收的响应包(16进制)
        if (bytesRead > 0) {
            logger.info("Received COTP response, bytesRead: " + bytesRead);
            logger.info("COTP response: " + bytesToHex(response, bytesRead));
        } else {
            logger.warning("COTP response is empty");
            return false;
        }
        // 增强响应验证逻辑
        if (bytesRead >= 6) {
            byte tpduType = response[1];
            // 允许CC(0xD0)或ER(0xF0)响应,便于调试
            if (tpduType == 0xD0) { // CC: 连接确认
                logger.info("COTP connection established successfully");
                return true;
            } else if (tpduType == 0xF0) { // ER: 连接拒绝
                logger.warning("COTP connection rejected");
                if (bytesRead >= 8) {
                    logger.warning("COTP error code: 0x" +
                            String.format("%02X", response[7]));
                }
            } else {
                logger.warning("Unexpected COTP TPDU type: 0x" +
                        String.format("%02X", tpduType));
            }
        } else {
            logger.warning("Invalid COTP response length: " + bytesRead);
        }
        return false;
    }
    // 辅助方法:字节数组转16进制字符串
    private String bytesToHex(byte[] bytes) {
        return bytesToHex(bytes, bytes.length);
    }
    private String bytesToHex(byte[] bytes, int length) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(String.format("%02X ", bytes[i]));
            if (i % 16 == 15) sb.append("\n"); // 每16字节换行
        }
        return sb.toString();
    }
    @Override
    public synchronized void disconnect() {
        if (connected) {
            try {
                if (outputStream != null) outputStream.close();
                if (inputStream != null) inputStream.close();
                if (socket != null) socket.close();
            } catch (IOException e) {
                logger.warning("Error closing S7 connection: " + e.getMessage());
            } finally {
                outputStream = null;
                inputStream = null;
                socket = null;
                connected = false;
                logger.info("Disconnected from S7 server");
            }
        }
    }
    @Override
    public boolean isConnected() {
        return connected && socket != null && socket.isConnected() && !socket.isClosed();
    }
    @Override
    public boolean readBit(String address) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int dbNumber = parsedAddress.getDbNumber();
        int area = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        int bit = parsedAddress.getBit();
        byte[] request = buildS7ReadRequest(area, dbNumber, startAddress, 1, 0x04); // 读取字节
        byte[] response = sendS7Request(request);
        if (response[22] == 0x00) { // 成功
            byte data = response[25];
            return (data & (1 << bit)) != 0;
        }
        throw new IOException("S7 read error: " + response[22]);
    }
    @Override
    public void writeBit(String address, boolean value) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int dbNumber = parsedAddress.getDbNumber();
        int area = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        int bit = parsedAddress.getBit();
        // 先读取当前值
        byte[] request = buildS7ReadRequest(area, dbNumber, startAddress, 1, 0x04); // 读取字节
        byte[] response = sendS7Request(request);
        if (response[22] != 0x00) { // 读取失败
            throw new IOException("S7 read error: " + response[22]);
        }
        byte data = response[25];
        // 修改位值
        if (value) {
            data |= (1 << bit);
        } else {
            data &= ~(1 << bit);
        }
        // 写入修改后的值
        request = buildS7WriteRequest(area, dbNumber, startAddress, new byte[]{data}, 0x04);
        response = sendS7Request(request);
        if (response[22] != 0x00) { // 写入失败
            throw new IOException("S7 write error: " + response[22]);
        }
    }
    @Override
    public int readRegister(String address) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int dbNumber = parsedAddress.getDbNumber();
        int area = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        byte[] request = buildS7ReadRequest(area, dbNumber, startAddress, 2, 0x06); // 读取字
        byte[] response = sendS7Request(request);
        if (response[22] == 0x00) { // 成功
            return ((response[25] & 0xFF) << 8) | (response[26] & 0xFF);
        }
        throw new IOException("S7 read error: " + response[22]);
    }
    @Override
    public void writeRegister(String address, int value) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int dbNumber = parsedAddress.getDbNumber();
        int area = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        byte[] data = new byte[2];
        data[0] = (byte) (value >> 8);
        data[1] = (byte) value;
        byte[] request = buildS7WriteRequest(area, dbNumber, startAddress, data, 0x06);
        byte[] response = sendS7Request(request);
        if (response[22] != 0x00) { // 写入失败
            throw new IOException("S7 write error: " + response[22]);
        }
    }
    @Override
    public int[] readRegisters(String address, int quantity) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int dbNumber = parsedAddress.getDbNumber();
        int area = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        byte[] request = buildS7ReadRequest(area, dbNumber, startAddress, quantity * 2, 0x06); // 读取多个字
        byte[] response = sendS7Request(request);
        if (response[22] == 0x00) { // 成功
            int[] result = new int[quantity];
            for (int i = 0; i < quantity; i++) {
                result[i] = ((response[25 + i * 2] & 0xFF) << 8) | (response[26 + i * 2] & 0xFF);
            }
            return result;
        }
        throw new IOException("S7 read error: " + response[22]);
    }
    @Override
    public void writeRegisters(String address, int[] values) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int dbNumber = parsedAddress.getDbNumber();
        int area = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        byte[] data = new byte[values.length * 2];
        for (int i = 0; i < values.length; i++) {
            data[i * 2] = (byte) (values[i] >> 8);
            data[i * 2 + 1] = (byte) values[i];
        }
        byte[] request = buildS7WriteRequest(area, dbNumber, startAddress, data, 0x06);
        byte[] response = sendS7Request(request);
        if (response[22] != 0x00) { // 写入失败
            throw new IOException("S7 write error: " + response[22]);
        }
    }
    @Override
    public float readFloat(String address) throws IOException {
        int[] registers = readRegisters(address, 2);
        int intBits = (registers[0] << 16) | registers[1];
        return Float.intBitsToFloat(intBits);
    }
    @Override
    public void writeFloat(String address, float value) throws IOException {
        int intBits = Float.floatToIntBits(value);
        int highWord = (intBits >> 16) & 0xFFFF;
        int lowWord = intBits & 0xFFFF;
        writeRegisters(address, new int[]{highWord, lowWord});
    }
    @Override
    public String readString(String address, int length) throws IOException {
        int[] registers = readRegisters(address, (length + 1) / 2);
        byte[] bytes = new byte[registers.length * 2];
        for (int i = 0; i < registers.length; i++) {
            bytes[i * 2] = (byte) ((registers[i] >> 8) & 0xFF);
            bytes[i * 2 + 1] = (byte) (registers[i] & 0xFF);
        }
        return new String(bytes, 0, length);
    }
    @Override
    public void writeString(String address, String value) throws IOException {
        byte[] bytes = value.getBytes();
        int[] registers = new int[(bytes.length + 1) / 2];
        for (int i = 0; i < bytes.length; i++) {
            int regIndex = i / 2;
            int byteIndex = i % 2;
            if (byteIndex == 0) {
                registers[regIndex] = (bytes[i] & 0xFF) << 8;
            } else {
                registers[regIndex] |= (bytes[i] & 0xFF);
            }
        }
        writeRegisters(address, registers);
    }
    @Override
    public void close() throws IOException {
        disconnect();
    }
    private boolean establishIsoConnection() throws IOException {
        byte[] request = new byte[21];
        request[0] = 0x03; // Protocol ID
        request[1] = 0x00;
        request[2] = 0x00;
        request[3] = 0x15; // Length
        request[4] = 0x02; // COTP header length
        request[5] = (byte) 0xF0; // COTP TPDU type: DT
        request[6] = (byte) 0x80; // TPDU number
        request[7] = 0x00; // Parameter code: ISO-COTP
        request[8] = 0x0A; // Parameter length
        request[9] = 0x02; // Protocol version
        request[10] = 0x01; // Reserved
        request[11] = 0x00; // Source TSAP high
        request[12] = 0x01; // Source TSAP low
        request[13] = 0x00; // Destination TSAP high
        request[14] = 0x01; // Destination TSAP low
        request[15] = 0x00; // User data length
        request[16] = 0x04; // S7 header length
        request[17] = 0x00; // S7 protocol ID
        request[18] = 0x11; // S7 setup communication
        request[19] = 0x00; // Reserved
        request[20] = 0x00; // Reserved
        outputStream.write(request);
        byte[] response = new byte[256];
        int bytesRead = inputStream.read(response);
        // 验证响应
        return bytesRead >= 22 &&
               response[17] == 0x00 &&
               response[18] == 0x0E &&
               response[19] == 0x00;
    }
    private boolean establishS7Connection() throws IOException {
        byte[] request = new byte[48];
        request[0] = 0x03; // Protocol ID
        request[1] = 0x00;
        request[2] = 0x00;
        request[3] = 0x2C; // Length
        request[4] = 0x02; // COTP header length
        request[5] = (byte) 0xF0; // COTP TPDU type: DT
        request[6] = (byte) 0x80; // TPDU number
        request[7] = 0x00; // Parameter code: ISO-COTP
        request[8] = 0x0A; // Parameter length
        request[9] = 0x02; // Protocol version
        request[10] = 0x01; // Reserved
        request[11] = 0x00; // Source TSAP high
        request[12] = 0x01; // Source TSAP low
        request[13] = 0x00; // Destination TSAP high
        request[14] = 0x01; // Destination TSAP low
        request[15] = 0x00; // User data length
        request[16] = 0x12; // S7 header length
        request[17] = 0x02; // S7 protocol ID
        request[18] = (byte) 0xF0; // ROSCTR (Job)
        request[19] = (byte) 0x80; // Reserved
        request[20] = (byte) (jobId >> 8); // Job ID high
        request[21] = (byte) jobId; // Job ID low
        request[22] = 0x00; // Parameter length high
        request[23] = 0x14; // Parameter length low
        request[24] = 0x04; // CPU function: Connect
        request[25] = 0x00; // Reserved
        request[26] = 0x00; // Source rack
        request[27] = 0x00; // Source slot
        request[28] = 0x00; // Destination rack
        request[29] = 0x01; // Destination slot
        request[30] = 0x00; // PDU length high
        request[31] = (byte) pduSize; // PDU length low
        request[32] = 0x00; // Max AMQ call high
        request[33] = 0x01; // Max AMQ call low
        request[34] = 0x00; // Max AMQ confirm high
        request[35] = 0x01; // Max AMQ confirm low
        request[36] = 0x00; // PDU timeout high
        request[37] = 0x00; // PDU timeout medium
        request[38] = 0x00; // PDU timeout low
        request[39] = 0x0A; // S7 version
        request[40] = 0x00; // Data length high
        request[41] = 0x00; // Data length low
        outputStream.write(request);
        byte[] response = new byte[256];
        int bytesRead = inputStream.read(response);
        // 验证响应
        if (bytesRead >= 38 &&
            response[18] == 0xF0 &&  // ROSCTR (Ack_Data)
            response[24] == 0x04 &&  // CPU function: Connect
            response[32] == 0x00) {  // Return code: Success
            pduSize = ((response[34] & 0xFF) << 8) | (response[35] & 0xFF);
            jobId++;
            return true;
        }
        return false;
    }
    private byte[] buildS7ReadRequest(int area, int dbNumber, int startAddress, int size, int wordLen) {
        int requestLength = 44;
        byte[] request = new byte[requestLength];
        request[0] = 0x03; // Protocol ID
        request[1] = 0x00;
        request[2] = 0x00;
        request[3] = (byte) (requestLength - 4); // Length
        request[4] = 0x02; // COTP header length
        request[5] = (byte) 0xF0; // COTP TPDU type: DT
        request[6] = (byte) 0x80; // TPDU number
        request[7] = 0x00; // Parameter code: ISO-COTP
        request[8] = 0x0A; // Parameter length
        request[9] = 0x02; // Protocol version
        request[10] = 0x01; // Reserved
        request[11] = 0x00; // Source TSAP high
        request[12] = 0x01; // Source TSAP low
        request[13] = 0x00; // Destination TSAP high
        request[14] = 0x01; // Destination TSAP low
        request[15] = 0x00; // User data length
        request[16] = 0x12; // S7 header length
        request[17] = 0x02; // S7 protocol ID
        request[18] = (byte) 0xF0; // ROSCTR (Job)
        request[19] = 0x00; // Reserved
        request[20] = (byte) (jobId >> 8); // Job ID high
        request[21] = (byte) jobId; // Job ID low
        request[22] = 0x00; // Parameter length high
        request[23] = 0x0E; // Parameter length low
        request[24] = 0x04; // CPU function: Read Var
        request[25] = 0x01; // Item count
        request[26] = 0x12; // Item specification length
        request[27] = 0x0A; // Syntax ID: S7ANY
        request[28] = (byte) wordLen; // Variable Type (Byte/Word/DWord)
        request[29] = 0x01; // Transport size (1 = bit, 2 = byte, 4 = word, 8 = dword)
        request[30] = 0x00; // Transport size high
        request[31] = (byte) (size & 0xFF); // Number of items
        request[32] = (byte) ((size >> 8) & 0xFF); // Number of items high
        request[33] = 0x10; // DB specification
        request[34] = (byte) ((dbNumber >> 8) & 0xFF); // DB number high
        request[35] = (byte) (dbNumber & 0xFF); // DB number low
        request[36] = (byte) area; // Area
        request[37] = (byte) ((startAddress >> 16) & 0xFF); // Address high
        request[38] = (byte) ((startAddress >> 8) & 0xFF); // Address medium
        request[39] = (byte) (startAddress & 0xFF); // Address low
        request[40] = 0x00; // Data length high
        request[41] = 0x00; // Data length low
        jobId++;
        return request;
    }
    private byte[] buildS7WriteRequest(int area, int dbNumber, int startAddress, byte[] data, int wordLen) {
        int dataLength = data.length;
        int requestLength = 44 + dataLength;
        byte[] request = new byte[requestLength];
        request[0] = 0x03; // Protocol ID
        request[1] = 0x00;
        request[2] = 0x00;
        request[3] = (byte) (requestLength - 4); // Length
        request[4] = 0x02; // COTP header length
        request[5] = (byte) 0xF0; // COTP TPDU type: DT
        request[6] = (byte) 0x80; // TPDU number
        request[7] = 0x00; // Parameter code: ISO-COTP
        request[8] = 0x0A; // Parameter length
        request[9] = 0x02; // Protocol version
        request[10] = 0x01; // Reserved
        request[11] = 0x00; // Source TSAP high
        request[12] = 0x01; // Source TSAP low
        request[13] = 0x00; // Destination TSAP high
        request[14] = 0x01; // Destination TSAP low
        request[15] = 0x00; // User data length
        request[16] = 0x12; // S7 header length
        request[17] = 0x02; // S7 protocol ID
        request[18] = (byte) 0xF0; // ROSCTR (Job)
        request[19] = 0x00; // Reserved
        request[20] = (byte) (jobId >> 8); // Job ID high
        request[21] = (byte) jobId; // Job ID low
        request[22] = 0x00; // Parameter length high
        request[23] = 0x0E; // Parameter length low
        request[24] = 0x05; // CPU function: Write Var
        request[25] = 0x01; // Item count
        request[26] = 0x12; // Item specification length
        request[27] = 0x0A; // Syntax ID: S7ANY
        request[28] = (byte) wordLen; // Variable Type (Byte/Word/DWord)
        request[29] = 0x01; // Transport size (1 = bit, 2 = byte, 4 = word, 8 = dword)
        request[30] = 0x00; // Transport size high
        request[31] = (byte) (dataLength & 0xFF); // Number of items
        request[32] = (byte) ((dataLength >> 8) & 0xFF); // Number of items high
        request[33] = 0x10; // DB specification
        request[34] = (byte) ((dbNumber >> 8) & 0xFF); // DB number high
        request[35] = (byte) (dbNumber & 0xFF); // DB number low
        request[36] = (byte) area; // Area
        request[37] = (byte) ((startAddress >> 16) & 0xFF); // Address high
        request[38] = (byte) ((startAddress >> 8) & 0xFF); // Address medium
        request[39] = (byte) (startAddress & 0xFF); // Address low
        request[40] = 0x00; // Data length high
        request[41] = (byte) (dataLength + 2); // Data length low
        request[42] = 0x04; // Return code: 0x04 = Success
        request[43] = (byte) dataLength; // Data length
        // 复制数据
        System.arraycopy(data, 0, request, 44, dataLength);
        jobId++;
        return request;
    }
    private byte[] sendS7Request(byte[] request) throws IOException {
        if (!isConnected()) {
            connect();
        }
        // 发送请求
        outputStream.write(request);
        // 接收响应
        byte[] header = new byte[4];
        int bytesRead = 0;
        // 读取头部
        while (bytesRead < 4) {
            int count = inputStream.read(header, bytesRead, 4 - bytesRead);
            if (count == -1) {
                throw new IOException("Connection closed while reading response header");
            }
            bytesRead += count;
        }
        int length = ((header[2] & 0xFF) << 8) | (header[3] & 0xFF);
        byte[] response = new byte[length + 4];
        // 复制头部
        System.arraycopy(header, 0, response, 0, 4);
        // 读取剩余部分
        bytesRead = 0;
        while (bytesRead < length) {
            int count = inputStream.read(response, 4 + bytesRead, length - bytesRead);
            if (count == -1) {
                throw new IOException("Connection closed while reading response body");
            }
            bytesRead += count;
        }
        // 检查Job ID
        int responseJobId = ((response[20] & 0xFF) << 8) | (response[21] & 0xFF);
        if (responseJobId != (jobId - 1)) {
            throw new IOException("Job ID mismatch in response");
        }
        return response;
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/s7/S7ClientOld.java
New file
@@ -0,0 +1,185 @@
package com.mes.connect.s7;
import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
import com.mes.connect.IndustrialInterface.AddressParser;
import com.mes.connect.IndustrialInterface.IndustrialClient;
import com.mes.connect.addressParser.S7AddressParser;
import com.mes.connect.addressParser.S7OldAddressParser;
import com.mes.connect.protocol.ProtocolAddress;
import lombok.extern.slf4j.Slf4j;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Random;
import java.util.logging.Logger;
/**
 * S7协议客户端实现
 */
@Slf4j
public class S7ClientOld implements IndustrialClient {
    private static final Logger logger = Logger.getLogger(S7ClientOld.class.getName());
    private final String host;
    private final int port;
    private final int rack;
    private final int slot;
    private boolean connected;
    private S7PLC s7PLC;
    private final AddressParser addressParser = new S7OldAddressParser();
    private EPlcType ePlcType;
    public S7ClientOld(String plcType,String host, int port, int rack, int slot) {
        this.host = host;
        this.port = port;
        this.rack = rack;
        this.slot = slot;
        switch (plcType) {
            case "S200_SMART":
                ePlcType=EPlcType.S200_SMART;
                break;
            case "S200":
                ePlcType=EPlcType.S200;
                break;
            case "S300":
                ePlcType=EPlcType.S300;
                break;
            case "S400":
                ePlcType=EPlcType.S400;
                break;
            case "S1200":
                ePlcType=EPlcType.S1200;
                break;
            case "S1500":
                ePlcType=EPlcType.S1500;
                break;
            default:
                throw new IllegalArgumentException("无效的西门子PLC类型: " + plcType);
        }
    }
    @Override
    public synchronized void connect() throws IOException {
        if (!connected) {
            this.s7PLC = new S7PLC(this.ePlcType, this.host, port, rack, slot);
            connected = true;
            logger.info("Connected to S7 server: " + host + ":" + port);
        }
    }
    @Override
    public synchronized void disconnect() {
        if (connected) {
            this.s7PLC.close();
        }
    }
    @Override
    public boolean isConnected() {
        return this.connected;
    }
    @Override
    public boolean readBit(String address) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int dbNumber = parsedAddress.getDbNumber();
        int area = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        int bit = parsedAddress.getBit();
        return  this.s7PLC.readBoolean(getAddress(parsedAddress));
    }
    @Override
    public void writeBit(String address, boolean value) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int dbNumber = parsedAddress.getDbNumber();
        int area = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        int bit = parsedAddress.getBit();
        this.s7PLC.writeBoolean(getAddress(parsedAddress),value);
    }
    @Override
    public int readRegister(String address) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        return this.s7PLC.readUInt16(getAddress(parsedAddress));
    }
    @Override
    public void writeRegister(String address, int value) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        this.s7PLC.writeUInt16(getAddress(parsedAddress),value);
    }
    @Override
    public int[] readRegisters(String address, int quantity) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int dbNumber = parsedAddress.getDbNumber();
        int area = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        // 计算需要读取的字节数 (每个UInt16占用2字节)
        int byteCount = quantity * 2;
        // 读取字节数组
        byte[] bytes = this.s7PLC.readByte(getAddress(parsedAddress), byteCount);
        // 将字节转换为无符号整数数组
        int[] result = new int[quantity];
        for (int i = 0; i < quantity; i++) {
            int index = i * 2;
            // 组合两个字节为一个无符号16位整数
            result[i] = ((bytes[index] & 0xFF) << 8) | (bytes[index + 1] & 0xFF);
        }
        return result;
    }
    @Override
    public void writeRegisters(String address, int[] values) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        int dbNumber = parsedAddress.getDbNumber();
        int area = parsedAddress.getFunctionCode();
        int startAddress = parsedAddress.getAddress();
        // 转换整数数组为字节数组
        byte[] bytes = new byte[values.length * 2];
        for (int i = 0; i < values.length; i++) {
            int index = i * 2;
            // 将整数拆分为两个字节
            bytes[index] = (byte) ((values[i] >> 8) & 0xFF);
            bytes[index + 1] = (byte) (values[i] & 0xFF);
        }
        this.s7PLC.writeByte(getAddress(parsedAddress),bytes);
    }
    @Override
    public float readFloat(String address) throws IOException {
        int[] registers = readRegisters(address, 2);
        int intBits = (registers[0] << 16) | registers[1];
        return Float.intBitsToFloat(intBits);
    }
    @Override
    public void writeFloat(String address, float value) throws IOException {
        int intBits = Float.floatToIntBits(value);
        int highWord = (intBits >> 16) & 0xFFFF;
        int lowWord = intBits & 0xFFFF;
        writeRegisters(address, new int[]{highWord, lowWord});
    }
    @Override
    public String readString(String address, int length) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        return this.s7PLC.readString(getAddress(parsedAddress));
    }
    @Override
    public void writeString(String address, String value) throws IOException {
        ProtocolAddress parsedAddress = addressParser.parse(address);
        this.s7PLC.writeString(getAddress(parsedAddress),value);
    }
    @Override
    public void close() throws IOException {
        disconnect();
    }
    private String getAddress(ProtocolAddress parsedAddress){
        return "DB"+parsedAddress.getDbNumber()+"."+parsedAddress.getAddress();
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/connect/s7/S7Server.java
New file
@@ -0,0 +1,434 @@
package com.mes.connect.s7;
import com.mes.connect.IndustrialInterface.AddressParser;
import com.mes.connect.IndustrialInterface.IndustrialDataHandler;
import com.mes.connect.IndustrialInterface.IndustrialServer;
import com.mes.connect.addressParser.S7AddressParser;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Logger;
/**
 * S7协议服务器实现(简化版)
 */
public class S7Server implements IndustrialServer {
    private static final Logger logger = Logger.getLogger(S7Server.class.getName());
    private ServerSocket serverSocket;
    private Thread serverThread;
    private boolean running;
    private IndustrialDataHandler handler;
    private final int port;
    private final ExecutorService threadPool = Executors.newFixedThreadPool(10);
    private final AddressParser addressParser = new S7AddressParser();
    public S7Server(int port) {
        this.port = port;
    }
    @Override
    public synchronized void start() throws IOException {
        if (!running) {
            serverSocket = new ServerSocket(port);
            serverThread = new Thread(this::serverLoop);
            serverThread.setDaemon(true);
            serverThread.start();
            running = true;
            logger.info("S7 server started on port " + port);
        }
    }
    @Override
    public synchronized void stop() {
        if (running) {
            running = false;
            try {
                if (serverSocket != null) {
                    serverSocket.close();
                }
                if (serverThread != null) {
                    serverThread.interrupt();
                    serverThread.join(1000);
                }
                threadPool.shutdownNow();
            } catch (IOException | InterruptedException e) {
                logger.warning("Error stopping S7 server: " + e.getMessage());
            } finally {
                serverSocket = null;
                serverThread = null;
                logger.info("S7 server stopped");
            }
        }
    }
    @Override
    public boolean isRunning() {
        return running;
    }
    @Override
    public void setDataHandler(IndustrialDataHandler handler) {
        this.handler = handler;
    }
    @Override
    public void close() throws IOException {
        stop();
    }
    private void serverLoop() {
        while (running) {
            try {
                Socket clientSocket = serverSocket.accept();
                threadPool.submit(() -> handleClient(clientSocket));
            } catch (IOException e) {
                if (running) {
                    logger.warning("Error accepting client connection: " + e.getMessage());
                }
            }
        }
    }
    private void handleClient(Socket clientSocket) {
        try (DataInputStream input = new DataInputStream(clientSocket.getInputStream());
             DataOutputStream output = new DataOutputStream(clientSocket.getOutputStream())) {
            // S7通信流程:COTP连接建立 -> ISO连接建立 -> S7协议数据交换
            // 1. 处理COTP连接请求
            if (!handleCotpConnection(input, output)) {
                return;
            }
            // 2. 处理ISO连接请求
            if (!handleIsoConnection(input, output)) {
                return;
            }
            // 3. 处理S7协议数据
            handleS7Protocol(input, output);
        } catch (IOException e) {
            logger.warning("Error handling client: " + e.getMessage());
        }
    }
    private boolean handleCotpConnection(DataInputStream input, DataOutputStream output) throws IOException {
        // 读取COTP连接请求
        byte[] buffer = new byte[256];
        int bytesRead = input.read(buffer);
        // 简单验证COTP连接请求
        if (bytesRead < 6 || buffer[0] != 0x02 || buffer[1] != 0xF0 || buffer[2] != 0x80) {
            logger.warning("Invalid COTP connection request");
            return false;
        }
        // 构建COTP连接确认
        byte[] response = new byte[6];
        response[0] = 0x02; // Length
        response[1] = (byte) 0xF0; // COTP TPDU type: DT
        response[2] = (byte) 0xD0; // TPDU number
        response[3] = 0x00; // Parameters
        response[4] = 0x00;
        response[5] = 0x00;
        output.write(response);
        return true;
    }
    private boolean handleIsoConnection(DataInputStream input, DataOutputStream output) throws IOException {
        // 读取ISO连接请求
        byte[] buffer = new byte[256];
        int bytesRead = input.read(buffer);
        // 简单验证ISO连接请求
        if (bytesRead < 10 || buffer[0] != 0x03 || buffer[1] != 0x00) {
            logger.warning("Invalid ISO connection request");
            return false;
        }
        // 构建ISO连接确认
        byte[] response = new byte[10];
        response[0] = 0x03; // Protocol ID
        response[1] = 0x00;
        response[2] = 0x00;
        response[3] = 0x0A; // Length
        response[4] = 0x02; // COTP header length
        response[5] = (byte) 0xF0; // COTP TPDU type: CC
        response[6] = (byte) 0x81; // Parameters
        response[7] = 0x00;
        response[8] = 0x00;
        response[9] = 0x00;
        output.write(response);
        return true;
    }
    private void handleS7Protocol(DataInputStream input, DataOutputStream output) throws IOException {
        byte[] buffer = new byte[1024];
        while (true) {
            int bytesRead = input.read(buffer);
            if (bytesRead <= 0) {
                break;
            }
            // 解析S7请求
            byte[] response = processS7Request(buffer, bytesRead);
            if (response != null) {
                output.write(response);
            }
        }
    }
    private byte[] processS7Request(byte[] request, int length) {
        // 解析S7请求PDU
        int protocolId = request[0] & 0xFF;
        int rosctr = request[1] & 0xFF; // 1 = Job, 3 = Ack_Data
        if (protocolId != 0x32 || rosctr != 1) {
            logger.warning("Unsupported S7 request type");
            return null;
        }
        int function = request[12] & 0xFF;
        try {
            switch (function) {
                case 0x04: // 读请求
                    return handleS7ReadRequest(request, length);
                case 0x05: // 写请求
                    return handleS7WriteRequest(request, length);
                default:
                    logger.warning("Unsupported S7 function: " + function);
                    return buildS7ErrorResponse(request, 0x01); // 功能不支持
            }
        } catch (Exception e) {
            logger.warning("Error processing S7 request: " + e.getMessage());
            return buildS7ErrorResponse(request, 0x03); // 处理错误
        }
    }
    private byte[] handleS7ReadRequest(byte[] request, int length) {
        // 解析请求参数
        int itemCount = request[22] & 0xFF;
        // 构建响应
        int responseLength = 24 + itemCount * 12;
        byte[] response = new byte[responseLength];
        // 复制通用头部
        System.arraycopy(request, 0, response, 0, 12);
        // 设置响应特定字段
        response[1] = 0x03; // ROSCTR = Ack_Data
        response[10] = 0x00; // 参数长度
        response[11] = 0x00;
        response[12] = 0x04; // 功能码:读
        // 设置数据部分
        response[13] = 0x00; // 数据长度高字节
        response[14] = (byte) (responseLength - 16); // 数据长度低字节
        response[15] = 0x00; // 返回代码:成功
        // 处理每个读取项
        int offset = 16;
        for (int i = 0; i < itemCount; i++) {
            int area = request[offset + 2] & 0xFF;
            int dbNumber = ((request[offset + 3] & 0xFF) << 8) | (request[offset + 4] & 0xFF);
            int wordLen = request[offset + 5] & 0xFF;
            int startAddress = ((request[offset + 6] & 0xFF) << 16) |
                              ((request[offset + 7] & 0xFF) << 8) |
                               (request[offset + 8] & 0xFF);
            int count = ((request[offset + 9] & 0xFF) << 8) | (request[offset + 10] & 0xFF);
            // 构建地址字符串
            String addressStr;
            if (area == 0x84) { // DB
                addressStr = String.format("S7.DB%d.DBW%d", dbNumber, startAddress);
            } else if (area == 0x81) { // 输入
                addressStr = String.format("S7.I%d", startAddress);
            } else if (area == 0x82) { // 输出
                addressStr = String.format("S7.Q%d", startAddress);
            } else if (area == 0x83) { // 内存
                addressStr = String.format("S7.M%d", startAddress);
            } else {
                response[offset] = (byte) 0x81; // 返回代码:参数错误
                response[offset + 1] = 0x00;
                response[offset + 2] = 0x00;
                offset += 3;
                continue;
            }
            // 根据数据类型处理读取
            if (wordLen == 0x04) { // 字节
                response[offset] = 0x00; // 返回代码:成功
                response[offset + 1] = 0x01; // 变量规范长度
                response[offset + 2] = 0x04; // 数据类型:字节
                response[offset + 3] = (byte) count; // 数据长度
                for (int j = 0; j < count; j++) {
                    String byteAddress = String.format("%s.%d", addressStr, j);
                    int value = handler.handleReadRegister(byteAddress) & 0xFF;
                    response[offset + 4 + j] = (byte) value;
                }
                offset += 4 + count;
            } else if (wordLen == 0x06) { // 字
                response[offset] = 0x00; // 返回代码:成功
                response[offset + 1] = 0x01; // 变量规范长度
                response[offset + 2] = 0x06; // 数据类型:字
                response[offset + 3] = (byte) (count * 2); // 数据长度
                for (int j = 0; j < count; j++) {
                    String wordAddress = String.format("%s.%d", addressStr, j);
                    int value = handler.handleReadRegister(wordAddress);
                    response[offset + 4 + j * 2] = (byte) (value >> 8);
                    response[offset + 5 + j * 2] = (byte) value;
                }
                offset += 4 + count * 2;
            } else if (wordLen == 0x08) { // 双字
                response[offset] = 0x00; // 返回代码:成功
                response[offset + 1] = 0x01; // 变量规范长度
                response[offset + 2] = 0x08; // 数据类型:双字
                response[offset + 3] = (byte) (count * 4); // 数据长度
                for (int j = 0; j < count; j++) {
                    String dwordAddress = String.format("%s.%d", addressStr, j);
                    int value = handler.handleReadRegister(dwordAddress);
                    response[offset + 4 + j * 4] = (byte) (value >> 24);
                    response[offset + 5 + j * 4] = (byte) (value >> 16);
                    response[offset + 6 + j * 4] = (byte) (value >> 8);
                    response[offset + 7 + j * 4] = (byte) value;
                }
                offset += 4 + count * 4;
            } else {
                response[offset] = (byte) 0x81; // 返回代码:参数错误
                response[offset + 1] = 0x00;
                response[offset + 2] = 0x00;
                offset += 3;
            }
        }
        return response;
    }
    private byte[] handleS7WriteRequest(byte[] request, int length) {
        // 解析请求参数
        int itemCount = request[22] & 0xFF;
        // 构建响应
        byte[] response = new byte[24 + itemCount * 3];
        // 复制通用头部
        System.arraycopy(request, 0, response, 0, 12);
        // 设置响应特定字段
        response[1] = 0x03; // ROSCTR = Ack_Data
        response[10] = 0x00; // 参数长度
        response[11] = 0x00;
        response[12] = 0x05; // 功能码:写
        // 设置数据部分
        response[13] = 0x00; // 数据长度高字节
        response[14] = (byte) (itemCount * 3); // 数据长度低字节
        // 处理每个写入项
        int offset = 16;
        for (int i = 0; i < itemCount; i++) {
            int area = request[offset + 2] & 0xFF;
            int dbNumber = ((request[offset + 3] & 0xFF) << 8) | (request[offset + 4] & 0xFF);
            int wordLen = request[offset + 5] & 0xFF;
            int startAddress = ((request[offset + 6] & 0xFF) << 16) |
                              ((request[offset + 7] & 0xFF) << 8) |
                               (request[offset + 8] & 0xFF);
            int count = ((request[offset + 9] & 0xFF) << 8) | (request[offset + 10] & 0xFF);
            int dataLength = request[offset + 11] & 0xFF;
            // 构建地址字符串
            String addressStr;
            if (area == 0x84) { // DB
                addressStr = String.format("S7.DB%d.DBW%d", dbNumber, startAddress);
            } else if (area == 0x81) { // 输入
                addressStr = String.format("S7.I%d", startAddress);
            } else if (area == 0x82) { // 输出
                addressStr = String.format("S7.Q%d", startAddress);
            } else if (area == 0x83) { // 内存
                addressStr = String.format("S7.M%d", startAddress);
            } else {
                response[offset] = (byte) 0x81; // 返回代码:参数错误
                offset += 3;
                continue;
            }
            // 根据数据类型处理写入
            if (wordLen == 0x04) { // 字节
                int[] values = new int[count];
                for (int j = 0; j < count; j++) {
                    values[j] = request[offset + 12 + j] & 0xFF;
                    String byteAddress = String.format("%s.%d", addressStr, j);
                    handler.handleWriteRegister(byteAddress, values[j]);
                }
                response[offset] = 0x00; // 返回代码:成功
                offset += 3;
            } else if (wordLen == 0x06) { // 字
                int[] values = new int[count];
                for (int j = 0; j < count; j++) {
                    values[j] = ((request[offset + 12 + j * 2] & 0xFF) << 8) |
                                (request[offset + 13 + j * 2] & 0xFF);
                    String wordAddress = String.format("%s.%d", addressStr, j);
                    handler.handleWriteRegister(wordAddress, values[j]);
                }
                response[offset] = 0x00; // 返回代码:成功
                offset += 3;
            } else if (wordLen == 0x08) { // 双字
                for (int j = 0; j < count; j++) {
                    int value = ((request[offset + 12 + j * 4] & 0xFF) << 24) |
                               ((request[offset + 13 + j * 4] & 0xFF) << 16) |
                               ((request[offset + 14 + j * 4] & 0xFF) << 8) |
                                (request[offset + 15 + j * 4] & 0xFF);
                    String dwordAddress = String.format("%s.%d", addressStr, j);
                    handler.handleWriteRegister(dwordAddress, value);
                }
                response[offset] = 0x00; // 返回代码:成功
                offset += 3;
            } else {
                response[offset] = (byte) 0x81; // 返回代码:参数错误
                offset += 3;
            }
        }
        return response;
    }
    private byte[] buildS7ErrorResponse(byte[] request, int errorCode) {
        byte[] response = new byte[24];
        // 复制通用头部
        System.arraycopy(request, 0, response, 0, 12);
        // 设置响应特定字段
        response[1] = 0x03; // ROSCTR = Ack_Data
        response[10] = 0x00; // 参数长度
        response[11] = 0x00;
        response[12] = request[12]; // 功能码
        // 设置数据部分
        response[13] = 0x00; // 数据长度高字节
        response[14] = 0x03; // 数据长度低字节
        response[15] = (byte) errorCode; // 返回代码
        return response;
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/controller/AccountController.java
New file
@@ -0,0 +1,37 @@
package com.mes.model.controller;
import com.mes.model.service.AccountService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.mes.utils.Result;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
 * <p>
 * 账户表 前端控制器
 * </p>
 *
 * @author wu
 * @since 2024-08-28
 */
@Api(tags = "账户")
@RestController
@RequestMapping("/account")
public class AccountController {
    @Autowired
    AccountService accountService;
    @ApiOperation("httpAPi测试")
    @PostMapping("/testApi")
    @ResponseBody
    public Result testApi (@RequestBody Map<String, Object> arguments) {
        String str[]={"123","456"};
        return Result.build(200,"连接成功",str);
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/entity/Account.java
New file
@@ -0,0 +1,51 @@
package com.mes.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
 * <p>
 * 账户表
 * </p>
 *
 * @author wu
 * @since 2024-08-28
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class Account implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 账户表主键
     */
      @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * 用户名称
     */
    private String userName;
    /**
     * 角色id
     */
    private Long roleId;
    /**
     * 账户
     */
    private String account;
    /**
     * 密码
     */
    private String password;
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/entity/Machine.java
New file
@@ -0,0 +1,74 @@
package com.mes.model.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.mes.model.mapper.MachineMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.Serializable;
/**
 * <p>
 * 账户表
 * </p>
 *
 * @author wu
 * @since 2024-08-28
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class Machine implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 账户表主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * 设备名称
     */
    private String name;
    /**
     * 协议类型ID
     */
    // 可以直接添加关联对象
    @TableField(exist = false, fill = FieldFill.INSERT_UPDATE)
    private ProtocolType protocolType;
    private Long protocolTypeId;
    /**
     * PLC类型
     */
    @TableField(exist = false)
    private PlcType plcType;
    private String plcTypeId;
    /**
     * ip
     */
    private String ip;
    /**
     * 端口
     */
    private int port;
    /**
     * 端口
     */
    private String machineFile;
    /**
     * 端口
     */
    private String logicFile;
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/entity/PlcType.java
New file
@@ -0,0 +1,41 @@
package com.mes.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
 * <p>
 * plc型号表
 * </p>
 *
 * @author yzx
 * @since 2025-06-13
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class PlcType implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 账户表主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * 设备名称
     */
    private String name;
    /**
     * 备注
     */
    private String remarks;
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/entity/ProtocolType.java
New file
@@ -0,0 +1,41 @@
package com.mes.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
 * <p>
 * 协议类型表
 * </p>
 *
 * @author yzx
 * @since 2025-06-13
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class ProtocolType implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * 协议名称
     */
    private String name;
    /**
     * 备注
     */
    private String remarks;
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/AccountMapper.java
New file
@@ -0,0 +1,16 @@
package com.mes.model.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.mes.model.entity.Account;
/**
 * <p>
 * 账户表 Mapper 接口
 * </p>
 *
 * @author wu
 * @since 2024-08-28
 */
public interface AccountMapper extends MPJBaseMapper<Account> {
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/MachineMapper.java
New file
@@ -0,0 +1,24 @@
package com.mes.model.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.mes.model.entity.Account;
import com.mes.model.entity.Machine;
import com.mes.model.entity.ProtocolType;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
 * <p>
 * 账户表 Mapper 接口
 * </p>
 *
 * @author wu
 * @since 2024-08-28
 */
@Mapper
public interface MachineMapper extends MPJBaseMapper<Machine> {
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/PlcTypeMapper.java
New file
@@ -0,0 +1,16 @@
package com.mes.model.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.mes.model.entity.PlcType;
/**
 * <p>
 * 账户表 Mapper 接口
 * </p>
 *
 * @author wu
 * @since 2024-08-28
 */
public interface PlcTypeMapper extends MPJBaseMapper<PlcType> {
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/ProtocolTypeMapper.java
New file
@@ -0,0 +1,16 @@
package com.mes.model.mapper;
import com.github.yulichang.base.MPJBaseMapper;
import com.mes.model.entity.ProtocolType;
/**
 * <p>
 * 账户表 Mapper 接口
 * </p>
 *
 * @author wu
 * @since 2024-08-28
 */
public interface ProtocolTypeMapper extends MPJBaseMapper<ProtocolType> {
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/xml/AccountMapper.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mes.model.mapper.AccountMapper">
</mapper>
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/xml/MachineMapper.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mes.model.mapper.MachineMapper">
</mapper>
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/xml/PlcTypeMapper.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mes.model.mapper.PlcTypeMapper">
</mapper>
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/mapper/xml/ProtocolTypeMapper.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mes.model.mapper.ProtocolTypeMapper">
</mapper>
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/AccountService.java
New file
@@ -0,0 +1,16 @@
package com.mes.model.service;
import com.github.yulichang.base.MPJBaseService;
import com.mes.model.entity.Account;
/**
 * <p>
 * 账户表 服务类
 * </p>
 *
 * @author wu
 * @since 2024-08-28
 */
public interface AccountService extends MPJBaseService<Account> {
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/MachineService.java
New file
@@ -0,0 +1,19 @@
package com.mes.model.service;
import com.github.yulichang.base.MPJBaseService;
import com.mes.model.entity.Account;
import com.mes.model.entity.Machine;
import java.util.List;
/**
 * <p>
 * 账户表 服务类
 * </p>
 *
 * @author wu
 * @since 2024-08-28
 */
public interface MachineService extends MPJBaseService<Machine> {
    List<Machine> getMachineConfig();
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/PlcTypeService.java
New file
@@ -0,0 +1,16 @@
package com.mes.model.service;
import com.github.yulichang.base.MPJBaseService;
import com.mes.model.entity.PlcType;
/**
 * <p>
 * 账户表 服务类
 * </p>
 *
 * @author wu
 * @since 2024-08-28
 */
public interface PlcTypeService extends MPJBaseService<PlcType> {
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/ProtocolTypeService.java
New file
@@ -0,0 +1,17 @@
package com.mes.model.service;
import com.github.yulichang.base.MPJBaseService;
import com.mes.model.entity.Account;
import com.mes.model.entity.ProtocolType;
/**
 * <p>
 * 账户表 服务类
 * </p>
 *
 * @author wu
 * @since 2024-08-28
 */
public interface ProtocolTypeService extends MPJBaseService<ProtocolType> {
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/impl/AccountServiceImpl.java
New file
@@ -0,0 +1,23 @@
package com.mes.model.service.impl;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.mes.model.entity.Account;
import com.mes.model.mapper.AccountMapper;
import com.mes.model.service.AccountService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
 * <p>
 * 账户表 服务实现类
 * </p>
 *
 * @author yanzhixin
 * @since 2024-09-03
 */
@Slf4j
@Service
public class AccountServiceImpl extends MPJBaseServiceImpl<AccountMapper, Account> implements AccountService {
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/impl/MachineServiceImpl.java
New file
@@ -0,0 +1,50 @@
package com.mes.model.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.mes.model.entity.Account;
import com.mes.model.entity.Machine;
import com.mes.model.entity.PlcType;
import com.mes.model.entity.ProtocolType;
import com.mes.model.mapper.AccountMapper;
import com.mes.model.mapper.MachineMapper;
import com.mes.model.mapper.PlcTypeMapper;
import com.mes.model.mapper.ProtocolTypeMapper;
import com.mes.model.service.AccountService;
import com.mes.model.service.MachineService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
 * <p>
 * 账户表 服务实现类
 * </p>
 *
 * @author yanzhixin
 * @since 2024-09-03
 */
@Slf4j
@Service
public class MachineServiceImpl extends MPJBaseServiceImpl<MachineMapper, Machine> implements MachineService {
    @Autowired
    private PlcTypeMapper plcTypeMapper;
    @Autowired
    private ProtocolTypeMapper protocolTypeMapper;
    public List<Machine> getMachineConfig() {
        List<Machine> machineConfig = baseMapper.selectList(null);
        for (int i=0;i<machineConfig.size();i++) {
            PlcType plcType=plcTypeMapper.selectOne(new QueryWrapper<PlcType>().lambda()
                    .eq(PlcType::getId,machineConfig.get(i).getPlcTypeId()));
            ProtocolType protocolType=protocolTypeMapper.selectOne(new QueryWrapper<ProtocolType>().lambda()
                    .eq(ProtocolType::getId,machineConfig.get(i).getProtocolTypeId()));
            machineConfig.get(i).setPlcType(plcType);
            machineConfig.get(i).setProtocolType(protocolType);
        }
        return machineConfig;
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/impl/PlcTypeServiceImpl.java
New file
@@ -0,0 +1,26 @@
package com.mes.model.service.impl;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.mes.model.entity.Machine;
import com.mes.model.entity.PlcType;
import com.mes.model.mapper.MachineMapper;
import com.mes.model.mapper.PlcTypeMapper;
import com.mes.model.service.MachineService;
import com.mes.model.service.PlcTypeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
 * <p>
 * 账户表 服务实现类
 * </p>
 *
 * @author yanzhixin
 * @since 2024-09-03
 */
@Slf4j
@Service
public class PlcTypeServiceImpl extends MPJBaseServiceImpl<PlcTypeMapper, PlcType> implements PlcTypeService {
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/model/service/impl/ProtocolTypeServiceImpl.java
New file
@@ -0,0 +1,23 @@
package com.mes.model.service.impl;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.mes.model.entity.ProtocolType;
import com.mes.model.mapper.ProtocolTypeMapper;
import com.mes.model.service.ProtocolTypeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
 * <p>
 * 账户表 服务实现类
 * </p>
 *
 * @author yanzhixin
 * @since 2024-09-03
 */
@Slf4j
@Service
public class ProtocolTypeServiceImpl extends MPJBaseServiceImpl<ProtocolTypeMapper, ProtocolType> implements ProtocolTypeService {
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/java/com/mes/plcConnectModuleApplication.java
New file
@@ -0,0 +1,33 @@
package com.mes;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
 * @Author : zhoush
 * @Date: 2024/3/25 10:49
 * @Description:
 */
@Slf4j
@SpringBootApplication
@MapperScan("com.mes.*.mapper")
@EnableDiscoveryClient
@EnableSwagger2
@EnableScheduling
@EnableAsync
public class plcConnectModuleApplication {
    public static void main(String[] args) {
        try {
            SpringApplication.run(plcConnectModuleApplication.class, args);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/main.iml
New file
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$/java" isTestSource="false" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
    <orderEntry type="library" name="servicebase-1.0-SNAPSHOT" level="project" />
    <orderEntry type="module" module-name="UnLoadGlassModule" />
    <orderEntry type="module" module-name="servicebase1" />
  </component>
</module>
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/loadLogic.json
New file
@@ -0,0 +1,165 @@
{
  "logics": [
    {
      "name":"请求逻辑",
      "sequence":"1",
      "connectType":"View",
      "connectAddress": "viewname",
      "logic":[
        {
          "codeId": "plcRequest",
          "address": "MB.4x0001",
          "value": [1],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesSend",
          "address": "MB.4x0010",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesSend",
          "address": "MB.4x0010",
          "fixed": true,
          "value": 1,
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "width",
          "address": "MB.4x0011",
          "fixed": false,
          "value": 1,
          "plcDataType": "int",
          "length": 2
        }
      ,
        {
          "codeId": "height",
          "address": "MB.4x0012",
          "fixed": false,
          "value": 2,
          "plcDataType": "int",
          "length": 2
        }
      ]
    },
    {
      "name":"请求清空",
      "sequence":"2",
      "connectType":"View",
      "connectAddress": "viewname",
      "logic":[
        {
          "codeId": "plcRequest",
          "address": "MB.4x0001",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesSend",
          "address": "MB.4x0010",
          "value": [1],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesSend",
          "address": "MB.4x0010",
          "fixed": true,
          "value": 0,
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "width",
          "address": "MB.4x0011",
          "fixed": true,
          "value": 0,
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "height",
          "address": "MB.4x0012",
          "fixed": true,
          "value": 0,
          "plcDataType": "int",
          "length": 2
        }
      ]
    },
    {
      "name":"完成逻辑",
      "sequence":"3",
      "connectType":"View",
      "connectAddress": "viewname",
      "logic":[
        {
          "codeId": "plcComplete",
          "address": "MB.4x0005",
          "value": [1],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesComplete",
          "address": "MB.4x0020",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesComplete",
          "address": "MB.4x0020",
          "fixed": true,
          "value": 1,
          "plcDataType": "int",
          "length": 2
        }
      ]
    },
    {
      "name":"完成清空",
      "sequence":"4",
      "connectType":"View",
      "connectAddress": "viewname",
      "logic":[
        {
          "codeId": "plcComplete",
          "address": "MB.4x0005",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesComplete",
          "address": "MB.4x0020",
          "value": [1,2,3],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesComplete",
          "address": "MB.4x0020",
          "fixed": true,
          "value": 0,
          "plcDataType": "int",
          "length": 2
        }
      ]
    }
  ]
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/loadLogic2.json
New file
@@ -0,0 +1,165 @@
{
  "logics": [
    {
      "name":"请求逻辑",
      "sequence":"1",
      "connectType":"Http",
      "connectAddress": "http://localhost:8082/account/testApi",
      "logic":[
        {
          "codeId": "plcRequest",
          "address": "MB.4x0001",
          "value": [1],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesSend",
          "address": "MB.4x0010",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesSend",
          "address": "MB.4x0010",
          "fixed": true,
          "value": 1,
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "width",
          "address": "MB.4x0011",
          "fixed": false,
          "value": 1,
          "plcDataType": "int",
          "length": 2
        }
      ,
        {
          "codeId": "height",
          "address": "MB.4x0012",
          "fixed": false,
          "value": 2,
          "plcDataType": "int",
          "length": 2
        }
      ]
    },
    {
      "name":"请求清空",
      "sequence":"2",
      "connectType":"View",
      "connectAddress": "viewname",
      "logic":[
        {
          "codeId": "plcRequest",
          "address": "MB.4x0001",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesSend",
          "address": "MB.4x0010",
          "value": [1],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesSend",
          "address": "MB.4x0010",
          "fixed": true,
          "value": 0,
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "width",
          "address": "MB.4x0011",
          "fixed": true,
          "value": 0,
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "height",
          "address": "MB.4x0012",
          "fixed": true,
          "value": 0,
          "plcDataType": "int",
          "length": 2
        }
      ]
    },
    {
      "name":"完成逻辑",
      "sequence":"3",
      "connectType":"View",
      "connectAddress": "viewname",
      "logic":[
        {
          "codeId": "plcComplete",
          "address": "MB.4x0005",
          "value": [1],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesComplete",
          "address": "MB.4x0020",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesComplete",
          "address": "MB.4x0020",
          "fixed": true,
          "value": 1,
          "plcDataType": "int",
          "length": 2
        }
      ]
    },
    {
      "name":"完成清空",
      "sequence":"4",
      "connectType":"View",
      "connectAddress": "viewname",
      "logic":[
        {
          "codeId": "plcComplete",
          "address": "MB.4x0005",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesComplete",
          "address": "MB.4x0020",
          "value": [1,2,3],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesComplete",
          "address": "MB.4x0020",
          "fixed": true,
          "value": 0,
          "plcDataType": "int",
          "length": 2
        }
      ]
    }
  ]
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/loadLogicS7.json
New file
@@ -0,0 +1,165 @@
{
  "logics": [
    {
      "name":"请求逻辑",
      "sequence":"1",
      "connectType":"View",
      "connectAddress": "viewname",
      "logic":[
        {
          "codeId": "plcRequest",
          "address": "S7.DB8.DBW0",
          "value": [1],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesSend",
          "address": "S7.DB8.DBW20",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesSend",
          "address": "S7.DB8.DBW20",
          "fixed": true,
          "value": 1,
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "width",
          "address": "S7.DB8.DBW22",
          "fixed": false,
          "value": 1,
          "plcDataType": "int",
          "length": 2
        }
      ,
        {
          "codeId": "height",
          "address": "S7.DB8.DBW24",
          "fixed": false,
          "value": 2,
          "plcDataType": "int",
          "length": 2
        }
      ]
    },
    {
      "name":"请求清空",
      "sequence":"2",
      "connectType":"View",
      "connectAddress": "viewname",
      "logic":[
        {
          "codeId": "plcRequest",
          "address": "S7.DB8.DBW0",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesSend",
          "address": "S7.DB8.DBW20",
          "value": [1],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesSend",
          "address": "S7.DB8.DBW20",
          "fixed": true,
          "value": 0,
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "width",
          "address": "S7.DB8.DBW22",
          "fixed": true,
          "value": 0,
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "height",
          "address": "S7.DB8.DBW24",
          "fixed": true,
          "value": 0,
          "plcDataType": "int",
          "length": 2
        }
      ]
    },
    {
      "name":"完成逻辑",
      "sequence":"3",
      "connectType":"View",
      "connectAddress": "viewname",
      "logic":[
        {
          "codeId": "plcComplete",
          "address": "S7.DB8.DBW10",
          "value": [1],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesComplete",
          "address": "S7.DB8.DBW40",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesComplete",
          "address": "S7.DB8.DBW40",
          "fixed": true,
          "value": 1,
          "plcDataType": "int",
          "length": 2
        }
      ]
    },
    {
      "name":"完成清空",
      "sequence":"4",
      "connectType":"View",
      "connectAddress": "viewname",
      "logic":[
        {
          "codeId": "plcComplete",
          "address": "S7.DB8.DBW10",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesComplete",
          "address": "S7.DB8.DBW40",
          "value": [1,2,3],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesComplete",
          "address": "S7.DB8.DBW40",
          "fixed": true,
          "value": 0,
          "plcDataType": "int",
          "length": 2
        }
      ]
    }
  ]
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/logicalRelationship.json
New file
@@ -0,0 +1,17 @@
{
  "请求逻辑":{
    "name":"请求逻辑",
    "connectType":"HTTP",
    "connectAddress": "http://39.105.110.179:5000/Request"
  },
  "请求清空":{
    "name":"请求清空",
    "connectType":"Procedure",
    "connectAddress": "存储过程名称"
  },
  "完成逻辑":{
    "name":"完成逻辑",
    "connectType":"View",
    "connectAddress": "视图名称"
  }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/shelf.json
New file
@@ -0,0 +1,244 @@
{
  "parameters": [
    {
      "serialNumber": 0,
      "content": "PLC请求",
      "codeId": "plcRequest",
      "plcDataType": "Word",
      "fontLocation": 0,
      "length": 2,
      "ratio": 1,
      "scale": 1,
      "address": "MB.4x0001",
      "remarks": ""
    },
    {
      "serialNumber": 1,
      "content": "PLC请求ID",
      "codeId": "plcRequestId",
      "plcDataType": "Word",
      "fontLocation": 2,
      "length": 2,
      "ratio": 2,
      "scale": 2,
      "address":"MB.4x0002",
      "remarks": ""
    },
    {
      "serialNumber": 2,
      "content": "备用_1",
      "codeId": "remarks_1",
      "plcDataType": "Word",
      "fontLocation": 4,
      "length": 2,
      "ratio": 3,
      "scale": 3,
      "address": "MB.4x0003",
      "remarks": ""
    },
    {
      "serialNumber": 3,
      "content": "备用_2",
      "codeId": "remarks_2",
      "plcDataType": "Word",
      "fontLocation": 6,
      "length": 2,
      "ratio": 4,
      "scale": 4,
      "address": "MB.4x0004",
      "remarks": ""
    },
    {
      "serialNumber": 4,
      "content": "PLC完成字",
      "codeId": "plcComplete",
      "plcDataType": "Word",
      "fontLocation": 8,
      "length": 2,
      "ratio": 5,
      "scale": 5,
      "address": "MB.4x0005",
      "remarks": ""
    },
    {
      "serialNumber": 5,
      "content": "备用_4",
      "codeId": "remarks_4",
      "plcDataType": "Word",
      "fontLocation": 10,
      "length": 2,
      "ratio": 6,
      "scale": 6,
      "address": "MB.4x0006",
      "remarks": ""
    },
    {
      "serialNumber": 6,
      "content": "备用_5",
      "codeId": "remarks_5",
      "plcDataType": "Word",
      "fontLocation": 12,
      "length": 2,
      "ratio": 7,
      "scale": 7,
      "address": "MB.4x0007",
      "remarks": ""
    },
    {
      "serialNumber": 7,
      "content": "备用_6",
      "codeId": "remarks_6",
      "plcDataType": "Word",
      "fontLocation": 14,
      "length": 2,
      "ratio": 8,
      "scale": 8,
      "address": "MB.4x0008",
      "remarks": ""
    },
    {
      "serialNumber": 8,
      "content": "备用_7",
      "codeId": "remarks_7",
      "plcDataType": "Word",
      "fontLocation": 16,
      "length": 2,
      "ratio": 9,
      "scale": 9,
      "address": "MB.4x0009",
      "remarks": ""
    },
    {
      "serialNumber": 9,
      "content": "Mes发送字",
      "codeId": "mesSend",
      "plcDataType": "Word",
      "fontLocation": 18,
      "length": 2,
      "ratio": 10,
      "scale": 10,
      "address": "MB.4x0010",
      "remarks": ""
    },
    {
      "serialNumber": 10,
      "content": "MES发送长",
      "codeId": "width",
      "plcDataType": "Word",
      "fontLocation": 20,
      "length": 2,
      "ratio": 11,
      "scale": 11,
      "address": "MB.4x0011",
      "remarks": ""
    },
    {
      "serialNumber": 11,
      "content": "MES发送宽",
      "codeId": "height",
      "plcDataType": "Word",
      "fontLocation": 22,
      "length": 2,
      "ratio": 12,
      "scale": 12,
      "address":"MB.4x0012",
      "remarks": ""
    },
    {
      "serialNumber": 12,
      "content": "G3M7设备状态",
      "codeId": "13",
      "plcDataType": "Word",
      "fontLocation": 24,
      "length": 2,
      "ratio": 13,
      "scale": 13,
      "address": "MB.4x0013",
      "remarks": ""
    },
    {
      "serialNumber": 13,
      "content": "Z12设备状态",
      "codeId": "14",
      "plcDataType": "Word",
      "fontLocation": 26,
      "length": 2,
      "ratio": 14,
      "scale": 14,
      "address": "MB.4x0014",
      "remarks": ""
    },
    {
      "serialNumber": 14,
      "content": "S8设备状态",
      "codeId": "15",
      "plcDataType": "Word",
      "fontLocation": 28,
      "length": 2,
      "ratio": 15,
      "scale": 15,
      "address": "MB.4x0015",
      "remarks": ""
    },
    {
      "serialNumber": 15,
      "content": "W11定位台设备状态",
      "codeId": "16",
      "plcDataType": "Word",
      "fontLocation": 30,
      "length": 2,
      "ratio": 16,
      "scale": 16,
      "address": "MB.4x0016",
      "remarks": ""
    },
    {
      "serialNumber": 16,
      "content": "S9设备状态",
      "codeId": "17",
      "plcDataType": "Word",
      "fontLocation": 32,
      "length": 2,
      "ratio": 17,
      "scale": 17,
      "address": "MB.4x0017",
      "remarks": ""
    },
    {
      "serialNumber": 17,
      "content": "S10设备状态",
      "codeId": "18",
      "plcDataType": "Word",
      "fontLocation": 34,
      "length": 2,
      "ratio": 18,
      "scale": 18,
      "address": "MB.4x0018",
      "remarks": ""
    },
    {
      "serialNumber": 19,
      "content": "S10设备状态",
      "codeId": "19",
      "plcDataType": "Word",
      "fontLocation": 34,
      "length": 2,
      "ratio": 18,
      "scale": 18,
      "address": "MB.4x0018",
      "remarks": ""
    },
    {
      "serialNumber": 20,
      "content": "mes确认完成",
      "codeId": "mesComplete",
      "plcDataType": "Word",
      "fontLocation": 40,
      "length": 2,
      "ratio": 10,
      "scale": 10,
      "address": "MB.4x0020",
      "remarks": ""
    }
  ]
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/shelfLogic.json
New file
@@ -0,0 +1,85 @@
{
  "logics": [
    {
      "name":"请求逻辑",
      "sequence":"1",
      "connectType":"Http",
      "connectAddress": "http://localhost:8082/account/testApi",
      "logic":[
        {
          "codeId": "plcRequest",
          "address": "MB.4x0001",
          "value": [1],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesSend",
          "address": "MB.4x0010",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesSend",
          "address": "MB.4x0010",
          "fixed": true,
          "value": 1,
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "width",
          "address": "MB.4x0011",
          "fixed": false,
          "value": 1,
          "plcDataType": "int",
          "length": 2
        }
      ,
        {
          "codeId": "height",
          "address": "MB.4x0012",
          "fixed": false,
          "value": 2,
          "plcDataType": "int",
          "length": 2
        }
      ]
    },
    {
      "name":"完成逻辑",
      "sequence":"2",
      "connectType":"Procedure",
      "connectAddress": "存储过程名称",
      "logic":[
        {
          "codeId": "plcComplete",
          "address": "MB.0x0000",
          "value": [1],
          "plcDataType": "int",
          "length": 2
        },
        {
          "codeId": "mesComplete",
          "address": "MB.0x0010",
          "value": [0],
          "plcDataType": "int",
          "length": 2
        }
      ],
      "returnValue": [
        {
          "codeId": "mesComplete",
          "address": "MB.0x0010",
          "fixed": true,
          "value": 1,
          "plcDataType": "int",
          "length": 2
        }
      ]
    }
  ]
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/JsonFile/shelfS7.json
New file
@@ -0,0 +1,244 @@
{
  "parameters": [
    {
      "serialNumber": 0,
      "content": "PLC请求",
      "codeId": "plcRequest",
      "plcDataType": "Word",
      "fontLocation": 0,
      "length": 2,
      "ratio": 1,
      "scale": 1,
      "address": "S7.DB8.DBW0",
      "remarks": ""
    },
    {
      "serialNumber": 1,
      "content": "PLC请求ID",
      "codeId": "plcRequestId",
      "plcDataType": "Word",
      "fontLocation": 2,
      "length": 2,
      "ratio": 2,
      "scale": 2,
      "address":"S7.DB8.DBW2",
      "remarks": ""
    },
    {
      "serialNumber": 2,
      "content": "备用_1",
      "codeId": "remarks_1",
      "plcDataType": "Word",
      "fontLocation": 4,
      "length": 2,
      "ratio": 3,
      "scale": 3,
      "address": "S7.DB8.DBW4",
      "remarks": ""
    },
    {
      "serialNumber": 3,
      "content": "备用_2",
      "codeId": "remarks_2",
      "plcDataType": "Word",
      "fontLocation": 6,
      "length": 2,
      "ratio": 4,
      "scale": 4,
      "address": "S7.DB8.DBW6",
      "remarks": ""
    },
    {
      "serialNumber": 4,
      "content": "PLC完成字",
      "codeId": "plcComplete",
      "plcDataType": "Word",
      "fontLocation": 10,
      "length": 2,
      "ratio": 5,
      "scale": 5,
      "address": "S7.DB8.DBW10",
      "remarks": ""
    },
    {
      "serialNumber": 5,
      "content": "备用_4",
      "codeId": "remarks_4",
      "plcDataType": "Word",
      "fontLocation": 10,
      "length": 2,
      "ratio": 6,
      "scale": 6,
      "address": "S7.DB8.DBW12",
      "remarks": ""
    },
    {
      "serialNumber": 6,
      "content": "备用_5",
      "codeId": "remarks_5",
      "plcDataType": "Word",
      "fontLocation": 12,
      "length": 2,
      "ratio": 7,
      "scale": 7,
      "address": "S7.DB8.DBW14",
      "remarks": ""
    },
    {
      "serialNumber": 7,
      "content": "备用_6",
      "codeId": "remarks_6",
      "plcDataType": "Word",
      "fontLocation": 14,
      "length": 2,
      "ratio": 8,
      "scale": 8,
      "address": "S7.DB8.DBW16",
      "remarks": ""
    },
    {
      "serialNumber": 8,
      "content": "备用_7",
      "codeId": "remarks_7",
      "plcDataType": "Word",
      "fontLocation": 16,
      "length": 2,
      "ratio": 9,
      "scale": 9,
      "address": "S7.DB8.DBW18",
      "remarks": ""
    },
    {
      "serialNumber": 9,
      "content": "Mes发送字",
      "codeId": "mesSend",
      "plcDataType": "Word",
      "fontLocation": 18,
      "length": 2,
      "ratio": 10,
      "scale": 10,
      "address": "S7.DB8.DBW20",
      "remarks": ""
    },
    {
      "serialNumber": 10,
      "content": "MES发送长",
      "codeId": "width",
      "plcDataType": "Word",
      "fontLocation": 20,
      "length": 2,
      "ratio": 11,
      "scale": 11,
      "address": "S7.DB8.DBW22",
      "remarks": ""
    },
    {
      "serialNumber": 11,
      "content": "MES发送宽",
      "codeId": "height",
      "plcDataType": "Word",
      "fontLocation": 22,
      "length": 2,
      "ratio": 12,
      "scale": 12,
      "address":"S7.DB8.DBW24",
      "remarks": ""
    },
    {
      "serialNumber": 12,
      "content": "G3M7设备状态",
      "codeId": "13",
      "plcDataType": "Word",
      "fontLocation": 24,
      "length": 2,
      "ratio": 13,
      "scale": 13,
      "address": "S7.DB8.DBW26",
      "remarks": ""
    },
    {
      "serialNumber": 13,
      "content": "Z12设备状态",
      "codeId": "14",
      "plcDataType": "Word",
      "fontLocation": 26,
      "length": 2,
      "ratio": 14,
      "scale": 14,
      "address": "S7.DB8.DBW28",
      "remarks": ""
    },
    {
      "serialNumber": 14,
      "content": "S8设备状态",
      "codeId": "15",
      "plcDataType": "Word",
      "fontLocation": 28,
      "length": 2,
      "ratio": 15,
      "scale": 15,
      "address": "S7.DB8.DBW30",
      "remarks": ""
    },
    {
      "serialNumber": 15,
      "content": "W11定位台设备状态",
      "codeId": "16",
      "plcDataType": "Word",
      "fontLocation": 30,
      "length": 2,
      "ratio": 16,
      "scale": 16,
      "address": "S7.DB8.DBW32",
      "remarks": ""
    },
    {
      "serialNumber": 16,
      "content": "S9设备状态",
      "codeId": "17",
      "plcDataType": "Word",
      "fontLocation": 32,
      "length": 2,
      "ratio": 17,
      "scale": 17,
      "address": "S7.DB8.DBW34",
      "remarks": ""
    },
    {
      "serialNumber": 17,
      "content": "S10设备状态",
      "codeId": "18",
      "plcDataType": "Word",
      "fontLocation": 34,
      "length": 2,
      "ratio": 18,
      "scale": 18,
      "address": "S7.DB8.DBW36",
      "remarks": ""
    },
    {
      "serialNumber": 19,
      "content": "S10设备状态",
      "codeId": "19",
      "plcDataType": "Word",
      "fontLocation": 34,
      "length": 2,
      "ratio": 18,
      "scale": 18,
      "address": "S7.DB8.DBW38",
      "remarks": ""
    },
    {
      "serialNumber": 20,
      "content": "mes确认完成",
      "codeId": "mesComplete",
      "plcDataType": "Word",
      "fontLocation": 40,
      "length": 2,
      "ratio": 10,
      "scale": 10,
      "address": "S7.DB8.DBW40",
      "remarks": ""
    }
  ]
}
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/application-cz.yml
New file
@@ -0,0 +1,32 @@
spring:
  datasource:
    dynamic:
      primary: hangzhoumes #设置默认的数据源或者数据源组,默认值即为master
      strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
      datasource:
        hangzhoumes:
          url: jdbc:mysql://192.168.1.199:3306/hangzhoumes?serverTimezone=GMT%2b8
          username: root
          password: beibo.123/
          driver-class-name: com.mysql.cj.jdbc.Driver
        pp:
          url: jdbc:mysql://192.168.1.199:3306/pp?serverTimezone=GMT%2b8
          username: root
          password: beibo.123/
          driver-class-name: com.mysql.cj.jdbc.Driver
        salve_hangzhoumes:
          url: jdbc:sqlserver://192.168.10.2:1433;databasename=hangzhoumes
          username: sa
          password: beibo.123/
          driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  application:
    name: deviceInteraction
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    password: 123456
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/application-dev.yml
New file
@@ -0,0 +1,32 @@
spring:
  datasource:
    dynamic:
      primary: hangzhoumes #设置默认的数据源或者数据源组,默认值即为master
      strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
      datasource:
        hangzhoumes:
          url: jdbc:mysql://127.0.0.1:3306/hangzhoumes?serverTimezone=GMT%2b8
          username: root
          password: beibo.123/
          driver-class-name: com.mysql.cj.jdbc.Driver
        pp:
          url: jdbc:mysql://127.0.0.1:3306/pp?serverTimezone=GMT%2b8
          username: root
          password: beibo.123/
          driver-class-name: com.mysql.cj.jdbc.Driver
        salve_hangzhoumes:
          url: jdbc:sqlserver://127.0.0.1:1433;databasename=hangzhoumes
          username: sa
          password: beibo.123/
          driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  application:
    name: deviceInteraction
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    password: 123456
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/application-prod.yml
New file
@@ -0,0 +1,32 @@
spring:
  datasource:
    dynamic:
      primary: mes_machine #设置默认的数据源或者数据源组,默认值即为master
      strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
      datasource:
        mes_machine:
          url: jdbc:mysql://localhost:3306/mes_machine?serverTimezone=GMT%2b8&rewriteBatchedStatements=true
          username: root
          password: beibo.123/
          driver-class-name: com.mysql.cj.jdbc.Driver
        salve_JomooKBB:
          url: jdbc:sqlserver://localhost:1433;databasename=JomooKBB
          username: sa
          password: beibo.123/
          driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
#        salve_JomooKBB:
#          url: jdbc:sqlserver://172.18.19.85:1433;databasename=JomooKBB
#          username: thok
#          password: jomoo@123
#          driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  application:
    name: deviceInteraction
  redis:
    database: 0
    host: localhost
    port: 6379
    password: 123456
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/application.yml
New file
@@ -0,0 +1,33 @@
server:
  port: 8081
  tomcat:
    uri-encoding: UTF-8
    max-threads: 800 #最大工作线程数量
    min-spare-threads: 20 #最小工作线程数量
    #max-connections: 10000 #一瞬间最大支持的并发的连接数
    accept-count: 200 #等待队列长度
spring:
  profiles:
    active: prod
  application:
    name: deviceInteraction
mybatis-plus:
  mapper-locations: classpath*:mapper/*.xml
#  configuration:
#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mes:
  threshold: 3
  ratio: 10
  max: # 第二条线的最大尺寸信息
    firstLength: 3500
    secondLength: 2500
  min:
    one: #第一条磨边线的最小尺寸信息
      firstLength: 600
      secondLength: 350
    two: #第二条磨边线的最小尺寸信息
      firstLength: 400
      secondLength: 300
  sequence:
    order: false
ShangHaiMesParent/moduleService/plcConnectModule/src/main/resources/logback-spring.xml
New file
@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
    <!-- logger上下文名称(根据业务修改) -->
    <contextName>deviceInteraction</contextName>
    <!-- 定义了一个名为serverName的属性,它的值来自于logging.file.name,如果没有找到该属性默认为MyServerName(根据业务修改) -->
    <springProperty name="serverName" source="logging.file.name" defaultValue="deviceInteraction"/>
    <springProperty name="logging.path" source="logging.file.path" defaultValue="././logs/"/>
    <!-- 彩色日志依赖的渲染类 -->
    <!-- 定义了一个名为clr的转换规则,它使用org.springframework.boot.logging.logback.ColorConverter类进行转换,这个元素通常用于将日志输出中的文本着色,以便更容易地区分不同的日志级别或其他信息 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <!-- WhitespaceThrowableProxyConverter和ExtendedWhitespaceThrowableProxyConverter都是用于将异常信息转换为字符串,并将其中的换行符替换为空格,以便更容易地在日志输出中显示的类。它们之间的区别在于,ExtendedWhitespaceThrowableProxyConverter在输出异常信息时会包含更多的详细信息,例如异常的类名、方法名和行号等 -->
    <!-- 定义了一个名为wex的转换规则,它使用org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter类进行转换,这个元素通常用于将异常信息转换为字符串,并将其中的换行符替换为空格,以便更容易地在日志输出中显示 -->
    <conversionRule conversionWord="wex"
                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
    <!-- 定义了一个名为wEx的转换规则,它使用org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter类进行转换,这个元素通常用于将异常信息转换为字符串,并将其中的换行符替换为空格,以便更容易地在日志输出中显示 -->
    <conversionRule conversionWord="wEx"
                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
    <!-- 彩色日志格式 -->
    <!-- value值是日志输出模板, :-是属性名和其默认值之间的分隔符,作用与:相同 -->
    <!-- 定义日志输出格式的转换规则,%d{yyyy-MM-dd HH:mm:ss.SSS}表示日期和时间,%clr表示将输出文本着色,{faint}表示使用淡色 -->
    <!-- %5p表示日志级别输出右对齐,左边以空格填充 -->
    <!-- ${PID:- }表示进程ID,%clr表示将输出文本着色,{magenta}表示使用洋红色 -->
    <!-- -表示一个分隔符 -->
    <!-- %t:显示产生该日志的线程名;%15:若字符长度小于15,则左边用空格填充;%.15:若字符长度超过15,截去多余字符 -->
    <!-- %-40:若字符长度小于40,则右边用空格填充;%.40:若字符长度超过40,截去多余字符;logger{39}对应的是“logging.WARNING”级别。具体来说,Python的logging模块定义了以下几个级别(从低到高):NOTSET、DEBUG、INFO、WARNING、ERROR、CRITICAL。因此,logger{39}表示的是WARNING级别,即日志记录器会记录所有WARNING级别及以上的日志信息 -->
    <!-- %m表示日志消息;%n表示换行符;${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}表示异常信息。如果日志输出中包含异常信息,这个规则将会将其转换为字符串,并将其中的换行符替换为空格,以便更容易地在日志输出中显示 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
    <!--1. 输出到控制台-->
    <!-- 定义控制台日志输出的appender,class="ch.qos.logback.core.ConsoleAppender"表示使用Logback框架提供的ConsoleAppender类来输出日志到控制台 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <!-- 定义日志输出级别的过滤器,class="ch.qos.logback.classic.filter.ThresholdFilter"表示使用Logback框架提供的ThresholdFilter类来过滤日志输出,<level>debug</level>表示只输出debug级别及以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
        <encoder>
            <!-- ${CONSOLE_LOG_PATTERN}表示控制台日志输出格式,UTF-8表示编码格式 -->
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!--2. 输出到文档-->
    <!-- 2.1 level为 DEBUG 日志,时间滚动输出  -->
    <!-- 定义文件日志输出的appender,class="ch.qos.logback.core.rolling.RollingFileAppender"表示使用Logback框架提供的RollingFileAppender类来输出日志到文件 -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${logging.path}/${serverName}/web_debug.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <!-- 定义日志文件滚动策略的标签,class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"表示使用Logback框架提供的TimeBasedRollingPolicy类来定义日志文件的滚动策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志归档 -->
            <!-- 定义日志文件名的模式。在这个模式中,${logging.path}表示日志文件的路径,%d{yyyy-MM-dd}表示日期格式,%i表示文件索引 -->
            <fileNamePattern>${logging.path}/${serverName}/web-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 定义日志文件滚动策略的标签,class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"表示使用Logback框架提供的SizeAndTimeBasedFNATP类来定义日志文件的滚动策略,<maxFileSize>100MB</maxFileSize>表示日志文件的最大大小为100MB。这个滚动策略通常用于按照时间和文件大小滚动日志文件,以便更好地管理日志文件的大小和数量 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录debug级别的 -->
        <!-- 定义日志输出级别的过滤器。在这个过滤器中,class="ch.qos.logback.classic.filter.LevelFilter"表示使用Logback框架提供的LevelFilter类来过滤日志输出,<level>debug</level>表示只输出debug级别及以上的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>debug</level>
            <!-- <onMatch>ACCEPT</onMatch>表示如果日志事件与过滤器匹配,则接受该事件,<onMismatch>DENY</onMismatch>表示如果日志事件与过滤器不匹配,则拒绝该事件 -->
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.2 level为 INFO 日志,时间滚动输出  -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${logging.path}/${serverName}/web_info.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 天天日志归档路径以及格式 -->
            <fileNamePattern>${logging.path}/${serverName}/web-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.3 level为 WARN 日志,时间滚动输出  -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${logging.path}/${serverName}/web_warn.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${logging.path}/${serverName}/web-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 2.4 level为 ERROR 日志,时间滚动输出  -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${logging.path}/${serverName}/web_error.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${logging.path}/${serverName}/web-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!--     4.1 开发环境:打印控制台-->
    <!-- 用于在Spring Boot应用程序中配置日志记录的标签。在这个标签中,name="dev"表示这个配置文件只在dev环境中生效,<logger name="com.myClass.controller" level="debug"/>表示为com.myClass.controller(根据业务修改)这个包下的类配置日志输出级别为debug -->
    <!--    <springProfile name="dev">-->
    <!--        <logger name="com.myClass.controller" level="debug"/>-->
    <!--    </springProfile>-->
    <!-- 用于配置日志输出的标签。在这个标签中,level="info"表示日志输出级别为info,<appender-ref ref="CONSOLE"/>、<appender-ref ref="DEBUG_FILE"/>、<appender-ref ref="INFO_FILE"/>、<appender-ref ref="WARN_FILE"/>、<appender-ref ref="ERROR_FILE"/>表示将日志输出到不同的appender中,分别为控制台、debug文件、info文件、warn文件和error文件 -->
    <root level="info">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="DEBUG_FILE"/>
        <appender-ref ref="INFO_FILE"/>
        <appender-ref ref="WARN_FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </root>
</configuration>
ShangHaiMesParent/moduleService/plcConnectModule/src/test/java/com/mes/plcConnectModuleApplicationTest.java
New file
@@ -0,0 +1,161 @@
package com.mes;
import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
import com.mes.common.JsonConversion;
import com.mes.common.ReadFile;
import com.mes.connect.IndustrialInterface.Api;
import com.mes.connect.IndustrialInterface.IndustrialClient;
import com.mes.connect.Thread.MachineThread;
import com.mes.connect.entity.LogicConfig;
import com.mes.connect.entity.PlcParameters;
import com.mes.connect.s7.S7Client;
import com.mes.connect.s7.S7ClientOld;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.io.IOException;
import java.sql.Types;
import java.util.*;
/**
 * @Author : yanzhixin
 * @Date: 2024/3/27 16:37
 * @Description:
 */
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = plcConnectModuleApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class plcConnectModuleApplicationTest {
    @Autowired
    Api api;
    @Test
    public void testb() {
        //byte[] resultValues=new byte[]{99, 23, 67, 76, 45, 49, 48, 45, 56, 48, 47, 55, 48, 67, 76, 45, 51, 45, 55, 51};
        String s="白玻";
        log.info(s);
    }
    @Test
    public void testReadJson() {
        try {
            LogicConfig logicConfig=JsonConversion.jsonToObjectByJackson(ReadFile.readJson("shelfLogic.json").toString(), LogicConfig.class);
            PlcParameters plcParameters=JsonConversion.jsonToObjectByJackson(ReadFile.readJson("shelf.json").toString(), PlcParameters.class);
            log.info("{},{}",logicConfig,plcParameters);
        }catch (Exception e) {
        }
    }
    @Test
    public void testReadS7Old() throws IOException {
        S7PLC s7PLC = new S7PLC(EPlcType.S1500, "10.153.19.191", 102, 0, 0);
        s7PLC.connect();
        int value= s7PLC.readUInt16("DB8.6");
        log.info("{},{}",value,s7PLC.checkConnected());
        s7PLC.close();
    }
    @Test
    public void testReadS7OldClient() throws IOException {
        IndustrialClient client = new S7ClientOld("S1500","10.153.19.191", 102, 0, 1);
        client.connect();
        int value=client.readRegister("S7.DB8.DBW6");
        log.info("{}",value);
        client.disconnect();
    }
    @Test
    public void testReadS7() throws IOException {
        IndustrialClient client=new S7Client("10.153.19.42", 102, 0, 1);;
        client.connect();
        // 连接到 PLC
        System.out.println("成功连接到 PLC");
//        // 读取单个位
//        boolean bitValue = client.readBit("S7.DB1.0");
//        System.out.println("DB1.DBX0.0 的值: " + bitValue);
//
//        // 写入单个位
//        client.writeBit("DB1.DBX0.1", true);
//        System.out.println("已将 DB1.DBX0.1 设置为 true");
        // 读取单个寄存器 (Word)
        int registerValue = client.readRegister("DB1.DBW2");
        System.out.println("DB1.DBW2 的值: " + registerValue);
//
//        // 写入单个寄存器
//        client.writeRegister("DB1.DBW4", 12345);
//        System.out.println("已将 DB1.DBW4 设置为 12345");
//
//        // 读取多个寄存器
//        int[] registers = client.readRegisters("DB1.DBW6", 3);
//        System.out.println("DB1.DBW6-DB1.DBW11 的值: " +
//                registers[0] + ", " +
//                registers[1] + ", " +
//                registers[2]);
//
//        // 写入多个寄存器
//        int[] values = {6789, 101112, 131415};
//        client.writeRegisters("DB1.DBW12", values);
//        System.out.println("已写入多个寄存器值");
//
//        // 读取浮点数
//        float floatValue = client.readFloat("DB1.DBD18");
//        System.out.println("DB1.DBD18 的浮点值: " + floatValue);
//
//        // 写入浮点数
//        client.writeFloat("DB1.DBD22", 3.14159f);
//        System.out.println("已将 DB1.DBD22 设置为 3.14159");
//
//        // 读取字符串
//        String stringValue = client.readString("DB1.DBW26", 10);
//        System.out.println("DB1.DBW26 开始的字符串: " + stringValue);
//
//        // 写入字符串
//        client.writeString("DB1.DBW36", "Hello PLC");
//        System.out.println("已写入字符串 'Hello PLC'");
    }
    @Test
    public void testApi() {
        //Http接口测试
//        Map<String, Object> data=new HashMap<>();
//        data.put("method","POST");
//        String resultHttp[]= api.httpApi("http://localhost:8082/account/testApi",data);
//        log.info("{}",resultHttp);
        // 查询带单个参数的视图
//        Map<String, Object> params = new HashMap<>();
//        params.put("width", 699); // 参数名与SQL中的列名一致
//        String resultView[]= api.viewApi("procedurename",null);
//        log.info("{}",resultView);
        // 示例 调用testProcedure存储过程
//        Map<String, Object> params = new HashMap<>();
//        params.put("dataParmars", "测试数据"); // 输入参数,对应存储过程中的IN参数
//        Map<String, Object> outParams = new HashMap<>();
//        outParams.put("messagedate", Types.VARCHAR); // 输出参数,对应存储过程中的OUT参数
//        String[] resultProcedure = api.procedureAPI("testProcedure", params, outParams);
//        // 打印执行结果
//        log.info("{}存储过程执行结果:{}",params,resultProcedure);
    }
    @Test
    public void testMainThread() {
        Thread thread = new Thread(() -> {
            while (true) {
                log.info(new Date().toString());
            }
        });
        thread.start();
    }
    @Test
    public void testMain() {
    }
}
ShangHaiMesParent/moduleService/plcConnectModule/src/test/test.iml
New file
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$">
      <sourceFolder url="file://$MODULE_DIR$/java" isTestSource="true" />
    </content>
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
</module>
ShangHaiMesParent/moduleService/pom.xml
New file
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>ShangHaiMesParent</artifactId>
        <groupId>com.mes</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>moduleService</artifactId>
    <packaging>pom</packaging>
    <modules>
        <module>plcConnectModule</module>
<!--        <module>CacheVerticalGlassModule</module>-->
<!--        <module>LoadGlassModule</module>-->
<!--        <module>TemperingGlassModule</module>-->
<!--        <module>UnLoadGlassModule</module>-->
<!--        <module>GlassStorageModule</module>-->
    </modules>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!--web 需要启动项目-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.0</version>
        </dependency>
        <!--依赖服务的工具类-->
        <!--        <dependency>-->
        <!--            <groupId>com.mes</groupId>-->
        <!--            <artifactId>common</artifactId>-->
        <!--            <version>1.0-SNAPSHOT</version>-->
        <!--        </dependency>-->
        <dependency>
            <artifactId>servicebase</artifactId>
            <groupId>com.mes</groupId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
<!--        <dependency>-->
<!--            <artifactId>springsecurity</artifactId>-->
<!--            <groupId>com.mes</groupId>-->
<!--            <version>1.0-SNAPSHOT</version>-->
<!--        </dependency>-->
        <!--开发者工具-->
        <!--        <dependency>-->
        <!--            <groupId>org.springframework.boot</groupId>-->
        <!--            <artifactId>spring-boot-devtools</artifactId>-->
        <!--            <optional>true</optional>-->
        <!--        </dependency>-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
ShangHaiMesParent/pom.xml
New file
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mes</groupId>
    <artifactId>ShangHaiMesParent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>common</module>
        <module>moduleService</module>
        <module>gateway</module>
    </modules>
    <packaging>pom</packaging>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
        <relativePath/>
    </parent>
    <properties>
        <!-- 跳过测试 -->
        <skipTests>true</skipTests>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <repositories>
        <repository>
            <id>nexus-aliyun</id>
            <name>Nexus aliyun</name>
            <layout>default</layout>
            <url>https://maven.aliyun.com/repository/public</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <releases>
                <enabled>true</enabled>
            </releases>
        </repository>
        <repository>
            <id>spring</id>
            <url>https://maven.aliyun.com/repository/spring</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>
ShangHaiMesParent/readMe.md
New file
@@ -0,0 +1,18 @@
1、本项目是基于SpringBoot+Mybatis-plus+Mysql+Vue+ElementUI+Maven+Nginx的项目,目录结果结构如下:
    ├─src
    ├─com   插件生成的代码,用于各自开发使用
    │  └─mes
    ├─common  公共模块
    │  ├─src
    └─moduleService
        ├─-CacheGlassModule
        ├─-CacheVerticalGlassModule
        ├─-LoadGlassModule
        ├─-TemperingGlassModule
        └─-UnLoadGlassModule
2、运行项目: 1、启动项目:启动各自模块启动类 例如:CacheGlassModuleApplication.java#main()
2、访问项目: 3、项目地址:http://localhost:8081/mesModuleCache/doc.html#/home
4、项目说明: 本界面为Api文档,公开人员用于调试 3、项目说明: 1、项目分为公共模块common,业务模块moduleService。 2、common模块中包含公共的类,例如:公共的实体类、拦截器、工具类、常量类、异常处理等。
3、moduleService中包含各个业务模块,每个业务模块中包含一个启动类,开发人员需要开发各自负责的业务模块。 4、com目录下的文件为插件生成的代码,用于各自开发使用。用完删除即可,避免影响开发。