| New file |
| | |
| | | # 默认忽略的文件 |
| | | /shelf/ |
| | | /workspace.xml |
| | | # 基于编辑器的 HTTP 客户端请求 |
| | | /httpRequests/ |
| | | # Datasource local storage ignored files |
| | | /dataSources/ |
| | | /dataSources.local.xml |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <project version="4"> |
| | | <component name="VcsDirectoryMappings"> |
| | | <mapping directory="" vcs="Git" /> |
| | | </component> |
| | | </project> |
| New file |
| | |
| | | # Default ignored files |
| | | /shelf/ |
| | | /workspace.xml |
| | | # Editor-based HTTP Client requests |
| | | /httpRequests/ |
| | | # Datasource local storage ignored files |
| | | /dataSources/ |
| | | /dataSources.local.xml |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <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> |
| New file |
| | |
| | | <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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <project version="4"> |
| | | <component name="VcsDirectoryMappings"> |
| | | <mapping directory="$PROJECT_DIR$/.." vcs="Git" /> |
| | | </component> |
| | | </project> |
| New file |
| | |
| | | { |
| | | "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":"" |
| | | } |
| | | ] |
| | | } |
| New file |
| | |
| | | { |
| | | "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": "" |
| | | } |
| | | |
| | | ] |
| | | } |
| New file |
| | |
| | | { |
| | | "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": "" |
| | | } |
| | | ] |
| | | |
| | | } |
| New file |
| | |
| | | { |
| | | "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": "" |
| | | } |
| | | |
| | | ] |
| | | } |
| New file |
| | |
| | | { |
| | | "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": "" |
| | | } |
| | | |
| | | ] |
| | | } |
| New file |
| | |
| | | { |
| | | "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": "" |
| | | } |
| | | ] |
| | | |
| | | } |
| New file |
| | |
| | | { |
| | | "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": "" |
| | | } |
| | | ] |
| | | |
| | | } |
| New file |
| | |
| | | { |
| | | "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": "" |
| | | } |
| | | |
| | | ] |
| | | } |
| New file |
| | |
| | | { |
| | | "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": "" |
| | | } |
| | | |
| | | ] |
| | | } |
| New file |
| | |
| | | { |
| | | "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": "" |
| | | } |
| | | ] |
| | | |
| | | } |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | 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; |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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())); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| New file |
| | |
| | | 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)){ |
| | | |
| | | } |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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> |
| | | */ |
| New file |
| | |
| | | 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(); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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'); |
| | | } |
| | | } |
| New file |
| | |
| | | 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")); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | ________ ________ ___ _____________ ____ |
| | | `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 // |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| New file |
| | |
| | | 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(); |
| | | |
| | | } |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| New file |
| | |
| | | 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()); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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)); |
| | | } |
| | | |
| | | } |
| | | |
| New file |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| New file |
| | |
| | | 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); |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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)); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | |
| | | } |
| New file |
| | |
| | | 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> { |
| | | |
| | | } |
| New file |
| | |
| | | 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> { |
| | | |
| | | } |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | 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> { |
| | | |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| New file |
| | |
| | | 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 { |
| | | |
| | | } |
| New file |
| | |
| | | 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"; |
| | | } |
| | | } |
| New file |
| | |
| | | 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)); |
| | | } |
| | | |
| | | } |
| | | |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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> { |
| | | |
| | | } |
| New file |
| | |
| | | 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> { |
| | | |
| | | } |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | 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> { |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| New file |
| | |
| | | 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 { |
| | | |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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 |
| New file |
| | |
| | | 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 |
| New file |
| | |
| | | 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 |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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 |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | 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("多线程异常!!"); |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.mes.connect.IndustrialInterface; |
| | | |
| | | import com.mes.connect.protocol.ProtocolAddress; |
| | | |
| | | /** |
| | | * 地址解析器接口 |
| | | */ |
| | | public interface AddressParser { |
| | | ProtocolAddress parse(String address); |
| | | } |
| New file |
| | |
| | | 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}$"); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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); |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| New file |
| | |
| | | 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)); |
| | | } |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| New file |
| | |
| | | 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; |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| New file |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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)); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| New file |
| | |
| | | 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()); |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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 + |
| | | '}'; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.mes.connect.protocol; |
| | | |
| | | /** |
| | | * 协议类型枚举 |
| | | */ |
| | | public enum ProtocolType { |
| | | S7, MODBUS_TCP, MODBUS_IP, MODBUS_RTU |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | } |
| New file |
| | |
| | | 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); |
| | | } |
| | | |
| | | } |
| | | |
| New file |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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> { |
| | | |
| | | } |
| New file |
| | |
| | | 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> { |
| | | |
| | | } |
| New file |
| | |
| | | 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> { |
| | | |
| | | } |
| New file |
| | |
| | | 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> { |
| | | |
| | | } |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | 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> { |
| | | |
| | | } |
| New file |
| | |
| | | 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(); |
| | | } |
| New file |
| | |
| | | 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> { |
| | | |
| | | } |
| New file |
| | |
| | | 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> { |
| | | |
| | | } |
| New file |
| | |
| | | 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 { |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | 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 { |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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 { |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | 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()); |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | { |
| | | "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 |
| | | } |
| | | ] |
| | | } |
| | | ] |
| | | } |
| New file |
| | |
| | | { |
| | | "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 |
| | | } |
| | | ] |
| | | } |
| | | ] |
| | | } |
| New file |
| | |
| | | { |
| | | "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 |
| | | } |
| | | ] |
| | | } |
| | | ] |
| | | } |
| New file |
| | |
| | | { |
| | | "请求逻辑":{ |
| | | "name":"请求逻辑", |
| | | "connectType":"HTTP", |
| | | "connectAddress": "http://39.105.110.179:5000/Request" |
| | | }, |
| | | "请求清空":{ |
| | | "name":"请求清空", |
| | | "connectType":"Procedure", |
| | | "connectAddress": "存储过程名称" |
| | | }, |
| | | "完成逻辑":{ |
| | | "name":"完成逻辑", |
| | | "connectType":"View", |
| | | "connectAddress": "视图名称" |
| | | } |
| | | } |
| New file |
| | |
| | | { |
| | | "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": "" |
| | | } |
| | | ] |
| | | } |
| New file |
| | |
| | | { |
| | | "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 |
| | | } |
| | | ] |
| | | } |
| | | ] |
| | | } |
| New file |
| | |
| | | { |
| | | "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": "" |
| | | } |
| | | ] |
| | | } |
| New file |
| | |
| | | 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 |
| New file |
| | |
| | | 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 |
| New file |
| | |
| | | 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 |
| New file |
| | |
| | | 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 |
| | | |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | 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() { |
| | | |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | <?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> |
| New file |
| | |
| | | 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目录下的文件为插件生成的代码,用于各自开发使用。用完删除即可,避免影响开发。 |