init
This commit is contained in:
commit
a1adfd9cbe
170
.gitignore
vendored
Normal file
170
.gitignore
vendored
Normal file
@ -0,0 +1,170 @@
|
||||
#################
|
||||
## Eclipse
|
||||
#################
|
||||
|
||||
_site
|
||||
*.iml
|
||||
.idea/
|
||||
target/
|
||||
*.log
|
||||
*.gz
|
||||
out/
|
||||
|
||||
*.pydevproject
|
||||
.project
|
||||
.metadata
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
.classpath
|
||||
.settings/
|
||||
.loadpath
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
|
||||
#################
|
||||
## Visual Studio
|
||||
#################
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
*_i.c
|
||||
*_p.c
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.vspscc
|
||||
.builds
|
||||
*.dotCover
|
||||
|
||||
#packages/
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish
|
||||
|
||||
# Others
|
||||
[Bb]in
|
||||
[Oo]bj
|
||||
# sql
|
||||
TestResults
|
||||
*.Cache
|
||||
ClientBin
|
||||
stylecop.*
|
||||
~$*
|
||||
*.dbmdl
|
||||
Generated_Code #added for RIA/Silverlight projects
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
|
||||
|
||||
|
||||
############
|
||||
## Windows
|
||||
############
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
|
||||
#############
|
||||
## Python
|
||||
#############
|
||||
|
||||
*.py[co]
|
||||
|
||||
# Packages
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist
|
||||
build
|
||||
eggs
|
||||
parts
|
||||
bin
|
||||
var
|
||||
sdist
|
||||
develop-eggs
|
||||
.installed.cfg
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
.coverage
|
||||
.tox
|
||||
|
||||
#Translations
|
||||
*.mo
|
||||
|
||||
#Mr Developer
|
||||
.mr.developer.cfg
|
||||
|
||||
# Mac crap
|
||||
.DS_Store
|
||||
|
||||
.gradle
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
249
gradlew
vendored
Normal file
249
gradlew
vendored
Normal file
@ -0,0 +1,249 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
92
gradlew.bat
vendored
Normal file
92
gradlew.bat
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
106
pom.xml
Normal file
106
pom.xml
Normal file
@ -0,0 +1,106 @@
|
||||
<?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.cisdi.data</groupId>
|
||||
<artifactId>dacoo-data-sdk-yongfeng</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-core</artifactId>
|
||||
<version>8.5.51</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-el</artifactId>
|
||||
<version>8.5.51</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-websocket</artifactId>
|
||||
<version>8.5.51</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-annotations-api</artifactId>
|
||||
<version>8.5.51</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.cisdi.data</groupId>
|
||||
<artifactId>dacoo-data-common</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.cisdi.data</groupId>
|
||||
<artifactId>dacoo-data-sdk</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<groupId>io.netty</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.97.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-dbcp2</artifactId>
|
||||
<version>2.8.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.46</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>27.0-jre</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
<version>1.1.2-beta5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.java-websocket</groupId>
|
||||
<artifactId>Java-WebSocket</artifactId>
|
||||
<version>1.3.8</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.28</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
28
rfid测试说明.txt
Normal file
28
rfid测试说明.txt
Normal file
@ -0,0 +1,28 @@
|
||||
心跳报文
|
||||
02486561727442656103
|
||||
|
||||
一个标签
|
||||
02524630313030303103
|
||||
|
||||
--2条电文
|
||||
0252463031303030310302524830333030303103
|
||||
|
||||
-- 4条电文
|
||||
02524630313030303103025248303330303031030252463031303030310302524830333030303103
|
||||
|
||||
-- 4条电文心跳2:
|
||||
025246303130303031030252483033303030310302524630313030303103025248303330303031030248656172744265610302486561727442656103
|
||||
|
||||
一个标签+心跳+ 一个标签
|
||||
02524630313030303103024865617274426561030252463031303030310302524630313030303103025246303130303031030252463031303030310302524630313030303103025246303130303031030252483033303030310302524630313030303103025248303330303031030248656172744265610302486561727442656103
|
||||
|
||||
|
||||
|
||||
-- 启用心跳
|
||||
{"enableHeartbeat":true,"heartbeatMaxLostCount":3,"heartbeatTimeInMs":5000}
|
||||
|
||||
--多个serverId
|
||||
{"serverList":["10.233.8.22:2112","10.233.8.23:2112","10.233.8.24:2112","10.233.8.25:2112"]}
|
||||
|
||||
--启用心跳+ 多个server
|
||||
{"enableHeartbeat":true,"heartbeatMaxLostCount":3,"heartbeatTimeInMs":5000,"serverList":["10.233.8.22:2112","10.233.8.23:2112","10.233.8.24:2112","10.233.8.25:2112"]}
|
2
settings.gradle
Normal file
2
settings.gradle
Normal file
@ -0,0 +1,2 @@
|
||||
rootProject.name = 'dacoo-data-sdk-DI-client'
|
||||
|
@ -0,0 +1,209 @@
|
||||
package com.cisdi.data.AMETEKSurfaceVision;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionAliveCheckTask;
|
||||
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionChannelInitializer;
|
||||
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionFrameDecoder;
|
||||
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionIoSession;
|
||||
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionSessionFactory;
|
||||
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionSocketReturnMessage;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.enums.GatewayState;
|
||||
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
|
||||
import com.cisdi.data.sdk.param.ListenSocketParam;
|
||||
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
|
||||
import com.cisdi.data.sdk.service.RouteService;
|
||||
import com.cisdi.data.sdk.vo.DeviceVo;
|
||||
import com.cisdi.data.sdk.vo.ExeResultVo;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
/**
|
||||
* 表检仪tcp协议 平台:server rfid:客户端
|
||||
*
|
||||
* @author tzz
|
||||
*/
|
||||
public class AMETEKSurfaceVisionGateway extends SocketGatewayBase {
|
||||
private static Logger logger = LoggerFactory.getLogger(AMETEKSurfaceVisionGateway.class);
|
||||
private TcpIoService ioService = null;
|
||||
private SessionFactory sessionFactory = null;
|
||||
private AtomicBoolean shouldRun = new AtomicBoolean(false);
|
||||
private String deviceId;
|
||||
private BlockingQueue<SocketReturnMessage> sendQueue = new LinkedBlockingQueue<>(1);
|
||||
|
||||
/**
|
||||
* 下发命令超时时间,单位毫秒
|
||||
*/
|
||||
private static int maxSendTime = 5000;
|
||||
|
||||
private static final int sleepInternal = 100;
|
||||
//10毫秒
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public ExeResultVo sendReturnMessage(SocketReturnMessage returnMsg) {
|
||||
logger.info("send msg is :{}", returnMsg);
|
||||
//阻塞队列,容量为1,若上一个命令未发送则阻塞
|
||||
sendQueue.put(returnMsg);
|
||||
|
||||
ExeResultVo sendResult = new ExeResultVo();
|
||||
sendResult.setSuccess(false);
|
||||
|
||||
try {
|
||||
SurfaceVisionSocketReturnMessage sendMsg = new SurfaceVisionSocketReturnMessage();
|
||||
BeanUtils.copyProperties(returnMsg, sendMsg);
|
||||
sendMsg.setSendReturnFlag(false);
|
||||
|
||||
//发送下发命令
|
||||
List<IoSession> sessions = sessionFactory.getSessions();
|
||||
SurfaceVisionIoSession ioSession = (SurfaceVisionIoSession) sessions.get(0);
|
||||
logger.info("send msg SurfaceVisionIoSession is :{}", ioSession);
|
||||
ioSession.send(sendMsg);
|
||||
|
||||
//等待下发命令返回,若等待时间超过最大等待时长,直接返回下发失败,每隔sleepInternal时间判断一次
|
||||
long sendTime = System.currentTimeMillis();
|
||||
while (!sendMsg.getSendReturnFlag()) {
|
||||
long now = System.currentTimeMillis();
|
||||
if ((now - sendTime) > (maxSendTime)) {
|
||||
sendResult.setMessage("下发命令响应超时,超时时间为:" + maxSendTime + "ms");
|
||||
ioSession.setCurrentSend(null);
|
||||
return sendResult;
|
||||
}
|
||||
Thread.sleep(sleepInternal);
|
||||
}
|
||||
ioSession.setCurrentSend(null);
|
||||
logger.info("send result is :{}", sendMsg.getRealData());
|
||||
|
||||
sendResult = sendMsg.getRealData();
|
||||
}catch (Exception e){
|
||||
logger.error("下发中断,异常为: ", e);
|
||||
sendResult.setMessage("下发异常中断");
|
||||
}finally {
|
||||
//空出阻塞队列
|
||||
sendQueue.take();
|
||||
}
|
||||
return sendResult;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if(state == GatewayState.RUNNING) {
|
||||
return;
|
||||
}
|
||||
|
||||
//配置信息校验
|
||||
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
|
||||
|
||||
maxSendTime = socketParam.getTimeout();
|
||||
|
||||
if (StringUtils.isEmpty(socketParam.getListenIp()) || socketParam.getListenPort() == null) {
|
||||
throw new BusinessException("未正确配置监听ip地址和监听端口。");
|
||||
}
|
||||
|
||||
logger.info("AMETEKSurfaceVision网关:{}读取启动配置参数:{}",instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
//读取网关连接配置参数
|
||||
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
|
||||
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
|
||||
|
||||
//一个网关连接只能配置一个设备
|
||||
if(deviceVos.size() > 1) {
|
||||
throw new BusinessException("网关Id:" +instanceVo.getRunId() + "为AMETEKSurfaceVision网关,只允许关联一个设备Id");
|
||||
}
|
||||
|
||||
deviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
|
||||
|
||||
if(StringUtils.isEmpty(deviceId)) {
|
||||
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
|
||||
}
|
||||
|
||||
//创建session工厂并初始化
|
||||
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
|
||||
SessionFactory factory = new SurfaceVisionSessionFactory(deviceId);
|
||||
factory.init(serviceProvider, this);
|
||||
|
||||
//初始化channel
|
||||
SurfaceVisionChannelInitializer<SurfaceVisionFrameDecoder> channelInitializer =
|
||||
new SurfaceVisionChannelInitializer<>(factory);
|
||||
|
||||
//初始化ioService
|
||||
defaultIoService.init(instanceVo, factory, channelInitializer);
|
||||
|
||||
ioService = defaultIoService;
|
||||
sessionFactory = factory;
|
||||
|
||||
//启动监听
|
||||
boolean open = ioService.open();
|
||||
|
||||
if(open == true) {
|
||||
state = GatewayState.RUNNING;
|
||||
logger.info("AMETEKSurfaceVision网关:{}启动成功 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
instanceVo.setLogOpen(true);
|
||||
//心跳机制
|
||||
shouldRun.set(true);
|
||||
//
|
||||
// Integer keepAlive = socketParam.getKeepAlive();
|
||||
//
|
||||
// if(keepAlive == null || keepAlive < 10) {
|
||||
// keepAlive = 10;
|
||||
// }else if (keepAlive > 60) {
|
||||
// keepAlive = 60;
|
||||
// }
|
||||
//
|
||||
// SurfaceVisionAliveCheckTask task = new SurfaceVisionAliveCheckTask(keepAlive, shouldRun, factory);
|
||||
//
|
||||
// Thread thread = new Thread(task, "ametek-surface-alive-check-thread-" + getInstanceVo().getRunId());
|
||||
// thread.start();
|
||||
}else {
|
||||
logger.info("AMETEKSurfaceVision网关:{}启动失败 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if(state == GatewayState.CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
//关闭channel
|
||||
if(sessionFactory != null) {
|
||||
for (IoSession ioSession : sessionFactory.getSessions()) {
|
||||
SurfaceVisionIoSession imsIoSession = (SurfaceVisionIoSession)ioSession;
|
||||
imsIoSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
//关闭监听和会话
|
||||
boolean close = ioService.close();
|
||||
if(close == true) {
|
||||
sessionFactory = null;
|
||||
state = GatewayState.CLOSED;
|
||||
shouldRun.set(false);
|
||||
logger.info("AMETEKSurfaceVision网关:{}关闭成功", instanceVo.getRunId());
|
||||
}else {
|
||||
logger.info("AMETEKSurfaceVision网关:{}关闭失败", instanceVo.getRunId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getActiveDeviceIds() {
|
||||
Set<String> set = Sets.newHashSet();
|
||||
set.add(deviceId);
|
||||
return set;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.cisdi.data.AMETEKSurfaceVision;
|
||||
|
||||
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionConstants;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cisdi.data.sdk.gateway.message.SocketMessage;
|
||||
import com.cisdi.data.sdk.procotol.SocketProtocol;
|
||||
import com.cisdi.data.sdk.procotol.base.ProtocolBase;
|
||||
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
|
||||
import com.cisdi.data.sdk.vo.DecodeVo;
|
||||
import com.cisdi.data.sdk.vo.ReturnVo;
|
||||
|
||||
/**
|
||||
* 表检仪协议发送给平台的数据编解码
|
||||
*
|
||||
* @author tzz
|
||||
*/
|
||||
public class AMETEKSurfaceVisionSocketProtocol extends ProtocolBase implements SocketProtocol {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public DecodeVo deCode(SocketMessage message) {
|
||||
DecodeVo vo = new DecodeVo();
|
||||
|
||||
Object object = message.getPropsMap().get(SurfaceVisionConstants.S_V_SEND_PLATFORM_DATA);
|
||||
|
||||
Map<String, Object> map = (Map<String, Object>)object;
|
||||
|
||||
vo.setData(map);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketReturnMessage enCode(ReturnVo returnVo) {
|
||||
SocketReturnMessage message = new SocketReturnMessage();
|
||||
message.setDeviceId(returnVo.getDeviceId());
|
||||
message.setMsgId(returnVo.getMsgId());
|
||||
message.setMsgKey(returnVo.getMsgKey());
|
||||
message.getPropsMap().put(SurfaceVisionConstants.S_V_SEND_DATA, returnVo.getValue());
|
||||
return message;
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package com.cisdi.data.AMETEKSurfaceVision;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 实例点位信息
|
||||
*
|
||||
* @author tzz
|
||||
*/
|
||||
public class DynamicCodeActionParamDTO {
|
||||
public enum PropertyType {
|
||||
BYTE,
|
||||
BOOLEAN,
|
||||
SHORT,
|
||||
INT,
|
||||
FLOAT,
|
||||
DOUBLE,
|
||||
STRING,
|
||||
LONG,
|
||||
PLACEHOLDER;
|
||||
}
|
||||
|
||||
private List<PropertyConfig> propertyList;
|
||||
|
||||
public void appendProperty(PropertyConfig propertyConfig) {
|
||||
|
||||
if (propertyConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (propertyList == null) {
|
||||
propertyList = new ArrayList<>();
|
||||
}
|
||||
propertyList.add(propertyConfig);
|
||||
}
|
||||
|
||||
public static class PropertyConfig{
|
||||
|
||||
/** 属性Id*/
|
||||
private String propertyId;
|
||||
|
||||
/** 属性类型*/
|
||||
private PropertyType propertyType;
|
||||
|
||||
/**长度*/
|
||||
private Integer length;
|
||||
|
||||
public String getPropertyId() {
|
||||
return propertyId;
|
||||
}
|
||||
|
||||
public void setPropertyId(String propertyId) {
|
||||
this.propertyId = propertyId;
|
||||
}
|
||||
|
||||
public PropertyType getPropertyType() {
|
||||
return propertyType;
|
||||
}
|
||||
|
||||
public void setPropertyType(PropertyType propertyType) {
|
||||
this.propertyType = propertyType;
|
||||
}
|
||||
|
||||
public Integer getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(Integer length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PropertyConfig{" +
|
||||
"propertyId='" + propertyId + '\'' +
|
||||
", propertyType=" + propertyType +
|
||||
", length=" + length +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public List<PropertyConfig> getPropertyList() {
|
||||
return propertyList;
|
||||
}
|
||||
|
||||
public void setPropertyList(List<PropertyConfig> propertyList) {
|
||||
this.propertyList = propertyList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DynamicCodeActionParamDTO{" +
|
||||
"propertyList=" + propertyList +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.cisdi.data.AMETEKSurfaceVision.gateway;
|
||||
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 保活时间检测,如果超过指定时间,则关闭连接
|
||||
* @author tzz
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
public class SurfaceVisionAliveCheckTask implements Runnable {
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
private AtomicBoolean shouldRun = null;
|
||||
|
||||
/**
|
||||
* 会话允许的保活时间,单位秒
|
||||
*/
|
||||
private int keepAlive;
|
||||
|
||||
private static final double multiply = 2;
|
||||
|
||||
private static final int sleepInternal = 1000; // 1秒
|
||||
|
||||
public SurfaceVisionAliveCheckTask(int keepAlive, AtomicBoolean shouldRun, SessionFactory sessionFactory) {
|
||||
super();
|
||||
this.keepAlive = keepAlive;
|
||||
this.shouldRun = shouldRun;
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
log.info("启动SurfaceVision心跳及检测心跳线程");
|
||||
|
||||
while (shouldRun != null && shouldRun.get() == true) {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
List<IoSession> sessions = sessionFactory.getSessions();
|
||||
|
||||
for (IoSession ioSession : sessions) {
|
||||
SurfaceVisionIoSession session = (SurfaceVisionIoSession)ioSession;
|
||||
log.info("{} 定时心跳发送检测", session.gwPrefix());
|
||||
session.sendBeat();
|
||||
|
||||
// 超出指定倍数心跳时间,关闭通道
|
||||
if((now - session.getLastAliveTime()) > (multiply * keepAlive * 1000)) {
|
||||
session.close();
|
||||
log.warn("{} 超出指定倍数{}心跳时间{},单位秒,关闭通道",
|
||||
session.gwPrefix(), multiply, keepAlive);
|
||||
}
|
||||
}
|
||||
|
||||
Thread.sleep(sleepInternal);
|
||||
} catch (Exception e) {
|
||||
log.warn(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("结束SurfaceVision保活超时检测线程");
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.cisdi.data.AMETEKSurfaceVision.gateway;
|
||||
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractChannelInitializer;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoChannelHandler;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultIoChannelHandler;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 表检仪协议通道初始化
|
||||
*
|
||||
* @author tzz
|
||||
*/
|
||||
public class SurfaceVisionChannelInitializer<I> extends AbstractChannelInitializer<I> {
|
||||
private SessionFactory factory;
|
||||
|
||||
/**
|
||||
* 构造通道初始化器对象
|
||||
* @param factory 会话工厂
|
||||
*/
|
||||
public SurfaceVisionChannelInitializer(SessionFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected AbstractIoChannelHandler<I> getTailHandler() {
|
||||
return new DefaultIoChannelHandler(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ChannelHandler> getHandlers() {
|
||||
List<ChannelHandler> handlers = new ArrayList<ChannelHandler>();
|
||||
handlers.add(new SurfaceVisionFrameDecoder());
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IdleStateHandler getIdleStateHandler() {
|
||||
return new IdleStateHandler(15, 15, 30);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChannelHandler getSslChannelHandler(Channel socketChannel) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package com.cisdi.data.AMETEKSurfaceVision.gateway;
|
||||
|
||||
/**
|
||||
* 存储表检仪协议常量信息
|
||||
*
|
||||
* @author tzz
|
||||
*/
|
||||
public final class SurfaceVisionConstants {
|
||||
|
||||
//下发命令返回消息头类型
|
||||
|
||||
/**
|
||||
* 非Query类型命令下发返回消息头,使用starWith判断
|
||||
*/
|
||||
public static final String RETURN_HEADER1 = "REPLY_";
|
||||
/**
|
||||
* 默认下发返回消息头(应为下发命令报错时消息返回头),使用equals判断
|
||||
*/
|
||||
public static final String RETURN_HEADER2 = "REPLY";
|
||||
/**
|
||||
* Query类型命令下发返回消息头,使用equals判断
|
||||
*/
|
||||
public static final String RETURN_HEADER3 = "RESULT";
|
||||
|
||||
|
||||
/**
|
||||
* 命令下发返回成功状态值,ok代表成功
|
||||
*/
|
||||
public static final String RETURN_OK = "OK";
|
||||
|
||||
/**
|
||||
* 消息分隔符
|
||||
*/
|
||||
public static final String SEPARATE1 = "\\|";
|
||||
|
||||
/**
|
||||
* 消息分隔符
|
||||
*/
|
||||
public static final char SEPARATE = '|';
|
||||
|
||||
/**
|
||||
* 消息结束符(除|以外)
|
||||
*/
|
||||
public static final char[] END = {'$','\r','\n'};
|
||||
|
||||
/**
|
||||
* Query类型命令下发消息头,使用starWith判断
|
||||
*/
|
||||
public static final String QUERY = "QUERY";
|
||||
|
||||
/**
|
||||
* 下发命令计数器最大值
|
||||
*/
|
||||
public static final int MAX_COUNT = 100;
|
||||
|
||||
/**
|
||||
* 下发命令正常返回消息最小字段数
|
||||
*/
|
||||
public static final int MIN_NORMAL_RETURN = 3;
|
||||
|
||||
/**
|
||||
* 下发命令数据KEY
|
||||
*/
|
||||
public static final String S_V_SEND_DATA = "surfaceVisionSendData";
|
||||
|
||||
/**
|
||||
* 返回给平台数据KEY
|
||||
*/
|
||||
public static final String S_V_SEND_PLATFORM_DATA = "surfaceVisionSendPlatformData";
|
||||
|
||||
/** 心跳符,$的16进制 */
|
||||
public static final byte BEAT_BYTE = 0x07;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.cisdi.data.AMETEKSurfaceVision.gateway;
|
||||
|
||||
import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO.PropertyConfig;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 表检仪编码
|
||||
*
|
||||
* @author zhongda
|
||||
*/
|
||||
public class SurfaceVisionEncoder {
|
||||
|
||||
/**
|
||||
* 下发命令编码
|
||||
* @param msgKey 消息头,也是平台电文ID
|
||||
* @param propsMap 下发消息
|
||||
* @param propertyConfigList 下发消息点位配置表
|
||||
* @param count 下发消息replayId
|
||||
*/
|
||||
public static ByteBuf Encode(String msgKey, Map<String, Object> propsMap, List<PropertyConfig> propertyConfigList, int count) {
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
//组装消息头
|
||||
stringBuffer.append(msgKey).append(SurfaceVisionConstants.SEPARATE);
|
||||
//非Query命令添加replayId
|
||||
if (!msgKey.startsWith(SurfaceVisionConstants.QUERY)){
|
||||
stringBuffer.append(count).append(SurfaceVisionConstants.SEPARATE);
|
||||
}
|
||||
//组装消息体
|
||||
for (PropertyConfig propertyConfig : propertyConfigList){
|
||||
String key = propertyConfig.getPropertyId();
|
||||
stringBuffer.append(propsMap.get(key))
|
||||
.append(SurfaceVisionConstants.SEPARATE);
|
||||
}
|
||||
//组装消息结尾
|
||||
stringBuffer.append(String.valueOf(SurfaceVisionConstants.END));
|
||||
|
||||
//UTF_8编码下发消息
|
||||
byte[] bytes = stringBuffer.toString().getBytes(StandardCharsets.UTF_8);
|
||||
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(bytes);
|
||||
|
||||
return wrappedBuffer;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.cisdi.data.AMETEKSurfaceVision.gateway;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 表检仪协议帧解码
|
||||
*
|
||||
* @author tzz
|
||||
*/
|
||||
public class SurfaceVisionFrameDecoder extends ByteToMessageDecoder {
|
||||
/** 结束符除|第一位,$的16进制 */
|
||||
private byte end = 0x24;
|
||||
/** 结束符除|第二位,\r的16进制 */
|
||||
private byte end1 = 0x0D;
|
||||
/** 结束符除|第三位,\n的16进制 */
|
||||
private byte end2 = 0x0A;
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf bufferIn, List<Object> out) throws Exception {
|
||||
if (bufferIn.readableBytes() < 1){
|
||||
return;
|
||||
}
|
||||
final int beginIndex = bufferIn.readerIndex();
|
||||
|
||||
int length = 0;
|
||||
for (int i = 0; i + 2 < bufferIn.readableBytes(); i += 1) {
|
||||
byte curByte = bufferIn.getByte(beginIndex + i);
|
||||
|
||||
//判断是否为结束符,若为结束符读取从beginIndex开始的所有数据
|
||||
if (curByte == end){
|
||||
if (end1 == bufferIn.getByte(beginIndex + i + 1) &&
|
||||
end2 == bufferIn.getByte(beginIndex + i + 2)){
|
||||
length = i + 3;
|
||||
byte[] bytes = new byte[i+3];
|
||||
bufferIn.readBytes(bytes);
|
||||
|
||||
ByteBuf copiedBuff = Unpooled.copiedBuffer(bytes);
|
||||
out.add(copiedBuff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i + 3 == bufferIn.readableBytes()){
|
||||
return;
|
||||
}
|
||||
}
|
||||
//若未结束,重置读索引
|
||||
bufferIn.readerIndex(beginIndex + length);
|
||||
|
||||
//解决可能得粘包和拆包问题
|
||||
decode(ctx, bufferIn, out);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package com.cisdi.data.AMETEKSurfaceVision.gateway;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author tzz
|
||||
*/
|
||||
@ToString
|
||||
public class SurfaceVisionFrameInputVo {
|
||||
/** 电文ID */
|
||||
private String msgKey;
|
||||
/** 下发命令返回ID */
|
||||
private Integer ReplayId;
|
||||
/** 下发命令返回状态值,true:成功,false:失败 */
|
||||
private Boolean status;
|
||||
/** 下发命令返回描述 */
|
||||
private String description;
|
||||
/** 是否为心跳信息 */
|
||||
private Boolean beatType = false;
|
||||
/** 通过命令上传的返回的数据值,按照顺序填入 */
|
||||
private List<String> data;
|
||||
/** 通过命令上传的返回的数据值与配置点位的点位id对应,按照顺序对应 */
|
||||
private Map<String, Object> returnData;
|
||||
|
||||
public String getMsgKey() {
|
||||
return msgKey;
|
||||
}
|
||||
|
||||
public Integer getReplayId() {
|
||||
return ReplayId;
|
||||
}
|
||||
|
||||
public Boolean getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public List<String> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public Boolean getBeatType() {
|
||||
return beatType;
|
||||
}
|
||||
|
||||
public Map<String, Object> getReturnData() {
|
||||
return returnData;
|
||||
}
|
||||
|
||||
public void setReturnData(Map<String, Object> returnData) {
|
||||
this.returnData = returnData;
|
||||
}
|
||||
|
||||
public void setBeatType(Boolean beatType) {
|
||||
this.beatType = beatType;
|
||||
}
|
||||
|
||||
public void setMsgKey(String msgKey) {
|
||||
this.msgKey = msgKey;
|
||||
}
|
||||
|
||||
public void setReplayId(Integer replayId) {
|
||||
ReplayId = replayId;
|
||||
}
|
||||
|
||||
public void setStatus(Boolean status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public void setData(List<String> data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
@ -0,0 +1,291 @@
|
||||
package com.cisdi.data.AMETEKSurfaceVision.gateway;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO;
|
||||
import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO.PropertyConfig;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.gateway.message.SocketMessage;
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoSession;
|
||||
import com.cisdi.data.sdk.service.DynamicCodecService;
|
||||
import com.cisdi.data.sdk.service.SendService;
|
||||
import com.cisdi.data.sdk.service.Service;
|
||||
import com.cisdi.data.sdk.vo.ExeResultVo;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 表检仪协议会话
|
||||
*
|
||||
* @author tzz
|
||||
*/
|
||||
public class SurfaceVisionIoSession extends AbstractIoSession implements IoSession {
|
||||
private long lastAliveTime = System.currentTimeMillis();
|
||||
private static Logger logger = LoggerFactory.getLogger(SurfaceVisionIoSession.class);
|
||||
private String deviceId = null;
|
||||
private String gwPrefixCache = null;
|
||||
private final static byte[] beat = {0x07,0x7C,0x24,0x0D,0x0A};
|
||||
|
||||
private int count = 1;
|
||||
// 初始化为0的原子整型变量作为计数器,用作发送命令的replayId,初始值为1
|
||||
|
||||
/** 当前下发命令replayId */
|
||||
private Integer currentCount = -1;
|
||||
|
||||
public void setCurrentSend(SurfaceVisionSocketReturnMessage currentSend) {
|
||||
this.currentSend = currentSend;
|
||||
}
|
||||
|
||||
/** 当前下发命令信息 */
|
||||
private SurfaceVisionSocketReturnMessage currentSend = null;
|
||||
|
||||
public void increment() {
|
||||
if (count < SurfaceVisionConstants.MAX_COUNT) {
|
||||
count++;
|
||||
// 自增1并返回新值
|
||||
}
|
||||
else {
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
// 获取当前计数器的值
|
||||
}
|
||||
|
||||
|
||||
public SurfaceVisionIoSession(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDeviceIds() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
/** 获取当前下发电文点位配置信息 */
|
||||
private List<PropertyConfig> getPropertyConfig(String msgKeyName){
|
||||
//获取DynamicService
|
||||
Service service = serviceProvider.getByName(ServiceName.DynamicCodec);
|
||||
if (service == null || !(service instanceof DynamicCodecService)) {
|
||||
throw new BusinessException("获取DynamicService失败");
|
||||
}
|
||||
|
||||
//获取网关ID
|
||||
String runId = socketGateway.getInstanceVo().getRunId();
|
||||
|
||||
//获取点位配置信息
|
||||
DynamicCodecService dynamicCodecService = (DynamicCodecService)service;
|
||||
String actionParam = dynamicCodecService.findByRunIdAndMsgKey(runId, msgKeyName);
|
||||
DynamicCodeActionParamDTO dto = null;
|
||||
try {
|
||||
dto = JSON.parseObject(actionParam, DynamicCodeActionParamDTO.class);
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException("连接id:" + runId + "电文号:" + msgKeyName + "json转换错误", e);
|
||||
}
|
||||
|
||||
if (dto == null || dto.getPropertyList() == null || dto.getPropertyList().isEmpty()) {
|
||||
throw new BusinessException("连接id:" + runId + "电文号:" + msgKeyName + "属性列表为空");
|
||||
}
|
||||
|
||||
//返回点位信息
|
||||
return dto.getPropertyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRead(Object message) {
|
||||
//获取表检仪上送或返回消息
|
||||
ByteBuf inBuf = (ByteBuf) message;
|
||||
|
||||
int length = inBuf.readableBytes();
|
||||
|
||||
//将消息头和消息体拆包,解析出消息头信息
|
||||
SurfaceVisionFrameInputVo vo = SurfaceVisionVoDecoder.Decode(inBuf);
|
||||
logger.info("AMETEKSurfaceVision收到 msg: {}", vo);
|
||||
|
||||
//消息头,也是电文信息
|
||||
String msgKey = vo.getMsgKey();
|
||||
|
||||
try {
|
||||
//通过消息头判断返回消息类型
|
||||
if(vo.getBeatType()){
|
||||
//判断是否心跳信息
|
||||
lastAliveTime = System.currentTimeMillis();
|
||||
logger.info("接收到心跳消息,当前时间为:{}", lastAliveTime);
|
||||
} else if (msgKey.startsWith(SurfaceVisionConstants.RETURN_HEADER1)) {
|
||||
//非Query命令正常返回消息
|
||||
//解码
|
||||
SurfaceVisionVoDecoder.DecodeReturn(vo);
|
||||
|
||||
//组装返回信息,判断replayId是否一致
|
||||
ExeResultVo sendResult = new ExeResultVo();
|
||||
if (!currentCount.equals(vo.getReplayId())) {
|
||||
logger.info("AMETEKSurfaceVision收到 msgkey: {} 消息:{}, ReplayId:{} 与实际发送下去的:{},不一致"
|
||||
, msgKey, vo, vo.getReplayId(), currentCount);
|
||||
sendResult.setSuccess(false);
|
||||
sendResult.setMessage("返回消息replayId与发送消息replayId不符");
|
||||
} else {
|
||||
sendResult.setSuccess(vo.getStatus());
|
||||
sendResult.setMessage(vo.getDescription());
|
||||
}
|
||||
|
||||
//组装返回结果
|
||||
returnData(sendResult);
|
||||
} else if (SurfaceVisionConstants.RETURN_HEADER2.equals(msgKey)) {
|
||||
//下发命令异常返回消息
|
||||
//解码
|
||||
SurfaceVisionVoDecoder.DecodeReturnError(vo);
|
||||
|
||||
ExeResultVo sendResult = new ExeResultVo();
|
||||
sendResult.setSuccess(vo.getStatus());
|
||||
sendResult.setMessage(vo.getDescription());
|
||||
|
||||
//组装返回结果
|
||||
returnData(sendResult);
|
||||
} else if (SurfaceVisionConstants.RETURN_HEADER3.equals(msgKey)) {
|
||||
//Query命令返回
|
||||
//解码
|
||||
SurfaceVisionVoDecoder.DecodeReturnQuery(vo);
|
||||
|
||||
ExeResultVo sendResult = new ExeResultVo();
|
||||
sendResult.setSuccess(vo.getStatus());
|
||||
sendResult.setMessage(vo.getDescription());
|
||||
|
||||
Map<Object, Object> queryData = new HashMap<>();
|
||||
queryData.putAll(vo.getReturnData());
|
||||
sendResult.setData(queryData);
|
||||
|
||||
//组装返回结果
|
||||
returnData(sendResult);
|
||||
} else {
|
||||
//主动上报消息
|
||||
//解码
|
||||
SurfaceVisionVoDecoder.DecodeData(vo, getPropertyConfig(msgKey));
|
||||
Map<String, Object> realDataMap = vo.getReturnData();
|
||||
|
||||
//数据发送到平台
|
||||
if (vo != null && serviceProvider != null && socketGateway != null) {
|
||||
SendService service = (SendService) serviceProvider.getByName(ServiceName.Send);
|
||||
|
||||
//组装数据包
|
||||
SocketMessage socketMessage = socketGateway.buildSocketMessage();
|
||||
socketMessage.setDeviceId(deviceId);
|
||||
|
||||
socketMessage.getPropsMap().put(SurfaceVisionConstants.S_V_SEND_PLATFORM_DATA, realDataMap);
|
||||
|
||||
socketMessage.setMsgKey(msgKey);
|
||||
|
||||
//发送数据
|
||||
service.sendMessage(socketMessage);
|
||||
} else {
|
||||
logger.info("AMETEKSurfaceVision收到 msgkey: {} 消息:{}, 但是不能发到平台", msgKey, JSON.toJSONString(realDataMap));
|
||||
}
|
||||
}
|
||||
}catch (Exception e){
|
||||
logger.error("AMETEKSurfaceVision接收消息匹配错误, msgKey: {}, msg:{}, error", msgKey, vo, e);
|
||||
}
|
||||
|
||||
if(socketGateway!= null && Boolean.TRUE.equals(socketGateway.getInstanceVo().getLogOpen())) {
|
||||
logger.info("AMETEKSurfaceVision {} 报文长度:{} vo:{} ", getChannel(), length, JSON.toJSONString(vo));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** 设置当前下发命令返回信息 */
|
||||
private void returnData(ExeResultVo sendResult) {
|
||||
if(currentSend == null){
|
||||
throw new BusinessException("下发返回消息没有对应的下发命令");
|
||||
}
|
||||
currentSend.setRealData(sendResult);
|
||||
currentSend.setSendReturnFlag(true);
|
||||
currentSend = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen() {
|
||||
super.onOpen();
|
||||
logger.info("建立连接,channel:{}", getChannel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if(getChannel() != null) {
|
||||
try {
|
||||
getChannel().close().sync();
|
||||
} catch (InterruptedException e) {
|
||||
logger.warn(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String gwPrefix() {
|
||||
if(gwPrefixCache != null) {
|
||||
return gwPrefixCache;
|
||||
}
|
||||
|
||||
gwPrefixCache = "";
|
||||
if(socketGateway != null && socketGateway.getInstanceVo() != null) {
|
||||
gwPrefixCache = "网关Id:" + socketGateway.getInstanceVo().getRunId() + "连接:" + getChannel() + " ";
|
||||
}else {
|
||||
gwPrefixCache = "连接:" + getChannel() + " ";
|
||||
}
|
||||
|
||||
return gwPrefixCache;
|
||||
}
|
||||
|
||||
public long getLastAliveTime() {
|
||||
return lastAliveTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Object message) {
|
||||
//下发命令
|
||||
SurfaceVisionSocketReturnMessage returnMsg = (SurfaceVisionSocketReturnMessage) message;
|
||||
String msgKey = returnMsg.getMsgKey();
|
||||
|
||||
//与AMETEKSurfaceVisionSocketProtocol类对应
|
||||
Map<String, Object> propsMap = (Map<String, Object>)
|
||||
returnMsg.getPropsMap().get(SurfaceVisionConstants.S_V_SEND_DATA);
|
||||
|
||||
//获取下发点位配置
|
||||
List<PropertyConfig> propertyConfigList = getPropertyConfig(msgKey);
|
||||
|
||||
//获取计数器值作为下发命令replayId
|
||||
int c = getCount();
|
||||
logger.info("下发数据, 数据:{}, 点位配置:{}, 返回ID:{}", propsMap, propertyConfigList, c);
|
||||
|
||||
ByteBuf byteBuf = SurfaceVisionEncoder.Encode(msgKey, propsMap, propertyConfigList, c);
|
||||
logger.info("下发数据的byteBuf:{}", byteBuf);
|
||||
|
||||
//下发命令编码后发送
|
||||
getChannel().writeAndFlush(byteBuf);
|
||||
|
||||
logger.info("下发数据成功");
|
||||
|
||||
//缓存当前下发命令信息和replayId
|
||||
currentSend = returnMsg;
|
||||
currentCount = c;
|
||||
|
||||
//计数器自增
|
||||
increment();
|
||||
}
|
||||
|
||||
public void sendBeat() {
|
||||
logger.info("发送心跳");
|
||||
ByteBuf byteBuf = Unpooled.wrappedBuffer(beat);
|
||||
getChannel().writeAndFlush(byteBuf);
|
||||
logger.info("心跳发送成功");
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.cisdi.data.AMETEKSurfaceVision.gateway;
|
||||
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractSessionFactory;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 表检仪协议会话工厂
|
||||
*
|
||||
* @author tzz
|
||||
*/
|
||||
public class SurfaceVisionSessionFactory extends AbstractSessionFactory {
|
||||
private String deviceId;
|
||||
|
||||
public SurfaceVisionSessionFactory(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IoSession newSession() {
|
||||
IoSession session = new SurfaceVisionIoSession(deviceId);
|
||||
session.init(UUID.randomUUID().toString(), provider, socketGateway);
|
||||
sessionSet.add(session);
|
||||
return session;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.cisdi.data.AMETEKSurfaceVision.gateway;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
|
||||
import com.cisdi.data.sdk.vo.ExeResultVo;
|
||||
|
||||
/**
|
||||
* 表检仪协议下发消息及返回信息
|
||||
*
|
||||
* @author tzz
|
||||
*/
|
||||
public class SurfaceVisionSocketReturnMessage extends SocketReturnMessage {
|
||||
/** 下发消息返回消息 */
|
||||
ExeResultVo realData;
|
||||
/** 下发消息返回标志 */
|
||||
boolean sendReturnFlag;
|
||||
|
||||
public SurfaceVisionSocketReturnMessage() {
|
||||
}
|
||||
|
||||
public ExeResultVo getRealData() {
|
||||
return this.realData;
|
||||
}
|
||||
|
||||
public void setRealData(ExeResultVo realData) {
|
||||
this.realData = realData;
|
||||
}
|
||||
|
||||
public boolean getSendReturnFlag() {
|
||||
return this.sendReturnFlag;
|
||||
}
|
||||
|
||||
public void setSendReturnFlag(boolean sendReturnFlag) {
|
||||
this.sendReturnFlag = sendReturnFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
package com.cisdi.data.AMETEKSurfaceVision.gateway;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO.PropertyConfig;
|
||||
import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO.PropertyType;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
/**
|
||||
* 表检仪解码
|
||||
*
|
||||
* @author zhongda
|
||||
*/
|
||||
public class SurfaceVisionVoDecoder {
|
||||
/** 将消息头和消息体拆包,解析出消息头信息 */
|
||||
public static SurfaceVisionFrameInputVo Decode(ByteBuf in) {
|
||||
SurfaceVisionFrameInputVo vo = new SurfaceVisionFrameInputVo();
|
||||
//消息体部分
|
||||
int length;
|
||||
if (in == null) {
|
||||
throw new BusinessException("ByteBuf 入参为null");
|
||||
} else if (in.readableBytes() > 4) {
|
||||
length = in.readableBytes();
|
||||
}
|
||||
else {
|
||||
throw new BusinessException("报文长度不匹配 ,期望:大于4,实际:" + in.readableBytes());
|
||||
}
|
||||
//去掉结束符
|
||||
byte[] headerBytes = new byte[length - 4];
|
||||
in.readBytes(headerBytes);
|
||||
|
||||
//将数据流转为字符串,UTF_8编码
|
||||
String strData = new String(headerBytes, StandardCharsets.UTF_8);
|
||||
|
||||
//以分隔符分割数据
|
||||
List<String> data = Arrays.asList(strData.split(SurfaceVisionConstants.SEPARATE1, -1));
|
||||
|
||||
//获取报文头
|
||||
vo.setMsgKey(data.get(0));
|
||||
|
||||
//去掉报文头
|
||||
vo.setData(data.subList(1, data.size()));
|
||||
|
||||
//判断是否为心跳帧
|
||||
byte[] header = data.get(0).getBytes(StandardCharsets.UTF_8);
|
||||
if (header.length == 1 && header[0] == SurfaceVisionConstants.BEAT_BYTE){
|
||||
vo.setBeatType(true);
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
/** 非Query命令正常返回消息解码 */
|
||||
public static void DecodeReturn(SurfaceVisionFrameInputVo vo) {
|
||||
List<String> data = vo.getData();
|
||||
if (data.size() < SurfaceVisionConstants.MIN_NORMAL_RETURN){
|
||||
throw new BusinessException("返回消息不标准,msg:" + JSON.toJSONString(data));
|
||||
}
|
||||
|
||||
vo.setReplayId(Integer.valueOf(data.get(0)));
|
||||
vo.setStatus(SurfaceVisionConstants.RETURN_OK.equalsIgnoreCase(data.get(1)));
|
||||
vo.setDescription(data.get(2));
|
||||
}
|
||||
|
||||
/** 命令异常返回消息解码 */
|
||||
public static void DecodeReturnError(SurfaceVisionFrameInputVo vo) {
|
||||
List<String> data = vo.getData();
|
||||
int size = data.size();
|
||||
if (size < SurfaceVisionConstants.MIN_NORMAL_RETURN){
|
||||
throw new BusinessException("返回消息不标准,msg:" + JSON.toJSONString(data));
|
||||
}
|
||||
|
||||
StringBuffer message = new StringBuffer();
|
||||
message.append(data.get(size - 1))
|
||||
.append(":")
|
||||
.append(data.get(size - 2));
|
||||
|
||||
vo.setReplayId(0);
|
||||
vo.setStatus(false);
|
||||
vo.setDescription(message.toString());
|
||||
}
|
||||
|
||||
/** Query命令返回消息解码 */
|
||||
public static void DecodeReturnQuery(SurfaceVisionFrameInputVo vo) {
|
||||
List<String> data = vo.getData();
|
||||
int size = data.size();
|
||||
if (size < 2){
|
||||
throw new BusinessException("返回查询消息不标准,msg:" + JSON.toJSONString(data));
|
||||
}
|
||||
|
||||
Map<String, Object> queryData = new HashMap<>();
|
||||
queryData.put("result", data.get(size - 1));
|
||||
|
||||
vo.setReplayId(0);
|
||||
vo.setStatus(true);
|
||||
vo.setReturnData(queryData);
|
||||
}
|
||||
|
||||
/** 上送消息解码 */
|
||||
public static void DecodeData(SurfaceVisionFrameInputVo vo, List<PropertyConfig> propertyConfigs) {
|
||||
List<String> data = vo.getData();
|
||||
|
||||
//判断上送消息字段数是否与点位配置信息字段数一致
|
||||
if (data.size() != propertyConfigs.size()){
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
stringBuffer.append("报文数据字段数与点位配置不一致 ,电文ID:")
|
||||
.append(vo.getMsgKey())
|
||||
.append(",电文字段数:")
|
||||
.append(data.size())
|
||||
.append(", 点位字段数:")
|
||||
.append(propertyConfigs.size());
|
||||
throw new BusinessException(stringBuffer.toString());
|
||||
}
|
||||
|
||||
Map<String, Object> valueMap = new HashMap<>();
|
||||
|
||||
//按照点位配置字段顺序获取上送信息
|
||||
for (int i = 0; i < data.size(); i++){
|
||||
String value = data.get(i);
|
||||
PropertyConfig propertyConfig = propertyConfigs.get(i);
|
||||
|
||||
PropertyType propertyType = propertyConfig.getPropertyType();
|
||||
|
||||
String propertyId = propertyConfig.getPropertyId();
|
||||
|
||||
formatValue(valueMap, value, propertyType, propertyId);
|
||||
}
|
||||
|
||||
vo.setReturnData(valueMap);
|
||||
}
|
||||
|
||||
/** 更具字段类型格式化数据值 */
|
||||
private static void formatValue(Map<String, Object> valueMap, String value, PropertyType propertyType, String propertyId) {
|
||||
switch (propertyType){
|
||||
case INT: {
|
||||
valueMap.put(propertyId, Integer.valueOf(value));
|
||||
break;
|
||||
}
|
||||
case BYTE: {
|
||||
valueMap.put(propertyId, Byte.valueOf(value));
|
||||
break;
|
||||
}
|
||||
case BOOLEAN: {
|
||||
valueMap.put(propertyId, Boolean.valueOf(value));
|
||||
break;
|
||||
}
|
||||
case SHORT: {
|
||||
valueMap.put(propertyId, Short.valueOf(value));
|
||||
break;
|
||||
}
|
||||
case FLOAT: {
|
||||
valueMap.put(propertyId, Float.valueOf(value));
|
||||
break;
|
||||
}
|
||||
case DOUBLE: {
|
||||
valueMap.put(propertyId, Double.valueOf(value));
|
||||
break;
|
||||
}
|
||||
case LONG: {
|
||||
valueMap.put(propertyId, Long.valueOf(value));
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
valueMap.put(propertyId, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
//标签读取
|
||||
SurfaceVisionFrameDecoder surfaceVisionFrameDecoder = new SurfaceVisionFrameDecoder();
|
||||
// String str = "DEFECT|1|3|2011-03-19 15:21:45|2.54|1.73|252.76|$\r\n";
|
||||
//粘包
|
||||
String str = "DEFECT|1|3|2011-03-19 15:21:45||1.23||$\r\nDEFECT|1|3|2011-03-19 15:21:45||1.23||";
|
||||
// String str = "DEFECT|1|3|2011-03-19 15:21:45|2.54|1.73|252.76|$\r\n";
|
||||
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
|
||||
ByteBuf copiedBuff = Unpooled.copiedBuffer(bytes);
|
||||
List<Object> out = new ArrayList<Object>();
|
||||
surfaceVisionFrameDecoder.decode(null, copiedBuff, out);
|
||||
|
||||
ByteBuf bufferIn = (ByteBuf) out.get(0);
|
||||
|
||||
SurfaceVisionFrameInputVo vo = Decode(bufferIn);
|
||||
String msgKey = vo.getMsgKey();
|
||||
|
||||
SocketReturnMessage returnMsg = new SocketReturnMessage();
|
||||
returnMsg.setMsgKey("1");
|
||||
returnMsg.setMsgId("2");
|
||||
returnMsg.setData(new byte[3]);
|
||||
|
||||
SurfaceVisionSocketReturnMessage sendMsg = new SurfaceVisionSocketReturnMessage();
|
||||
BeanUtils.copyProperties(returnMsg, sendMsg);
|
||||
|
||||
sendMsg.setSendReturnFlag(true);
|
||||
|
||||
String msgKey1 = "test";
|
||||
Map<String, Object> propsMap = new HashMap<>();
|
||||
propsMap.put("id1", 1);
|
||||
propsMap.put("id2", 2.33);
|
||||
propsMap.put("id3", "value");
|
||||
List<PropertyConfig> propertyConfigList = new ArrayList<>();
|
||||
PropertyConfig propertyConfig1 = new PropertyConfig();
|
||||
propertyConfig1.setPropertyId("id1");
|
||||
propertyConfigList.add(propertyConfig1);
|
||||
PropertyConfig propertyConfig2 = new PropertyConfig();
|
||||
propertyConfig2.setPropertyId("id2");
|
||||
propertyConfigList.add(propertyConfig2);
|
||||
PropertyConfig propertyConfig3 = new PropertyConfig();
|
||||
propertyConfig3.setPropertyId("id3");
|
||||
propertyConfigList.add(propertyConfig3);
|
||||
int count = 1;
|
||||
|
||||
SurfaceVisionEncoder.Encode(msgKey1, propsMap, propertyConfigList, count);
|
||||
}
|
||||
|
||||
|
||||
}
|
354
src/main/java/com/cisdi/data/DHV/YFDHealthVibrationGateway.java
Normal file
354
src/main/java/com/cisdi/data/DHV/YFDHealthVibrationGateway.java
Normal file
@ -0,0 +1,354 @@
|
||||
package com.cisdi.data.DHV;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.cisdi.data.DHV.gateway.vo.dhv.OtherParamVO;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.enums.GatewayState;
|
||||
import com.cisdi.data.sdk.gateway.base.PulledHttpGatewayBase;
|
||||
import com.cisdi.data.sdk.param.PullHttpParam;
|
||||
import com.cisdi.data.sdk.procotol.message.HttpReturnMessage;
|
||||
import com.cisdi.data.sdk.service.RouteService;
|
||||
import com.cisdi.data.sdk.vo.DeviceVo;
|
||||
import com.cisdi.data.sdk.vo.ExeResultVo;
|
||||
import com.cisdi.data.DHV.gateway.impl.dhv.YFDHVPullTask;
|
||||
import com.cisdi.data.DHV.gateway.vo.PullHttpTaskStartVo;
|
||||
import com.cisdi.data.DHV.gateway.vo.dhv.MPSVO;
|
||||
import com.cisdi.data.DHV.gateway.vo.dhv.MPVVO;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* @author jianghc
|
||||
* @function: YFDHealthVibrationGateway永锋现场-设备健康振动数据接入网关,入口
|
||||
* @date 2022年05月05日 09:29
|
||||
*/
|
||||
public class YFDHealthVibrationGateway extends PulledHttpGatewayBase {
|
||||
private static Logger logger = LoggerFactory.getLogger(YFDHealthVibrationGateway.class);
|
||||
|
||||
//设备id
|
||||
private String deviceId;
|
||||
//设备当前是否运行
|
||||
private AtomicBoolean shouldRun = null;
|
||||
// 允许最小的拉取间隔为1毫秒
|
||||
private static final int Min_Pull_Internal = 1;
|
||||
// 允许最小的超时时间间隔,为1000毫秒
|
||||
private static final int Min_Timeout = 1000;
|
||||
|
||||
|
||||
@Override
|
||||
public ExeResultVo sendReturnMessage(HttpReturnMessage httpReturnMessage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (state == GatewayState.RUNNING) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
startInternal();
|
||||
state = GatewayState.RUNNING;
|
||||
logger.info("永峰设备健康振动数据http拉取网关:{}启动成功", instanceVo.getRunId());
|
||||
} catch (Exception e) {
|
||||
logger.error("永峰设备健康振动数据http拉取网关:{}启动失败", instanceVo.getRunId());
|
||||
logger.error(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void startInternal() {
|
||||
httpParam = JSON.parseObject(instanceVo.getParameter(), PullHttpParam.class);
|
||||
|
||||
if (StringUtils.isEmpty(httpParam.getPullLocation())) {
|
||||
throw new BusinessException("未正确配置拉取地址。");
|
||||
}
|
||||
|
||||
if (httpParam.getPullInternal() == null) {
|
||||
throw new BusinessException("未正确配置拉取间隔");
|
||||
}
|
||||
|
||||
if (httpParam.getTimeout() == null) {
|
||||
throw new BusinessException("未正确配置拉取超时时间");
|
||||
}
|
||||
|
||||
httpParam.setPullInternal(httpParam.getPullInternal() < Min_Pull_Internal ?
|
||||
Min_Pull_Internal : httpParam.getPullInternal());
|
||||
|
||||
httpParam.setTimeout(httpParam.getTimeout() < Min_Timeout ? Min_Timeout : httpParam.getTimeout());
|
||||
|
||||
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
|
||||
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
|
||||
|
||||
if (deviceVos.size() > 1) {
|
||||
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为永峰设备健康振动数据http拉取网关,只允许关联一个设备Id");
|
||||
}
|
||||
|
||||
deviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
|
||||
|
||||
logger.info("永峰设备健康振动数据http拉取网关:{}读取启动配置参数:{}", getInstanceVo().getRunId(), httpParam);
|
||||
|
||||
closePrevState();
|
||||
shouldRun = new AtomicBoolean(true);
|
||||
|
||||
// DynamicCodecService dynamicCodecService = (DynamicCodecService) serviceProvider.getByName(ServiceName.DynamicCodec);
|
||||
// if (dynamicCodecService == null || !(dynamicCodecService instanceof DynamicCodecService)) {
|
||||
// throw new BusinessException("获取JDynamicCodecService失败");
|
||||
// }
|
||||
// String tagConfig = dynamicCodecService.findByRunIdAndMsgKeyNoCache(getInstanceVo().getRunId(),"mps.MPS");
|
||||
// if (Strings.isEmpty(tagConfig)) {
|
||||
// throw new BusinessException("未正确配置当前DHV所需配置");
|
||||
// }else{
|
||||
// logger.info("点位配置信息:"+tagConfig);
|
||||
// }
|
||||
|
||||
|
||||
// 启动线程
|
||||
PullHttpTaskStartVo startVo = new PullHttpTaskStartVo();
|
||||
startVo.setDeviceId(deviceId);
|
||||
startVo.setGatewayBase(this);
|
||||
startVo.setServiceProvider(serviceProvider);
|
||||
startVo.setHttpParam(httpParam);
|
||||
startVo.setShouldRun(shouldRun);
|
||||
|
||||
//其他参数
|
||||
OtherParamVO otherParamVO = null;
|
||||
if (httpParam.getOtherParameter() != null && httpParam.getOtherParameter().trim().length() > 0) {
|
||||
String otherParameter = httpParam.getOtherParameter();
|
||||
otherParamVO = parseOtherParameter(otherParameter);
|
||||
} else {
|
||||
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
|
||||
}
|
||||
|
||||
// 启动拉取ids的线程
|
||||
YFDHVPullTask idsTask = new YFDHVPullTask(startVo, otherParamVO);
|
||||
Thread idsThread = new Thread(idsTask, "永峰-设备健康振动数据网关");
|
||||
idsThread.start();
|
||||
|
||||
state = GatewayState.RUNNING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param otherParameter
|
||||
* @return com.cisdi.data.yongfeng.gateway.vo.dhv.OtherParamVO
|
||||
* @function: 解析其他参数
|
||||
* @author jianghc
|
||||
* @date 2022/5/6 16:41
|
||||
*/
|
||||
private OtherParamVO parseOtherParameter(String otherParameter) {
|
||||
MPSVO mpsvo = new MPSVO();
|
||||
List<MPVVO> mpvvoList = new ArrayList<>();
|
||||
JSONObject jsonObject = null;
|
||||
try {
|
||||
jsonObject = JSONObject.parseObject(otherParameter);
|
||||
} catch (Exception ex) {
|
||||
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
|
||||
}
|
||||
Object obj = jsonObject.get("mps");
|
||||
if (obj != null && obj instanceof JSONObject) {
|
||||
JSONObject databaseName = (JSONObject) obj;
|
||||
Object dbNames = databaseName.get("databaseName");
|
||||
if (dbNames instanceof JSONArray) {
|
||||
JSONArray jsonArray = (JSONArray) dbNames;
|
||||
List<String> dbNameList = new ArrayList<>();
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
dbNameList.add((String) jsonArray.get(i));
|
||||
}
|
||||
mpsvo.setDatabaseName(dbNameList);
|
||||
} else if (dbNames instanceof String) {
|
||||
List<String> dbNameList = new ArrayList<>();
|
||||
dbNameList.add((String) dbNames);
|
||||
mpsvo.setDatabaseName(dbNameList);
|
||||
}
|
||||
}
|
||||
Object obj1 = jsonObject.get("mpv");
|
||||
if (obj1 != null && obj1 instanceof JSONArray) {
|
||||
JSONArray jsonArray = (JSONArray) obj1;
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
JSONObject obj2 = (JSONObject) jsonArray.get(i);
|
||||
MPVVO mpvvo = new MPVVO();
|
||||
String databaseName = obj2.getString("databaseName");
|
||||
if (databaseName != null && databaseName.trim().length() > 0) {
|
||||
mpvvo.setDatabaseName(databaseName);
|
||||
} else {
|
||||
mpvvo.setDatabaseName(null);
|
||||
}
|
||||
String measuringPointNumberOrTechID = obj2.getString("measuringPointNumberOrTechID");
|
||||
if (measuringPointNumberOrTechID != null && measuringPointNumberOrTechID.trim().length() > 0) {
|
||||
mpvvo.setMeasuringPointNumberOrTechID(measuringPointNumberOrTechID);
|
||||
} else {
|
||||
if (databaseName != null && databaseName.trim().length() > 0) {
|
||||
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
|
||||
}
|
||||
mpvvo.setMeasuringPointNumberOrTechID(null);
|
||||
}
|
||||
String assignmentTechIDorName = obj2.getString("assignmentTechIDorName");
|
||||
if (assignmentTechIDorName != null && assignmentTechIDorName.trim().length() > 0) {
|
||||
mpvvo.setAssignmentTechIDorName(assignmentTechIDorName);
|
||||
} else {
|
||||
if (databaseName != null && databaseName.trim().length() > 0) {
|
||||
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
|
||||
}
|
||||
mpvvo.setAssignmentTechIDorName(null);
|
||||
}
|
||||
Boolean ShortMem = obj2.getBoolean("ShortMem");
|
||||
if (ShortMem != null && ShortMem.equals(Boolean.TRUE)) {
|
||||
mpvvo.setShortMem(Boolean.TRUE);
|
||||
} else if (ShortMem != null && ShortMem.equals(Boolean.FALSE)) {
|
||||
mpvvo.setShortMem(Boolean.FALSE);
|
||||
} else {
|
||||
mpvvo.setShortMem(null);
|
||||
}
|
||||
mpvvo.setMaxCount(obj2.getInteger("MaxCount"));
|
||||
Boolean LongMem = obj2.getBoolean("LongMem");
|
||||
if (LongMem != null && LongMem.equals(Boolean.TRUE)) {
|
||||
mpvvo.setLongMem(Boolean.TRUE);
|
||||
} else if (LongMem != null && LongMem.equals(Boolean.FALSE)) {
|
||||
mpvvo.setLongMem(Boolean.FALSE);
|
||||
} else {
|
||||
mpvvo.setLongMem(null);
|
||||
}
|
||||
String StartDateTime = obj2.getString("StartDateTime");
|
||||
if (StartDateTime != null && StartDateTime.trim().length() > 0) {
|
||||
mpvvo.setStartDateTime(StartDateTime);
|
||||
} else {
|
||||
mpvvo.setStartDateTime(null);
|
||||
}
|
||||
String StopDateTime = obj2.getString("StopDateTime");
|
||||
if (StopDateTime != null && StopDateTime.trim().length() > 0) {
|
||||
mpvvo.setStopDateTime(StopDateTime);
|
||||
} else {
|
||||
mpvvo.setStopDateTime(null);
|
||||
}
|
||||
mpvvo.setMpktTech(obj2.getInteger("MpktTech"));
|
||||
String Expand = obj2.getString("Expand");
|
||||
if (Expand != null && Expand.trim().length() > 0) {
|
||||
mpvvo.setExpand(Expand);
|
||||
} else {
|
||||
mpvvo.setExpand(null);
|
||||
}
|
||||
mpvvoList.add(mpvvo);
|
||||
}
|
||||
} else if (obj1 != null && obj1 instanceof JSONObject) {
|
||||
JSONObject obj2 = (JSONObject) obj1;
|
||||
MPVVO mpvvo = new MPVVO();
|
||||
String databaseName = obj2.getString("databaseName");
|
||||
if (databaseName != null && databaseName.trim().length() > 0) {
|
||||
mpvvo.setDatabaseName(databaseName);
|
||||
} else {
|
||||
mpvvo.setDatabaseName(null);
|
||||
}
|
||||
String measuringPointNumberOrTechID = obj2.getString("measuringPointNumberOrTechID");
|
||||
if (measuringPointNumberOrTechID != null && measuringPointNumberOrTechID.trim().length() > 0) {
|
||||
mpvvo.setMeasuringPointNumberOrTechID(measuringPointNumberOrTechID);
|
||||
} else {
|
||||
if (databaseName != null && databaseName.trim().length() > 0) {
|
||||
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
|
||||
}
|
||||
mpvvo.setMeasuringPointNumberOrTechID(null);
|
||||
}
|
||||
String assignmentTechIDorName = obj2.getString("assignmentTechIDorName");
|
||||
if (assignmentTechIDorName != null && assignmentTechIDorName.trim().length() > 0) {
|
||||
mpvvo.setAssignmentTechIDorName(assignmentTechIDorName);
|
||||
} else {
|
||||
if (databaseName != null && databaseName.trim().length() > 0) {
|
||||
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
|
||||
}
|
||||
mpvvo.setAssignmentTechIDorName(null);
|
||||
}
|
||||
Boolean ShortMem = obj2.getBoolean("ShortMem");
|
||||
if (ShortMem != null && ShortMem.equals(Boolean.TRUE)) {
|
||||
mpvvo.setShortMem(Boolean.TRUE);
|
||||
} else if (ShortMem != null && ShortMem.equals(Boolean.FALSE)) {
|
||||
mpvvo.setShortMem(Boolean.FALSE);
|
||||
} else {
|
||||
mpvvo.setShortMem(null);
|
||||
}
|
||||
mpvvo.setMaxCount(obj2.getInteger("MaxCount"));
|
||||
Boolean LongMem = obj2.getBoolean("LongMem");
|
||||
if (LongMem != null && LongMem.equals(Boolean.TRUE)) {
|
||||
mpvvo.setLongMem(Boolean.TRUE);
|
||||
} else if (LongMem != null && LongMem.equals(Boolean.FALSE)) {
|
||||
mpvvo.setLongMem(Boolean.FALSE);
|
||||
} else {
|
||||
mpvvo.setLongMem(null);
|
||||
}
|
||||
String StartDateTime = obj2.getString("StartDateTime");
|
||||
if (StartDateTime != null && StartDateTime.trim().length() > 0) {
|
||||
mpvvo.setStartDateTime(StartDateTime);
|
||||
} else {
|
||||
mpvvo.setStartDateTime(null);
|
||||
}
|
||||
String StopDateTime = obj2.getString("StopDateTime");
|
||||
if (StopDateTime != null && StopDateTime.trim().length() > 0) {
|
||||
mpvvo.setStopDateTime(StopDateTime);
|
||||
} else {
|
||||
mpvvo.setStopDateTime(null);
|
||||
}
|
||||
mpvvo.setMpktTech(obj2.getInteger("MpktTech"));
|
||||
String Expand = obj2.getString("Expand");
|
||||
if (Expand != null && Expand.trim().length() > 0) {
|
||||
mpvvo.setExpand(Expand);
|
||||
} else {
|
||||
mpvvo.setExpand(null);
|
||||
}
|
||||
mpvvoList.add(mpvvo);
|
||||
}
|
||||
if ((mpsvo.getDatabaseName() == null || mpsvo.getDatabaseName().size() < 1) && (mpvvoList.size() < 1)) {
|
||||
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
|
||||
}
|
||||
String user = jsonObject.getString("user");
|
||||
String pass = jsonObject.getString("pass");
|
||||
String Authorization = null;
|
||||
if (user != null) {
|
||||
Authorization = "Basic " + new String(Base64.getEncoder().encode((user + ":" + pass).getBytes(StandardCharsets.UTF_8)));
|
||||
} else {
|
||||
Authorization = "Basic ";
|
||||
}
|
||||
String emptyanddefault = jsonObject.getString("emptyanddefault");
|
||||
OtherParamVO otherParamVO = new OtherParamVO();
|
||||
otherParamVO.setMpsvo(mpsvo);
|
||||
otherParamVO.setMpvvoList(mpvvoList);
|
||||
otherParamVO.setAuthorization(Authorization);
|
||||
otherParamVO.setEmptyanddefault(emptyanddefault);
|
||||
return otherParamVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (state == GatewayState.CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
closePrevState();
|
||||
|
||||
logger.info("永峰设备健康振动数据http拉取网关:{}关闭中", getInstanceVo().getRunId());
|
||||
|
||||
state = GatewayState.CLOSED;
|
||||
|
||||
logger.info("永峰设备健康振动数据http拉取网关:{}关闭成功", getInstanceVo().getRunId());
|
||||
}
|
||||
|
||||
private void closePrevState() {
|
||||
if (shouldRun != null) {
|
||||
shouldRun.set(false);
|
||||
shouldRun = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getActiveDeviceIds() {
|
||||
Set<String> set = new HashSet<String>();
|
||||
if (deviceId != null) {
|
||||
set.add(deviceId);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
}
|
1523
src/main/java/com/cisdi/data/DHV/doc/readme.md
Normal file
1523
src/main/java/com/cisdi/data/DHV/doc/readme.md
Normal file
File diff suppressed because it is too large
Load Diff
BIN
src/main/java/com/cisdi/data/DHV/doc/现场点位数据信息.xlsx
Normal file
BIN
src/main/java/com/cisdi/data/DHV/doc/现场点位数据信息.xlsx
Normal file
Binary file not shown.
BIN
src/main/java/com/cisdi/data/DHV/doc/设备健康振动协议使用说明.docx
Normal file
BIN
src/main/java/com/cisdi/data/DHV/doc/设备健康振动协议使用说明.docx
Normal file
Binary file not shown.
@ -0,0 +1,42 @@
|
||||
package com.cisdi.data.DHV.gateway.config;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import okhttp3.ConnectionPool;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author jianghc
|
||||
* @function:
|
||||
* @date 2022年05月07日 10:26
|
||||
*/
|
||||
public class YFHttpClient {
|
||||
|
||||
private static Map<Integer, OkHttpClient> map = Maps.newConcurrentMap();
|
||||
|
||||
|
||||
public static OkHttpClient get(Integer timeout) {
|
||||
|
||||
OkHttpClient okHttpClient = map.get(timeout);
|
||||
|
||||
if(okHttpClient != null) {
|
||||
return okHttpClient;
|
||||
}
|
||||
|
||||
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||
builder.connectTimeout(timeout, TimeUnit.MILLISECONDS)
|
||||
.readTimeout(timeout, TimeUnit.MILLISECONDS)
|
||||
.writeTimeout(timeout,TimeUnit.MILLISECONDS)
|
||||
.connectionPool(new ConnectionPool(15, 1, TimeUnit.MINUTES))
|
||||
.retryOnConnectionFailure(true);
|
||||
|
||||
okHttpClient = builder.build();
|
||||
|
||||
map.put(timeout, okHttpClient);
|
||||
|
||||
return okHttpClient;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.cisdi.data.DHV.gateway.impl;
|
||||
|
||||
import com.cisdi.data.DHV.gateway.vo.dhv.OtherParamVO;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.DHV.gateway.vo.PullHttpTaskStartVo;
|
||||
|
||||
/**
|
||||
* @author jianghc
|
||||
* @function:
|
||||
* @date 2022年05月05日 09:37
|
||||
*/
|
||||
public class HttpPullTaskBase {
|
||||
/**
|
||||
* 线程启动参数
|
||||
*/
|
||||
protected PullHttpTaskStartVo startVo = null;
|
||||
|
||||
protected void checkInitParam(PullHttpTaskStartVo taskStartVo, OtherParamVO otherParamVO) {
|
||||
if(taskStartVo.getShouldRun() == null
|
||||
|| taskStartVo.getShouldRun() == null
|
||||
|| taskStartVo.getHttpParam() == null) {
|
||||
throw new BusinessException("永峰设备健康振动数据Http拉取线程启动参数缺失。");
|
||||
}
|
||||
this.startVo = taskStartVo;
|
||||
}
|
||||
}
|
@ -0,0 +1,575 @@
|
||||
package com.cisdi.data.DHV.gateway.impl.dhv;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.cisdi.data.DHV.gateway.config.YFHttpClient;
|
||||
import com.cisdi.data.DHV.gateway.impl.HttpPullTaskBase;
|
||||
import com.cisdi.data.DHV.gateway.vo.PullHttpTaskStartVo;
|
||||
import com.cisdi.data.DHV.gateway.vo.dhv.*;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.gateway.base.PulledHttpGatewayBase;
|
||||
import com.cisdi.data.sdk.gateway.message.HttpMessage;
|
||||
import com.cisdi.data.sdk.gateway.message.Message;
|
||||
import com.cisdi.data.sdk.gateway.message.MessageBatch;
|
||||
import com.cisdi.data.sdk.service.SendService;
|
||||
import com.cisdi.data.sdk.service.ServiceProvider;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Response;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author jianghc
|
||||
* @function:
|
||||
* @date 2022年05月05日 10:32
|
||||
*/
|
||||
public class YFDHVPullTask extends HttpPullTaskBase implements Runnable {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(YFDHVPullTask.class);
|
||||
|
||||
//请求测点状态的URL地址
|
||||
private String[] DHV_MPS_URL = null;
|
||||
|
||||
//获取teachName的URL地址
|
||||
private String[] DHV_MET_URL = null;
|
||||
|
||||
//请求测点总值的URL地址
|
||||
private String[] DHV_MPV_URL = null;
|
||||
|
||||
//测点的ID
|
||||
private String[] measuringPointNumberOrTechIDs = null;
|
||||
|
||||
//base64编码的user:password
|
||||
private String Authorization;
|
||||
|
||||
//DHV请求必须携带的头部参数
|
||||
private String emptyanddefault;
|
||||
|
||||
//超时时间
|
||||
private Integer timeOut;
|
||||
|
||||
//其他参数中配置的数据库
|
||||
private List<String> dbNames;
|
||||
|
||||
//判断当前是否获取了db-测点id-测点方法的一个标志,在网关启动的时候执行一次后变成true,并装入下面三个容器中
|
||||
private boolean metPara = false;
|
||||
private List<String> dbNameList;
|
||||
private List<String> itemIdList;
|
||||
private List<String> methodNameList;
|
||||
|
||||
//连接管理中的拉取地址,以上所有的URL地址都是用这个地址为前缀拼接成的
|
||||
private String url;
|
||||
|
||||
public YFDHVPullTask(PullHttpTaskStartVo pullHttpTaskStartVo, OtherParamVO otherParamVO) {
|
||||
checkInitParam(pullHttpTaskStartVo, otherParamVO);
|
||||
|
||||
url = startVo.getHttpParam().getPullLocation();
|
||||
if (url == null) {
|
||||
logger.error("拉取地址不能为空!");
|
||||
throw new BusinessException("拉取地址不能为空!");
|
||||
}
|
||||
if (url.endsWith("/")) {
|
||||
url = url.substring(0, url.length() - 1);
|
||||
}
|
||||
|
||||
dbNames = otherParamVO.getMpsvo().getDatabaseName();
|
||||
int dbNamesLen = dbNames.size();
|
||||
if (dbNamesLen > 0) {
|
||||
DHV_MPS_URL = new String[dbNamesLen];
|
||||
for (int i = 0; i < dbNamesLen; i++) {
|
||||
DHV_MPS_URL[i] = url + String.format(YFDHV.YF_DHV_MPS, dbNames.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
Authorization = otherParamVO.getAuthorization();
|
||||
|
||||
emptyanddefault = otherParamVO.getEmptyanddefault() == null ? "1" : otherParamVO.getEmptyanddefault();
|
||||
|
||||
timeOut = startVo.getHttpParam().getTimeout();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
OkHttpClient httpClient = YFHttpClient.get(startVo.getHttpParam().getPullInternal());
|
||||
if (DHV_MPS_URL != null) {
|
||||
for (int i = 0; i < DHV_MPS_URL.length; i++) {
|
||||
logger.info("MPS采集地址:" + DHV_MPS_URL[i]);
|
||||
}
|
||||
} else {
|
||||
logger.info("您尚未配置采集地址");
|
||||
}
|
||||
|
||||
//在这个驱动中,我们只请求如下时间范围的数据,从当前时间往前数半个小时(第一次请求这样)
|
||||
//以后每个半个小时请求一次,每次的请求时间范围是,上一次的请求时间到当前时间点,通常会比半个小时多一点点,
|
||||
//多出来的时间是上一次请求的耗时时间
|
||||
LocalDateTime endTime = null;
|
||||
LocalDateTime startTime = null;
|
||||
while (startVo.getShouldRun().get() == true) {
|
||||
logger.info("即将采集设备数据......");
|
||||
LocalDateTime end_time_temp = null;
|
||||
if (endTime != null) {
|
||||
end_time_temp = endTime;
|
||||
}
|
||||
endTime = LocalDateTime.now();
|
||||
if (startTime == null) {
|
||||
startTime = endTime.minusMinutes(30);
|
||||
} else {
|
||||
startTime = end_time_temp;
|
||||
}
|
||||
Map<String, String> mpsJsonStringMap = MPSRequest(httpClient);
|
||||
if (DHV_MET_URL == null) {
|
||||
Construct_DHV_MET_URL();
|
||||
}
|
||||
if (DHV_MPV_URL == null) {
|
||||
METRequest(httpClient);
|
||||
}
|
||||
Map<String, JSONObject> mpvJsonArrayMap = MPVRequest(httpClient, startTime, endTime);
|
||||
if (mpsJsonStringMap != null && mpsJsonStringMap.size() > 0) {
|
||||
for (int i = 0; i < mpsJsonStringMap.size(); i++) {
|
||||
String msgKey = dbNames.get(i) + YFDHV.YF_Separator + YFDHV.YF_MPS;
|
||||
sendToNextMQ(mpsJsonStringMap.get(dbNames.get(i)), msgKey);
|
||||
}
|
||||
}
|
||||
if (mpvJsonArrayMap != null && mpvJsonArrayMap.size() > 0) {
|
||||
List<String> dbNameList = new ArrayList<>(mpvJsonArrayMap.keySet());
|
||||
for (int i = 0; i < dbNameList.size(); i++) {
|
||||
String dbName = dbNameList.get(i);
|
||||
sendToNextMQ(mpvJsonArrayMap.get(dbName).toJSONString(), dbName);
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(startVo.getHttpParam().getPullInternal());
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("休眠异常");
|
||||
throw new BusinessException("休眠异常");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param httpClient
|
||||
* @return java.lang.String
|
||||
* @function: 终极奥义之通过DHV_MPS_URL地址获取测点状态信息
|
||||
* @author jianghc
|
||||
* @date 2022/5/24 16:16
|
||||
*/
|
||||
private Map<String, String> MPSRequest(OkHttpClient httpClient) {
|
||||
if (!metPara) {
|
||||
dbNameList = new ArrayList<>();
|
||||
itemIdList = new ArrayList<>();
|
||||
}
|
||||
if (DHV_MPS_URL == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, String> mpsJsonMap = new HashMap<>();
|
||||
int DHV_MPS_URL_Len = DHV_MPS_URL.length;
|
||||
|
||||
for (int i = 0; i < DHV_MPS_URL_Len; i++) {
|
||||
okhttp3.Request request = new okhttp3.Request.Builder()
|
||||
.header("Authorization", Authorization)
|
||||
.header("emptyanddefault", emptyanddefault)
|
||||
.url(DHV_MPS_URL[i])
|
||||
.get()
|
||||
.build();
|
||||
Response response = null;
|
||||
try {
|
||||
Long currentTime_start = System.currentTimeMillis();
|
||||
Long currentTime_end = 0l;
|
||||
response = httpClient.newCall(request).execute();
|
||||
currentTime_end = System.currentTimeMillis();
|
||||
if (currentTime_end - currentTime_start > timeOut) {
|
||||
logger.error("地址:" + DHV_MPS_URL[i] + "请求超时!");
|
||||
throw new BusinessException("地址:" + DHV_MPS_URL[i] + "请求超时!");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("被请求的接口:" + DHV_MPS_URL[i] + "请求超时," + e.getMessage());
|
||||
throw new BusinessException("被请求的接口:" + DHV_MPS_URL[i] + "请求超时," + e.getMessage());
|
||||
}
|
||||
if (response.isSuccessful()) {
|
||||
String jsonString = null;
|
||||
try {
|
||||
jsonString = new String(response.body().bytes(), StandardCharsets.UTF_8);
|
||||
} catch (Exception ex) {
|
||||
logger.error("MPS响应数据解析异常");
|
||||
throw new BusinessException("MPS响应数据解析异常");
|
||||
}
|
||||
Object jsonArrayObject = ((JSONObject) JSONObject.parse(jsonString)).get("values");
|
||||
JSONObject resJson = new JSONObject();
|
||||
if (jsonArrayObject instanceof JSONArray) {
|
||||
JSONArray jsonArray = (JSONArray) jsonArrayObject;
|
||||
for (int j = 0; j < jsonArray.size(); j++) {
|
||||
JSONObject jsonObject = (JSONObject) jsonArray.get(j);
|
||||
MPSItem[] mpsItems = MPSItem.values();
|
||||
MPSItem primary = MPSItem.getPrimary();
|
||||
Object primaryValue = jsonObject.get(primary.toString());
|
||||
|
||||
String mp = jsonObject.getString(MPSItem.getPrimary().getMpsItem());
|
||||
if (!AllowMeasuringPoint.allowMeasuringPoint(mp)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (MPSItem mpsItem : mpsItems) {
|
||||
String key = dbNames.get(i) + YFDHV.YF_Separator + primaryValue + YFDHV.YF_Separator + mpsItem.getMpsItem();
|
||||
Object value = jsonObject.get(mpsItem.toString());
|
||||
resJson.fluentPut(key, value);
|
||||
}
|
||||
resJson.fluentPut(dbNames.get(i) + YFDHV.YF_Separator + primaryValue + YFDHV.YF_Separator + YFDHV.DateTime
|
||||
, LocalDateTime.now());//注意测点状态时间是系统生成的,没有从接口中获取到
|
||||
if (!metPara) {
|
||||
String mpx = jsonObject.getString(MPSItem.getPrimary().getMpsItem());
|
||||
if (!AllowMeasuringPoint.allowMeasuringPoint(mpx)) {
|
||||
continue;
|
||||
}
|
||||
dbNameList.add(dbNames.get(i));
|
||||
itemIdList.add(mpx);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.warn("地址:" + DHV_MPS_URL[i] + " 未采集到数据!");
|
||||
}
|
||||
if (resJson.size() > 0) {
|
||||
mpsJsonMap.put(dbNames.get(i), resJson.toJSONString());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!metPara) {
|
||||
StringBuilder stringBuffer = new StringBuilder("\n");
|
||||
stringBuffer.append("测点状态采集点信息:\n");
|
||||
stringBuffer.append("=======================================================================================\n");
|
||||
for (int i = 0; i < dbNameList.size(); i++) {
|
||||
stringBuffer.append("数据库:" + dbNameList.get(i) + " 测点状态id:" + itemIdList.get(i) + "\n");
|
||||
}
|
||||
stringBuffer.append("=======================================================================================\n");
|
||||
logger.info(stringBuffer.toString());
|
||||
metPara = true;
|
||||
}
|
||||
if (mpsJsonMap.size() > 0) {
|
||||
return mpsJsonMap;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @function: 构造DHV_MET_URL的请求地址
|
||||
* @author jianghc
|
||||
* @date 2022/5/24 16:12
|
||||
*/
|
||||
private void Construct_DHV_MET_URL() {
|
||||
if (itemIdList == null || itemIdList.size() == 0) {
|
||||
return;
|
||||
}
|
||||
int itemIdList_len = itemIdList.size();
|
||||
DHV_MET_URL = new String[itemIdList_len];
|
||||
for (int i = 0; i < itemIdList.size(); i++) {
|
||||
String measuringPointNumberOrTechID = itemIdList.get(i);
|
||||
if (measuringPointNumberOrTechID.contains("#")) {
|
||||
measuringPointNumberOrTechID = measuringPointNumberOrTechID.replace("#", "%23");
|
||||
}
|
||||
DHV_MET_URL[i] = url + String.format(YFDHV.YF_DHV_METH, dbNameList.get(i), measuringPointNumberOrTechID);
|
||||
}
|
||||
StringBuilder stringBuffer = new StringBuilder("\n");
|
||||
stringBuffer.append("获取测点总值需要的方法请求路径包含:\n");
|
||||
stringBuffer.append("=======================================================================================\n");
|
||||
for (int i = 0; i < DHV_MET_URL.length; i++) {
|
||||
stringBuffer.append(DHV_MET_URL[i] + "\n");
|
||||
}
|
||||
stringBuffer.append("=======================================================================================\n");
|
||||
logger.info(stringBuffer.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param httpClient
|
||||
* @function: 主要要来获取dbNameList,itemIdList,methodNameList
|
||||
* @author jianghc
|
||||
* @date 2022/5/24 16:12
|
||||
*/
|
||||
private void METRequest(OkHttpClient httpClient) {
|
||||
List<String> dbNameList_temp = new ArrayList<>();
|
||||
List<String> itemIdList_temp = new ArrayList<>();
|
||||
if (DHV_MET_URL == null) {
|
||||
return;
|
||||
}
|
||||
methodNameList = new ArrayList<>();
|
||||
int DHV_MET_URL_len = DHV_MET_URL.length;
|
||||
for (int i = 0; i < DHV_MET_URL_len; i++) {
|
||||
okhttp3.Request request = new okhttp3.Request.Builder()
|
||||
.header("Authorization", Authorization)
|
||||
.header("emptyanddefault", emptyanddefault)
|
||||
.url(DHV_MET_URL[i])
|
||||
.get()
|
||||
.build();
|
||||
Response response = null;
|
||||
try {
|
||||
response = httpClient.newCall(request).execute();
|
||||
} catch (IOException ex) {
|
||||
throw new BusinessException("接口:" + DHV_MET_URL[i] + "请求失败!");
|
||||
}
|
||||
if (response != null && response.isSuccessful()) {
|
||||
String jsonString = null;
|
||||
try {
|
||||
jsonString = new String(response.body().bytes(), StandardCharsets.UTF_8);
|
||||
} catch (Exception ex) {
|
||||
logger.error("MPS响应数据解析异常");
|
||||
throw new BusinessException("MPS响应数据解析异常");
|
||||
}
|
||||
JSONObject jsonObject = (JSONObject) JSONObject.parse(jsonString);
|
||||
JSONArray jsonArray = (JSONArray) jsonObject.get("values");
|
||||
if (jsonArray != null && jsonArray.size() > 0) {
|
||||
for (int j = 0; j < jsonArray.size(); j++) {
|
||||
JSONObject jsonObject_val = (JSONObject) jsonArray.get(j);
|
||||
String TechName = jsonObject_val.getString("TechName");
|
||||
if (!AllowMethod.allowMethod(TechName)) {
|
||||
logger.info(TechName + "方法不匹配");
|
||||
continue;
|
||||
}
|
||||
dbNameList_temp.add(dbNameList.get(i));
|
||||
itemIdList_temp.add(itemIdList.get(i));
|
||||
methodNameList.add(TechName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dbNameList = null;
|
||||
dbNameList = dbNameList_temp;
|
||||
itemIdList = null;
|
||||
itemIdList = itemIdList_temp;
|
||||
StringBuilder stringBuilder = new StringBuilder("\n");
|
||||
measuringPointNumberOrTechIDs = new String[dbNameList.size()];
|
||||
stringBuilder.append("测点总值需要的参数:\n");
|
||||
stringBuilder.append("=======================================================================================\n");
|
||||
for (int i = 0; i < dbNameList.size(); i++) {
|
||||
measuringPointNumberOrTechIDs[i] = dbNameList.get(i) + YFDHV.YF_Separator + itemIdList.get(i) + YFDHV.YF_Separator + methodNameList.get(i);
|
||||
stringBuilder.append("数据库:" + dbNameList.get(i)
|
||||
+ " 测点总值id:" + itemIdList.get(i)
|
||||
+ " 方法:" + methodNameList.get(i) + "\n");
|
||||
}
|
||||
stringBuilder.append("=======================================================================================\n");
|
||||
logger.info(stringBuilder.toString());
|
||||
Construct_DHV_MPV_URL();
|
||||
}
|
||||
|
||||
/**
|
||||
* @function: 构造DHV_MPV_URL的请求地址
|
||||
* @author jianghc
|
||||
* @date 2022/5/24 16:14
|
||||
*/
|
||||
private void Construct_DHV_MPV_URL() {
|
||||
if (methodNameList == null) {
|
||||
return;
|
||||
}
|
||||
int methodNameList_len = methodNameList.size();
|
||||
DHV_MPV_URL = new String[methodNameList_len];
|
||||
for (int i = 0; i < methodNameList_len; i++) {
|
||||
String measuringPointNumberOrTechID = itemIdList.get(i);
|
||||
if (measuringPointNumberOrTechID.contains("#")) {
|
||||
measuringPointNumberOrTechID = measuringPointNumberOrTechID.replace("#", "%23");
|
||||
}
|
||||
DHV_MPV_URL[i] = url + String.format(YFDHV.YF_DHV_MPV, dbNameList.get(i), measuringPointNumberOrTechID, methodNameList.get(i));
|
||||
DHV_MPV_URL[i] += "?ShortMem=true&LongMem=true&Expand=result";
|
||||
}
|
||||
StringBuilder stringBuilder = new StringBuilder("\n");
|
||||
stringBuilder.append("测点总值请求路径(该请求路径不含时间参数 &StartDateTime &StopDateTime ):\n");
|
||||
stringBuilder.append("=======================================================================================\n");
|
||||
for (int i = 0; i < DHV_MPV_URL.length; i++) {
|
||||
stringBuilder.append(DHV_MPV_URL[i] + "\n");
|
||||
}
|
||||
stringBuilder.append("=======================================================================================\n");
|
||||
logger.info(stringBuilder.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param httpClient
|
||||
* @param start
|
||||
* @param end
|
||||
* @return Map<String, JSONArray>
|
||||
* @function: 终极奥义之通过DHV_MPV_URL信息获取测点总值信息
|
||||
* @author jianghc
|
||||
* @date 2022/5/24 16:14
|
||||
*/
|
||||
private Map<String, JSONObject> MPVRequest(OkHttpClient httpClient, LocalDateTime start, LocalDateTime end) {
|
||||
String startTime = start.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
String endTime = end.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
if (DHV_MPV_URL == null) {
|
||||
return null;
|
||||
}
|
||||
int DHV_MPV_URL_Len = DHV_MPV_URL.length;
|
||||
|
||||
Map<String, JSONObject> jsonArrayResObj = new HashMap<>();
|
||||
JSONObject resJson = null;
|
||||
for (int i = 0; i < DHV_MPV_URL_Len; i++) {
|
||||
String msgKey = dbNameList.get(i) + YFDHV.YF_Separator + itemIdList.get(i) + YFDHV.YF_Separator + YFDHV.YF_MPV;
|
||||
resJson = jsonArrayResObj.get(msgKey);
|
||||
if (resJson == null) {
|
||||
resJson = new JSONObject();
|
||||
}
|
||||
okhttp3.Request request = new okhttp3.Request.Builder()
|
||||
.header("Authorization", Authorization)
|
||||
.header("emptyanddefault", emptyanddefault)
|
||||
//.url(DHV_MPV_URL[i] + "&StartDateTime=2020-01-01 00:00:01" + "&StopDateTime=" + endTime)
|
||||
.url(DHV_MPV_URL[i] + "&StartDateTime=" + startTime + "&StopDateTime=" + endTime)
|
||||
.get()
|
||||
.build();
|
||||
Response response = null;
|
||||
try {
|
||||
Long currentTime_start = System.currentTimeMillis();
|
||||
Long currentTime_end = 0l;
|
||||
response = httpClient.newCall(request).execute();
|
||||
currentTime_end = System.currentTimeMillis();
|
||||
if (currentTime_end - currentTime_start > timeOut) {
|
||||
logger.error("地址:" + DHV_MPV_URL[i] + "请求超时!");
|
||||
throw new BusinessException("地址:" + DHV_MPV_URL[i] + "请求超时!");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("地址:" + DHV_MPV_URL[i] + "请求超时!" + e.getMessage());
|
||||
throw new BusinessException("地址:" + DHV_MPV_URL[i] + "请求超时!");
|
||||
}
|
||||
MPVItem[] mpvItems = MPVItem.values();
|
||||
if (response.isSuccessful()) {
|
||||
MPVItem primary = MPVItem.getPrimary();
|
||||
String primary_value = measuringPointNumberOrTechIDs[i];
|
||||
String jsonString = null;
|
||||
try {
|
||||
jsonString = new String(response.body().bytes(), StandardCharsets.UTF_8);
|
||||
} catch (Exception ex) {
|
||||
logger.error("MPV响应数据解析异常");
|
||||
throw new BusinessException("MPV响应数据解析异常");
|
||||
}
|
||||
Object jsonObject_temp = JSONObject.parse(jsonString);
|
||||
if (jsonObject_temp instanceof JSONObject) {
|
||||
JSONObject jsonObject = (JSONObject) jsonObject_temp;
|
||||
Object jsonArrayObject = jsonObject.get("values");
|
||||
if (jsonArrayObject != null && jsonArrayObject instanceof JSONArray) {
|
||||
JSONArray jsonArray = (JSONArray) jsonArrayObject;
|
||||
|
||||
for (int j = 0; j < jsonArray.size(); j++) {
|
||||
Object obj = jsonArray.get(j);
|
||||
if (j >= 2) {
|
||||
logger.error("拉取数据过多,请缩短采集时间间隔!");
|
||||
logger.error("多余数据将不被采集:" + ((JSONObject) obj).toJSONString());
|
||||
continue;
|
||||
}
|
||||
if (obj != null && obj instanceof JSONObject) {
|
||||
JSONObject jsonObject_value = (JSONObject) obj;
|
||||
Object obj_Result = jsonObject_value.get("Result");
|
||||
if (obj_Result != null && obj_Result instanceof JSONObject) {
|
||||
JSONObject jsonObject_Result = (JSONObject) obj_Result;
|
||||
|
||||
//primary_value=数据库.测点.方法
|
||||
//key-value
|
||||
//key:数据库.测点.方法.属性
|
||||
//value:测点
|
||||
resJson.fluentPut(primary_value + YFDHV.YF_Separator + primary.getMpvItem(),
|
||||
primary_value.split(YFDHV.YF_EscapeCharacter + YFDHV.YF_Separator)[1]);
|
||||
|
||||
|
||||
Object RPM = jsonObject_Result.get("RPM");
|
||||
if (RPM != null && RPM instanceof JSONObject) {
|
||||
JSONObject rpmObj = (JSONObject) RPM;
|
||||
MPVRPMItem[] mpvrpmItems = MPVRPMItem.values();
|
||||
for (MPVRPMItem mpvrpmItem : mpvrpmItems) {
|
||||
String key = primary_value + YFDHV.YF_Separator + mpvrpmItem.getMpvRPMItem();
|
||||
String value = rpmObj.getString(mpvrpmItem.getMpvRPMItem());
|
||||
//key-value
|
||||
//key:数据库.测点.方法.属性
|
||||
//value:属性值
|
||||
resJson.fluentPut(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
//String DateTime_key = primary_value + YFDHV.YF_Separator + MPVItem.DateTime.getMpvItem();
|
||||
//String DateTime_value = jsonObject_Result.get(MPVItem.DateTime.toString()).toString();
|
||||
//key-value
|
||||
//key:数据库.测点.方法.属性
|
||||
//value:属性值
|
||||
//resJson.fluentPut(DateTime_key, DateTime_value);
|
||||
|
||||
Object obj_Conditions = jsonObject_Result.get("Conditions");
|
||||
if (obj_Conditions != null && obj_Conditions instanceof JSONObject) {
|
||||
JSONObject jsonObject_Conditions = (JSONObject) obj_Conditions;
|
||||
|
||||
for (MPVItem mpvItem : mpvItems) {
|
||||
String key = primary_value + YFDHV.YF_Separator + mpvItem.getMpvItem();
|
||||
Object value = null;
|
||||
try {
|
||||
value = jsonObject_Conditions.get(mpvItem.toString());
|
||||
} catch (Exception ex) {
|
||||
logger.error("永峰设备健康振动数据Http网关response解析异常");
|
||||
throw new BusinessException("永峰设备健康振动数据Http网关response解析异常");
|
||||
}
|
||||
if (value != null) {
|
||||
//key-value
|
||||
//key:数据库.测点.方法.属性
|
||||
//value:属性值
|
||||
resJson.fluentPut(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resJson != null && resJson.size() > 0) {
|
||||
jsonArrayResObj.put(msgKey, resJson);
|
||||
}
|
||||
}
|
||||
if (jsonArrayResObj.size() > 0) {
|
||||
return jsonArrayResObj;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param body
|
||||
* @param msgKey
|
||||
* @function: 将数据发送到平台
|
||||
* @author jianghc
|
||||
* @date 2022/5/24 16:15
|
||||
*/
|
||||
private void sendToNextMQ(Object body, String msgKey) {
|
||||
ServiceProvider serviceProvider = startVo.getServiceProvider();
|
||||
PulledHttpGatewayBase gatewayBase = startVo.getGatewayBase();
|
||||
if (serviceProvider != null && gatewayBase != null && body instanceof String) {
|
||||
SendService service = (SendService) serviceProvider.getByName(ServiceName.Send);
|
||||
Message message = null;
|
||||
HttpMessage httpMessage = gatewayBase.buildHttpMessage();
|
||||
httpMessage.setDeviceId(startVo.getDeviceId());
|
||||
httpMessage.setProviderCode(null);
|
||||
httpMessage.setBody((String) body);
|
||||
httpMessage.setMsgKey(msgKey);
|
||||
message = httpMessage;
|
||||
service.sendMessage(message);
|
||||
} else if (serviceProvider != null && gatewayBase != null && body instanceof JSONArray) {
|
||||
SendService service = (SendService) serviceProvider.getByName(ServiceName.Send);
|
||||
Message message;
|
||||
JSONArray sendBody = (JSONArray) body;
|
||||
List<Message> httpMessages = new ArrayList(sendBody.size());
|
||||
for (Object obj : sendBody) {
|
||||
HttpMessage httpMessage = gatewayBase.buildHttpMessage();
|
||||
httpMessage.setDeviceId(startVo.getDeviceId());
|
||||
httpMessage.setProviderCode(null);
|
||||
httpMessage.setBody(obj.toString());
|
||||
httpMessage.setMsgKey(msgKey);
|
||||
httpMessages.add(httpMessage);
|
||||
}
|
||||
MessageBatch<Message> batch = new MessageBatch<>(httpMessages);
|
||||
message = batch;
|
||||
service.sendMessage(message);
|
||||
} else {
|
||||
logger.info("连接id-{} 拉取采集到值-{}", gatewayBase.getInstanceVo().getRunId(), body);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.cisdi.data.DHV.gateway.vo;
|
||||
|
||||
import com.cisdi.data.sdk.gateway.base.PulledHttpGatewayBase;
|
||||
import com.cisdi.data.sdk.param.PullHttpParam;
|
||||
import com.cisdi.data.sdk.service.ServiceProvider;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class PullHttpTaskStartVo {
|
||||
private AtomicBoolean shouldRun;
|
||||
private ServiceProvider serviceProvider;
|
||||
private String deviceId;
|
||||
private PulledHttpGatewayBase gatewayBase;
|
||||
private PullHttpParam httpParam;
|
||||
|
||||
public AtomicBoolean getShouldRun() {
|
||||
return shouldRun;
|
||||
}
|
||||
|
||||
public void setShouldRun(AtomicBoolean shouldRun) {
|
||||
this.shouldRun = shouldRun;
|
||||
}
|
||||
|
||||
public ServiceProvider getServiceProvider() {
|
||||
return serviceProvider;
|
||||
}
|
||||
|
||||
public void setServiceProvider(ServiceProvider serviceProvider) {
|
||||
this.serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public PulledHttpGatewayBase getGatewayBase() {
|
||||
return gatewayBase;
|
||||
}
|
||||
|
||||
public void setGatewayBase(PulledHttpGatewayBase gatewayBase) {
|
||||
this.gatewayBase = gatewayBase;
|
||||
}
|
||||
|
||||
public PullHttpParam getHttpParam() {
|
||||
return httpParam;
|
||||
}
|
||||
|
||||
public void setHttpParam(PullHttpParam httpParam) {
|
||||
this.httpParam = httpParam;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.cisdi.data.DHV.gateway.vo.dhv;
|
||||
|
||||
public enum AllowMeasuringPoint {
|
||||
//1#XB-10V -02,符合规则的测点
|
||||
RegularExpression1("^([\\s]*)([0-9]+)[#]([A-Z]+)([\\s]*)[-]([\\s]*)([0-9]+)([A-Z]+)([\\s]*)([\\s]*)[-]([\\s]*)([0-9]+)([\\s]*)$"),
|
||||
//1#XB-ZG1 -05,符合规则的测点
|
||||
RegularExpression2("^([\\s]*)([0-9]+)[#]([A-Z]+)([\\s]*)[-]([\\s]*)([A-Z]+)([0-9]+)([\\s]*)([\\s]*)[-]([\\s]*)([0-9]+)([\\s]*)$"),
|
||||
//2#XB-1#GF-05,符合规则的测点
|
||||
RegularExpression3("^([\\s]*)([0-9]+)[#]([A-Z]+)([\\s]*)[-]([\\s]*)([0-9]+)[#]([A-Z]+)([\\s]*)([\\s]*)[-]([\\s]*)([0-9]+)([\\s]*)$");
|
||||
|
||||
private String reg;
|
||||
|
||||
AllowMeasuringPoint(String reg) {
|
||||
this.reg = reg;
|
||||
}
|
||||
|
||||
private String getReg() {
|
||||
return this.reg;
|
||||
}
|
||||
|
||||
public static boolean allowMeasuringPoint(String mp) {
|
||||
if (mp == null) {
|
||||
return true;
|
||||
}
|
||||
AllowMeasuringPoint[] allowMeasuringPoints = AllowMeasuringPoint.values();
|
||||
for (int i = 0; i < allowMeasuringPoints.length; i++) {
|
||||
if (mp.matches(allowMeasuringPoints[i].getReg())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.cisdi.data.DHV.gateway.vo.dhv;
|
||||
|
||||
|
||||
public enum AllowMethod {
|
||||
// tam1("SPM HD"),
|
||||
// tam2("HD ENV"),
|
||||
// tam3("振动低频"),
|
||||
// tam4("振动高频"),
|
||||
|
||||
am1("冲击脉冲频谱"),
|
||||
am2("振动速度谱"),
|
||||
am3("冲击脉冲"),
|
||||
am4("振动速度"),
|
||||
am5("冲击脉冲谱"),
|
||||
am6("冲激脉冲频谱"),
|
||||
am7("振动速度普");
|
||||
|
||||
private String method;
|
||||
|
||||
AllowMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
private String getMethod(){
|
||||
return this.method;
|
||||
}
|
||||
|
||||
public static boolean allowMethod(String am) {
|
||||
if (am == null) {
|
||||
return false;
|
||||
}
|
||||
AllowMethod[] allowMethods=AllowMethod.values();
|
||||
for (int i=0;i<allowMethods.length;i++) {
|
||||
if (am.contains(allowMethods[i].getMethod())){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
23
src/main/java/com/cisdi/data/DHV/gateway/vo/dhv/MPSItem.java
Normal file
23
src/main/java/com/cisdi/data/DHV/gateway/vo/dhv/MPSItem.java
Normal file
@ -0,0 +1,23 @@
|
||||
package com.cisdi.data.DHV.gateway.vo.dhv;
|
||||
|
||||
public enum MPSItem {
|
||||
Number("Number"),
|
||||
ColorEval("ColorEval");
|
||||
//DateTime("DateTime");注意测点状态时间是系统生成的,没有从接口中获取到
|
||||
|
||||
private String mpsItem;
|
||||
|
||||
MPSItem(String mpsItem) {
|
||||
this.mpsItem=mpsItem;
|
||||
}
|
||||
|
||||
public String getMpsItem(){
|
||||
return mpsItem;
|
||||
}
|
||||
|
||||
|
||||
public static MPSItem getPrimary() {
|
||||
return Number;
|
||||
}
|
||||
|
||||
}
|
26
src/main/java/com/cisdi/data/DHV/gateway/vo/dhv/MPSVO.java
Normal file
26
src/main/java/com/cisdi/data/DHV/gateway/vo/dhv/MPSVO.java
Normal file
@ -0,0 +1,26 @@
|
||||
package com.cisdi.data.DHV.gateway.vo.dhv;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author jianghc
|
||||
* @function:
|
||||
* @date 2022年05月06日 16:23
|
||||
*/
|
||||
public class MPSVO implements Serializable {
|
||||
|
||||
List<String> databaseName;
|
||||
|
||||
public MPSVO(){
|
||||
|
||||
}
|
||||
|
||||
public List<String> getDatabaseName() {
|
||||
return databaseName;
|
||||
}
|
||||
|
||||
public void setDatabaseName(List<String> databaseName) {
|
||||
this.databaseName = databaseName;
|
||||
}
|
||||
}
|
27
src/main/java/com/cisdi/data/DHV/gateway/vo/dhv/MPVItem.java
Normal file
27
src/main/java/com/cisdi/data/DHV/gateway/vo/dhv/MPVItem.java
Normal file
@ -0,0 +1,27 @@
|
||||
package com.cisdi.data.DHV.gateway.vo.dhv;
|
||||
|
||||
public enum MPVItem {
|
||||
measuringPointNumberOrTechID("measuringPointNumberOrTechID"),
|
||||
// DateTime("DateTime"),
|
||||
HDm("HDm"),
|
||||
HDc("HDc");
|
||||
// VEL("VEL"),
|
||||
// DISP("DISP"),
|
||||
// ACC("ACC"),
|
||||
// Peak("Peak"),
|
||||
// PkToPk("PkToPk");
|
||||
|
||||
private String mpvItem;
|
||||
|
||||
MPVItem(String mpvItem) {
|
||||
this.mpvItem = mpvItem;
|
||||
}
|
||||
|
||||
public String getMpvItem() {
|
||||
return this.mpvItem;
|
||||
}
|
||||
|
||||
public static MPVItem getPrimary() {
|
||||
return measuringPointNumberOrTechID;
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.cisdi.data.DHV.gateway.vo.dhv;
|
||||
|
||||
public enum MPVRPMItem {
|
||||
// RPM1("RPM1"),
|
||||
// RPM2("RPM2"),
|
||||
// Avg("Avg"),
|
||||
// Min("Min"),
|
||||
Max("Max");
|
||||
// Delta("Delta");
|
||||
|
||||
MPVRPMItem(String mpvRPMItem) {
|
||||
this.mpvRPMItem = mpvRPMItem;
|
||||
}
|
||||
|
||||
private String mpvRPMItem;
|
||||
|
||||
public String getMpvRPMItem() {
|
||||
return this.mpvRPMItem;
|
||||
}
|
||||
}
|
147
src/main/java/com/cisdi/data/DHV/gateway/vo/dhv/MPVVO.java
Normal file
147
src/main/java/com/cisdi/data/DHV/gateway/vo/dhv/MPVVO.java
Normal file
@ -0,0 +1,147 @@
|
||||
package com.cisdi.data.DHV.gateway.vo.dhv;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author jianghc
|
||||
* @function:
|
||||
* @date 2022年05月06日 16:25
|
||||
*/
|
||||
public class MPVVO implements Serializable {
|
||||
|
||||
private String databaseName;
|
||||
|
||||
private String measuringPointNumberOrTechID;
|
||||
|
||||
private String assignmentTechIDorName;
|
||||
|
||||
private Boolean shortMem;
|
||||
|
||||
private Boolean longMem;
|
||||
|
||||
private Integer maxCount;
|
||||
|
||||
private String startDateTime;
|
||||
|
||||
private String stopDateTime;
|
||||
|
||||
private Integer mpktTech;
|
||||
|
||||
private String expand;
|
||||
|
||||
public String getParameter() {
|
||||
String para = "?placeholder=placeholder";//该参数无意义,用作占位符,方便后面拼接url,统一 &xxx=yyy
|
||||
if (shortMem != null) {
|
||||
para = para + ("&ShortMem=" + shortMem);
|
||||
} else {
|
||||
para = para + ("&ShortMem=" + true);
|
||||
}
|
||||
if (longMem != null) {
|
||||
para = para + ("&LongMem=" + longMem);
|
||||
} else {
|
||||
para = para + ("&LongMem=" + true);
|
||||
}
|
||||
if (maxCount != null) {
|
||||
para = para + ("&MaxCount=" + maxCount);
|
||||
}
|
||||
// if (startDateTime != null) {
|
||||
// para = para + ("&StartDateTime=" + startDateTime);
|
||||
//
|
||||
// }
|
||||
// if (stopDateTime != null) {
|
||||
// para = para + ("&StartDateTime=" + startDateTime);
|
||||
// }
|
||||
if (mpktTech != null) {
|
||||
para = para + ("&MpktTech=" + mpktTech);
|
||||
}
|
||||
if (expand != null) {
|
||||
para = para + ("&Expand=" + expand);
|
||||
}
|
||||
return para;
|
||||
}
|
||||
|
||||
public MPVVO() {
|
||||
|
||||
}
|
||||
|
||||
public String getDatabaseName() {
|
||||
return databaseName;
|
||||
}
|
||||
|
||||
public void setDatabaseName(String databaseName) {
|
||||
this.databaseName = databaseName;
|
||||
}
|
||||
|
||||
public String getMeasuringPointNumberOrTechID() {
|
||||
return measuringPointNumberOrTechID;
|
||||
}
|
||||
|
||||
public void setMeasuringPointNumberOrTechID(String measuringPointNumberOrTechID) {
|
||||
this.measuringPointNumberOrTechID = measuringPointNumberOrTechID;
|
||||
}
|
||||
|
||||
public String getAssignmentTechIDorName() {
|
||||
return assignmentTechIDorName;
|
||||
}
|
||||
|
||||
public void setAssignmentTechIDorName(String assignmentTechIDorName) {
|
||||
this.assignmentTechIDorName = assignmentTechIDorName;
|
||||
}
|
||||
|
||||
public boolean isShortMem() {
|
||||
return shortMem;
|
||||
}
|
||||
|
||||
public void setShortMem(Boolean shortMem) {
|
||||
this.shortMem = shortMem;
|
||||
}
|
||||
|
||||
public boolean isLongMem() {
|
||||
return longMem;
|
||||
}
|
||||
|
||||
public void setLongMem(Boolean longMem) {
|
||||
this.longMem = longMem;
|
||||
}
|
||||
|
||||
public int getMaxCount() {
|
||||
return maxCount;
|
||||
}
|
||||
|
||||
public void setMaxCount(Integer maxCount) {
|
||||
this.maxCount = maxCount;
|
||||
}
|
||||
|
||||
public String getStartDateTime() {
|
||||
return startDateTime;
|
||||
}
|
||||
|
||||
public void setStartDateTime(String startDateTime) {
|
||||
this.startDateTime = startDateTime;
|
||||
}
|
||||
|
||||
public String getStopDateTime() {
|
||||
return stopDateTime;
|
||||
}
|
||||
|
||||
public void setStopDateTime(String stopDateTime) {
|
||||
this.stopDateTime = stopDateTime;
|
||||
}
|
||||
|
||||
public int getMpktTech() {
|
||||
return mpktTech;
|
||||
}
|
||||
|
||||
public void setMpktTech(Integer mpktTech) {
|
||||
this.mpktTech = mpktTech;
|
||||
}
|
||||
|
||||
public String getExpand() {
|
||||
return expand;
|
||||
}
|
||||
|
||||
public void setExpand(String expand) {
|
||||
this.expand = expand;
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.cisdi.data.DHV.gateway.vo.dhv;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author jianghc
|
||||
* @function: 连接管理中,自定义的其他参数
|
||||
* @date 2022年05月05日 09:48
|
||||
*/
|
||||
public class OtherParamVO implements Serializable {
|
||||
|
||||
private MPSVO mpsvo;
|
||||
|
||||
private List<MPVVO> mpvvoList;
|
||||
|
||||
String Authorization;
|
||||
|
||||
String emptyanddefault;
|
||||
|
||||
public OtherParamVO(){
|
||||
|
||||
}
|
||||
|
||||
public MPSVO getMpsvo() {
|
||||
return mpsvo;
|
||||
}
|
||||
|
||||
public void setMpsvo(MPSVO mpsvo) {
|
||||
this.mpsvo = mpsvo;
|
||||
}
|
||||
|
||||
public List<MPVVO> getMpvvoList() {
|
||||
return mpvvoList;
|
||||
}
|
||||
|
||||
public void setMpvvoList(List<MPVVO> mpvvoList) {
|
||||
this.mpvvoList = mpvvoList;
|
||||
}
|
||||
|
||||
public String getAuthorization() {
|
||||
return Authorization;
|
||||
}
|
||||
|
||||
public void setAuthorization(String authorization) {
|
||||
Authorization = authorization;
|
||||
}
|
||||
|
||||
public String getEmptyanddefault() {
|
||||
return emptyanddefault;
|
||||
}
|
||||
|
||||
public void setEmptyanddefault(String emptyanddefault) {
|
||||
this.emptyanddefault = emptyanddefault;
|
||||
}
|
||||
}
|
45
src/main/java/com/cisdi/data/DHV/gateway/vo/dhv/YFDHV.java
Normal file
45
src/main/java/com/cisdi/data/DHV/gateway/vo/dhv/YFDHV.java
Normal file
@ -0,0 +1,45 @@
|
||||
package com.cisdi.data.DHV.gateway.vo.dhv;
|
||||
|
||||
/**
|
||||
* @author jianghc
|
||||
* @function: 设备健康振动数据接入请求接口路径
|
||||
* @date 2022/5/6 15:46
|
||||
*/
|
||||
public interface YFDHV {
|
||||
|
||||
|
||||
//测点状态接口
|
||||
//{databaseName}
|
||||
String YF_DHV_MPS = "/databases/%s/measuringpoints";
|
||||
|
||||
|
||||
//测点方法接口
|
||||
//{dataBaseNamePlaceholder}数据库
|
||||
//{measuringPointNumberOrTechID}测点编码
|
||||
String YF_DHV_METH = "/databases/%s/measuringpoints/%s/assignments";
|
||||
|
||||
|
||||
//测点总值接口
|
||||
//{databaseName}
|
||||
//{measuringPointNumberOrTechID}
|
||||
//{assignmentTechIDorName}
|
||||
String YF_DHV_MPV = "/databases/%s/measuringpoints/%s/assignments/%s/results";
|
||||
|
||||
|
||||
//测点状态电文号=数据库.MPS
|
||||
String YF_MPS = "MPS";
|
||||
|
||||
|
||||
//测点总值电文号=测点.MPV
|
||||
String YF_MPV = "MPV";
|
||||
|
||||
//分隔符,用.作为分隔符
|
||||
String YF_Separator = ".";
|
||||
|
||||
//转义字符,split("\\.")时使用
|
||||
String YF_EscapeCharacter="\\";
|
||||
|
||||
//注意测点状态时间是系统生成的,没有从接口中获取到
|
||||
String DateTime = "DateTime";
|
||||
|
||||
}
|
146
src/main/java/com/cisdi/data/DIClient/DIClientGateway.java
Normal file
146
src/main/java/com/cisdi/data/DIClient/DIClientGateway.java
Normal file
@ -0,0 +1,146 @@
|
||||
package com.cisdi.data.DIClient;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.DIClient.bean.DIClientCnfg;
|
||||
import com.cisdi.data.DIClient.bean.PDIOVo;
|
||||
import com.cisdi.data.DIClient.gateway.DBReader;
|
||||
import com.cisdi.data.DIClient.gateway.DBTask;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.enums.GatewayState;
|
||||
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
|
||||
import com.cisdi.data.sdk.param.ListenSocketParam;
|
||||
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
|
||||
import com.cisdi.data.sdk.service.RouteService;
|
||||
import com.cisdi.data.sdk.vo.DeviceVo;
|
||||
import com.cisdi.data.sdk.vo.ExeResultVo;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class DIClientGateway extends SocketGatewayBase {
|
||||
private static Logger logger = LoggerFactory.getLogger(DIClientGateway.class);
|
||||
|
||||
private String deviceId;
|
||||
private DBTask dbTask = null;
|
||||
|
||||
private AtomicLong lastTime=new AtomicLong(0);
|
||||
private AtomicInteger no=new AtomicInteger(0);
|
||||
@Override
|
||||
public ExeResultVo sendReturnMessage(SocketReturnMessage returnMsg) {
|
||||
ExeResultVo rt = new ExeResultVo();
|
||||
|
||||
|
||||
|
||||
PDIOVo pdioVo = new PDIOVo();
|
||||
pdioVo.setQueueId(returnMsg.getMsgKey());
|
||||
pdioVo.setData(new String(returnMsg.getData()));
|
||||
Long thisTime=System.currentTimeMillis();
|
||||
if(thisTime>lastTime.get())
|
||||
{
|
||||
lastTime.set(thisTime);
|
||||
no.set(0);
|
||||
pdioVo.setSerialNo(0);
|
||||
pdioVo.setTimeStamp(thisTime);
|
||||
}
|
||||
else if(thisTime==lastTime.get())
|
||||
{
|
||||
pdioVo.setSerialNo(no.incrementAndGet());
|
||||
pdioVo.setTimeStamp(thisTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
pdioVo.setTimeStamp(lastTime.get());
|
||||
pdioVo.setSerialNo(no.incrementAndGet());
|
||||
}
|
||||
|
||||
|
||||
pdioVo.setHeader("cisdi");
|
||||
pdioVo.setStatus("N");
|
||||
dbTask.sendMessage(pdioVo);
|
||||
|
||||
rt.setSuccess(true);
|
||||
rt.setMessage("DIClient下发数据成功,消息体为" + JSON.toJSONString(pdioVo));
|
||||
logger.info("DIClient下发数据成功,消息体为" + JSON.toJSONString(pdioVo));
|
||||
return rt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (state == GatewayState.RUNNING) {
|
||||
return;
|
||||
}
|
||||
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
|
||||
|
||||
String otherParameter = socketParam.getOtherParameter();
|
||||
DIClientCnfg diClientCnfg = null;
|
||||
// 处理分组
|
||||
if (StringUtils.isNotBlank(otherParameter)) {
|
||||
diClientCnfg = JSON.parseObject(otherParameter, DIClientCnfg.class);
|
||||
}
|
||||
if (diClientCnfg == null) {
|
||||
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为DIClient网关,请配置正确的DIClient配置");
|
||||
}
|
||||
|
||||
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
|
||||
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
|
||||
|
||||
if (deviceVos.size() > 1) {
|
||||
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为DIClient网关,只允许关联一个设备Id");
|
||||
}
|
||||
|
||||
deviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
|
||||
|
||||
if (StringUtils.isEmpty(deviceId)) {
|
||||
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
|
||||
}
|
||||
logger.info("DIClient网关:{}读取启动配置参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
|
||||
|
||||
boolean open = false;
|
||||
DBReader dbReader = new DBReader(diClientCnfg.getDriverClassName(), diClientCnfg.getUrl(), diClientCnfg.getUser(), diClientCnfg.getPwd());
|
||||
open = dbReader.connectionInternal(0);
|
||||
if (open == true) {
|
||||
dbTask = new DBTask(serviceProvider, this, dbReader, diClientCnfg.getCycleTime(), deviceId);
|
||||
dbTask.start();
|
||||
state = GatewayState.RUNNING;
|
||||
logger.info("DIClient网关:{}启动成功 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
} else {
|
||||
logger.info("DIClient网关:{}启动失败 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (state == GatewayState.CLOSED) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
dbTask.close();
|
||||
state = GatewayState.CLOSED;
|
||||
logger.info("网关:" + instanceVo.getRunId() + "关闭成功", instanceVo.getRunId());
|
||||
} catch (SQLException e) {
|
||||
logger.error("网关:" + instanceVo.getRunId() + "关闭失败" + e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getActiveDeviceIds() {
|
||||
|
||||
Set<String> set = Sets.newConcurrentHashSet();
|
||||
|
||||
if (StringUtils.isNotEmpty(deviceId)) {
|
||||
set.add(deviceId);
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
}
|
52
src/main/java/com/cisdi/data/DIClient/DIClientTest.java
Normal file
52
src/main/java/com/cisdi/data/DIClient/DIClientTest.java
Normal file
@ -0,0 +1,52 @@
|
||||
package com.cisdi.data.DIClient;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.DIClient.bean.DIClientCnfg;
|
||||
import com.cisdi.data.DIClient.gateway.DBReader;
|
||||
import com.cisdi.data.DIClient.gateway.DBTask;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.enums.GatewayState;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
public class DIClientTest {
|
||||
public static void main(String[] args) throws UnsupportedEncodingException {
|
||||
char x=0x03;
|
||||
String test="20210408195055077MR001 N11001001 yf R一级焦炭 Bt 7.000 2 Y99999.0000 0.0000 0.0000 0.0000 B020 ";
|
||||
String value="7.000 ";
|
||||
value=value.trim();
|
||||
int splitIndex = value.length() - 3;
|
||||
|
||||
String t="{\"cycleTime\":3000,\"dbName\":\"test\",\"driverClassName\":\"com.mysql.jdbc.Driver\",\"pwd\":\"yLNklB0v6Hu&J2T!\",\"url\":\"jdbc:mysql://10.232.12.58:3306/zgerp?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false\",\"user\":\"root\"} ";
|
||||
|
||||
String prev = value.substring(0, splitIndex-1);
|
||||
String end = value.substring(splitIndex);
|
||||
|
||||
DIClientCnfg diClientCnfg=new DIClientCnfg();
|
||||
diClientCnfg.setCycleTime((long) 3000);
|
||||
diClientCnfg.setDbName("test");
|
||||
diClientCnfg.setDriverClassName("com.mysql.jdbc.Driver");
|
||||
diClientCnfg.setUrl("jdbc:mysql://10.232.12.58:3306/zgerp?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false");
|
||||
diClientCnfg.setUser("root");
|
||||
diClientCnfg.setPwd("yLNklB0v6Hu&J2T!");
|
||||
|
||||
System.out.println(JSON.toJSONString(diClientCnfg));
|
||||
boolean open = false;
|
||||
DBReader dbReader=new DBReader(diClientCnfg.getDriverClassName(),diClientCnfg.getUrl(),diClientCnfg.getUser(),diClientCnfg.getPwd());
|
||||
open=dbReader.connectionInternal(0);
|
||||
if(open == true) {
|
||||
DBTask dbTask=new DBTask(null,null,dbReader,diClientCnfg.getCycleTime(),"");
|
||||
dbTask.start();
|
||||
|
||||
|
||||
try {
|
||||
Thread.sleep(10000000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("DIClient网关:{}启动成功 参数:{}");
|
||||
}else {
|
||||
System.out.println("DIClient网关:{}启动失败 参数:{}");
|
||||
}
|
||||
}
|
||||
}
|
31
src/main/java/com/cisdi/data/DIClient/bean/DBFieldVo.java
Normal file
31
src/main/java/com/cisdi/data/DIClient/bean/DBFieldVo.java
Normal file
@ -0,0 +1,31 @@
|
||||
package com.cisdi.data.DIClient.bean;
|
||||
|
||||
public class DBFieldVo {
|
||||
private String filedName;
|
||||
private String as;
|
||||
private boolean orderBy;
|
||||
|
||||
public String getFiledName() {
|
||||
return filedName;
|
||||
}
|
||||
|
||||
public void setFiledName(String filedName) {
|
||||
this.filedName = filedName;
|
||||
}
|
||||
|
||||
public String getAs() {
|
||||
return as;
|
||||
}
|
||||
|
||||
public void setAs(String as) {
|
||||
this.as = as;
|
||||
}
|
||||
|
||||
public boolean isOrderBy() {
|
||||
return orderBy;
|
||||
}
|
||||
|
||||
public void setOrderBy(boolean orderBy) {
|
||||
this.orderBy = orderBy;
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package com.cisdi.data.DIClient.bean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DBTableTaskCnfg {
|
||||
private DBTableVo tableName;
|
||||
private List<DBFieldVo> fieldNames;
|
||||
private List<String> condition;
|
||||
private Long cycleTime;
|
||||
private String taskType;
|
||||
private String sortType;
|
||||
private String groupBy;
|
||||
private String msgKey;
|
||||
|
||||
public String getMsgKey() {
|
||||
return msgKey;
|
||||
}
|
||||
|
||||
public void setMsgKey(String msgKey) {
|
||||
this.msgKey = msgKey;
|
||||
}
|
||||
|
||||
public DBTableVo getTableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
public void setTableName(DBTableVo tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public List<DBFieldVo> getFieldNames() {
|
||||
return fieldNames;
|
||||
}
|
||||
|
||||
public void setFieldNames(List<DBFieldVo> fieldNames) {
|
||||
this.fieldNames = fieldNames;
|
||||
}
|
||||
|
||||
public List<String> getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public void setCondition(List<String> condition) {
|
||||
this.condition = condition;
|
||||
}
|
||||
|
||||
public Long getCycleTime() {
|
||||
return cycleTime;
|
||||
}
|
||||
|
||||
public void setCycleTime(Long cycleTime) {
|
||||
this.cycleTime = cycleTime;
|
||||
}
|
||||
|
||||
public String getTaskType() {
|
||||
return taskType;
|
||||
}
|
||||
|
||||
public void setTaskType(String taskType) {
|
||||
this.taskType = taskType;
|
||||
}
|
||||
|
||||
public String getSortType() {
|
||||
return sortType;
|
||||
}
|
||||
|
||||
public void setSortType(String sortType) {
|
||||
this.sortType = sortType;
|
||||
}
|
||||
|
||||
public String getGroupBy() {
|
||||
return groupBy;
|
||||
}
|
||||
|
||||
public void setGroupBy(String groupBy) {
|
||||
this.groupBy = groupBy;
|
||||
}
|
||||
}
|
40
src/main/java/com/cisdi/data/DIClient/bean/DBTableVo.java
Normal file
40
src/main/java/com/cisdi/data/DIClient/bean/DBTableVo.java
Normal file
@ -0,0 +1,40 @@
|
||||
package com.cisdi.data.DIClient.bean;
|
||||
|
||||
public class DBTableVo {
|
||||
private DBTableVo leftTable;
|
||||
private String rightTable;
|
||||
private String joinType;
|
||||
private String on;
|
||||
|
||||
public DBTableVo getLeftTable() {
|
||||
return leftTable;
|
||||
}
|
||||
|
||||
public void setLeftTable(DBTableVo leftTable) {
|
||||
this.leftTable = leftTable;
|
||||
}
|
||||
|
||||
public String getRightTable() {
|
||||
return rightTable;
|
||||
}
|
||||
|
||||
public void setRightTable(String rightTable) {
|
||||
this.rightTable = rightTable;
|
||||
}
|
||||
|
||||
public String getJoinType() {
|
||||
return joinType;
|
||||
}
|
||||
|
||||
public void setJoinType(String joinType) {
|
||||
this.joinType = joinType;
|
||||
}
|
||||
|
||||
public String getOn() {
|
||||
return on;
|
||||
}
|
||||
|
||||
public void setOn(String on) {
|
||||
this.on = on;
|
||||
}
|
||||
}
|
72
src/main/java/com/cisdi/data/DIClient/bean/DIClientCnfg.java
Normal file
72
src/main/java/com/cisdi/data/DIClient/bean/DIClientCnfg.java
Normal file
@ -0,0 +1,72 @@
|
||||
package com.cisdi.data.DIClient.bean;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DIClientCnfg {
|
||||
private String dbName;
|
||||
private String url;
|
||||
private String user;
|
||||
private String pwd;
|
||||
private String driverClassName;
|
||||
private Long cycleTime;
|
||||
//TASK名字,TASK筛选条件
|
||||
// Map<String, DBTableTaskCnfg> taskMap;
|
||||
|
||||
|
||||
public Long getCycleTime() {
|
||||
return cycleTime;
|
||||
}
|
||||
|
||||
public void setCycleTime(Long cycleTime) {
|
||||
this.cycleTime = cycleTime;
|
||||
}
|
||||
|
||||
public String getDbName() {
|
||||
return dbName;
|
||||
}
|
||||
|
||||
public void setDbName(String dbName) {
|
||||
this.dbName = dbName;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public String getPwd() {
|
||||
return pwd;
|
||||
}
|
||||
|
||||
public void setPwd(String pwd) {
|
||||
this.pwd = pwd;
|
||||
}
|
||||
|
||||
public String getDriverClassName() {
|
||||
return driverClassName;
|
||||
}
|
||||
|
||||
public void setDriverClassName(String driverClassName) {
|
||||
this.driverClassName = driverClassName;
|
||||
}
|
||||
|
||||
// public Map<String, DBTableTaskCnfg> getTaskMap() {
|
||||
// return taskMap;
|
||||
// }
|
||||
//
|
||||
// public void setTaskMap(Map<String, DBTableTaskCnfg> taskMap) {
|
||||
// this.taskMap = taskMap;
|
||||
// }
|
||||
}
|
76
src/main/java/com/cisdi/data/DIClient/bean/PDIOVo.java
Normal file
76
src/main/java/com/cisdi/data/DIClient/bean/PDIOVo.java
Normal file
@ -0,0 +1,76 @@
|
||||
package com.cisdi.data.DIClient.bean;
|
||||
|
||||
public class PDIOVo {
|
||||
private Long timeStamp;
|
||||
private Integer serialNo;
|
||||
private String queueId;
|
||||
private String header;
|
||||
private String data;
|
||||
private String status;
|
||||
private String processTime;
|
||||
private String description;
|
||||
|
||||
public Long getTimeStamp() {
|
||||
return timeStamp;
|
||||
}
|
||||
|
||||
public void setTimeStamp(Long timeStamp) {
|
||||
this.timeStamp = timeStamp;
|
||||
}
|
||||
|
||||
public Integer getSerialNo() {
|
||||
return serialNo;
|
||||
}
|
||||
|
||||
public void setSerialNo(Integer serialNo) {
|
||||
this.serialNo = serialNo;
|
||||
}
|
||||
|
||||
public String getQueueId() {
|
||||
return queueId;
|
||||
}
|
||||
|
||||
public void setQueueId(String queueId) {
|
||||
this.queueId = queueId;
|
||||
}
|
||||
|
||||
public String getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public void setHeader(String header) {
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getProcessTime() {
|
||||
return processTime;
|
||||
}
|
||||
|
||||
public void setProcessTime(String processTime) {
|
||||
this.processTime = processTime;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
215
src/main/java/com/cisdi/data/DIClient/gateway/DBReader.java
Normal file
215
src/main/java/com/cisdi/data/DIClient/gateway/DBReader.java
Normal file
@ -0,0 +1,215 @@
|
||||
package com.cisdi.data.DIClient.gateway;
|
||||
|
||||
import com.cisdi.data.DIClient.bean.PDIOVo;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.*;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Date;
|
||||
|
||||
public class DBReader
|
||||
{
|
||||
Logger logger= LoggerFactory.getLogger(DBReader.class);
|
||||
|
||||
/**
|
||||
* JDBC的连接对象实例
|
||||
*/
|
||||
private Connection conn = null;
|
||||
private String driver;
|
||||
private String url;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
public DBReader(String driver, String url, String username, String password) {
|
||||
this.driver = driver;
|
||||
this.url = url;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public void reconnect()
|
||||
{
|
||||
logger.info("由于发生了异常,正在尝试重连");
|
||||
try {
|
||||
if(conn!=null&&!conn.isClosed())
|
||||
{
|
||||
conn.close();
|
||||
}
|
||||
connectionInternal(0);
|
||||
} catch (SQLException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean connectionInternal(int reconnectNumber) {
|
||||
try {
|
||||
Class.forName(driver);
|
||||
conn = DriverManager.getConnection(url, username, password);
|
||||
logger.info("【DI Client】建立与mysql数据库(URL:" + url + ")的连接");
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
|
||||
logger.error("【DI Client】SQL:连接失败,等待重连,剩余重连次数" + reconnectNumber + " 异常信息:" + e.getLocalizedMessage());
|
||||
reconnectNumber=reconnectNumber-1;
|
||||
if (reconnectNumber <= 0) {
|
||||
logger.error("【DI Client】SQL:重连失败,DIClient连接启动失败");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (Exception e1) {
|
||||
logger.info("【DI Client】SQL:等待失败,进程退出");
|
||||
}
|
||||
return this.connectionInternal(reconnectNumber);
|
||||
}
|
||||
}
|
||||
public void close() throws SQLException {
|
||||
if(conn!=null&&!conn.isClosed())
|
||||
{
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
|
||||
public int getTotal()
|
||||
{
|
||||
String sql = "select count(*) from TBDIPDI where status='N' ";
|
||||
ResultSet myResult = null;
|
||||
PreparedStatement pre = null;
|
||||
try {
|
||||
pre = conn.prepareStatement(sql);
|
||||
myResult = pre.executeQuery();
|
||||
while (myResult.next()) {
|
||||
return myResult.getInt("count(*)");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("【DB】SQL语句" + sql + "执行失败,请检查配置文件是否正确,以及数据表是否更改:" + e.getLocalizedMessage(), e);
|
||||
reconnect();
|
||||
} finally {
|
||||
closeObj(myResult);
|
||||
closeObj(pre);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public List<PDIOVo> getPDIOs(int limit)
|
||||
{
|
||||
List<PDIOVo> rt=new ArrayList<>();
|
||||
String sql = "select timestamp,serialno,queueid,header,data,status,processtime,description from TBDIPDI where status='N' order by TIMESTAMP,SerialNo asc limit "+limit;
|
||||
ResultSet myResult = null;
|
||||
PreparedStatement pre = null;
|
||||
try {
|
||||
pre = conn.prepareStatement(sql);
|
||||
myResult = pre.executeQuery();
|
||||
while (myResult.next()) {
|
||||
PDIOVo pdioVo=new PDIOVo();
|
||||
pdioVo.setTimeStamp(myResult.getLong("timestamp"));
|
||||
pdioVo.setSerialNo(myResult.getInt("serialno"));
|
||||
pdioVo.setQueueId(myResult.getString("queueid"));
|
||||
pdioVo.setHeader(myResult.getString("header"));
|
||||
pdioVo.setData(myResult.getString("data"));
|
||||
pdioVo.setStatus(myResult.getString("status"));
|
||||
pdioVo.setProcessTime(myResult.getString("processtime"));
|
||||
pdioVo.setDescription(myResult.getString("description"));
|
||||
rt.add(pdioVo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("【DB】SQL语句" + sql + "执行失败,请检查配置文件是否正确,以及数据表是否更改:" + e.getLocalizedMessage(), e);
|
||||
reconnect();
|
||||
|
||||
} finally {
|
||||
closeObj(myResult);
|
||||
closeObj(pre);
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
|
||||
private void closeObj(Object obj) {
|
||||
if (obj == null) {
|
||||
return;
|
||||
}
|
||||
if (obj instanceof PreparedStatement) {
|
||||
PreparedStatement prepare = (PreparedStatement) obj;
|
||||
try {
|
||||
prepare.close();
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
if (obj instanceof ResultSet) {
|
||||
ResultSet resultSet = (ResultSet) obj;
|
||||
try {
|
||||
resultSet.close();
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
throw new BusinessException("not support type" + obj.getClass());
|
||||
}
|
||||
|
||||
public void updateStatus(List<PDIOVo> pdioVos,char status,String desc)
|
||||
{
|
||||
if(pdioVos==null||pdioVos.size()==0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
String inStr="(";
|
||||
for(PDIOVo pdioVo:pdioVos)
|
||||
{
|
||||
inStr+="("+pdioVo.getTimeStamp()+","+pdioVo.getSerialNo()+"),";
|
||||
}
|
||||
if(inStr.contains("),"))
|
||||
{
|
||||
inStr=inStr.substring(0,inStr.length()-1);
|
||||
}
|
||||
inStr+=")";
|
||||
List<PDIOVo> rt=new ArrayList<>();
|
||||
|
||||
Date date=new Date();
|
||||
DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
String sql = "update TBDIPDI set status='"+status+"', processtime='"+format.format(date)+"'"+ (StringUtils.isBlank(desc)?"":",description='"+desc+"'") +" where (timestamp,serialno) in "+ inStr;
|
||||
int myResultCount = 0;
|
||||
PreparedStatement pre = null;
|
||||
try {
|
||||
pre = conn.prepareStatement(sql);
|
||||
myResultCount = pre.executeUpdate();
|
||||
if(myResultCount!=pdioVos.size())
|
||||
{
|
||||
logger.error("【DB】部分数据更新失败,入参"+pdioVos.size()+"条,更新了"+myResultCount+"条");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("【DB】SQL语句" + sql + "执行失败,请检查配置文件是否正确,以及数据表是否更改:" + e.getLocalizedMessage(), e);
|
||||
reconnect();
|
||||
} finally {
|
||||
closeObj(pre);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPDIOs(PDIOVo pdioVos)
|
||||
{
|
||||
String sql = "insert into TBDIPDO (TBDIPDO.`TimeStamp`,TBDIPDO.SerialNo,TBDIPDO.QueueId,TBDIPDO.Header,TBDIPDO.`Data`,TBDIPDO.`Status`) value ("+pdioVos.getTimeStamp()+","+pdioVos.getSerialNo()+",'"+pdioVos.getQueueId()+"','"+pdioVos.getHeader()+"','"+pdioVos.getData()+"','"+pdioVos.getStatus()+"')";
|
||||
int myResultCount = 0;
|
||||
PreparedStatement pre = null;
|
||||
try {
|
||||
pre = conn.prepareStatement(sql);
|
||||
myResultCount = pre.executeUpdate();
|
||||
if(myResultCount!=1)
|
||||
{
|
||||
logger.error("【DB】部分数据插入失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("【DB】SQL语句" + sql + "执行失败,请检查配置文件是否正确,以及数据表是否更改:" + e.getLocalizedMessage(), e);
|
||||
reconnect();
|
||||
} finally {
|
||||
closeObj(pre);
|
||||
}
|
||||
}
|
||||
}
|
137
src/main/java/com/cisdi/data/DIClient/gateway/DBTask.java
Normal file
137
src/main/java/com/cisdi/data/DIClient/gateway/DBTask.java
Normal file
@ -0,0 +1,137 @@
|
||||
package com.cisdi.data.DIClient.gateway;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.DIClient.bean.DBFieldVo;
|
||||
import com.cisdi.data.DIClient.bean.DBTableTaskCnfg;
|
||||
import com.cisdi.data.DIClient.bean.PDIOVo;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
|
||||
import com.cisdi.data.sdk.gateway.message.SocketMessage;
|
||||
import com.cisdi.data.sdk.service.DynamicCodecService;
|
||||
import com.cisdi.data.sdk.service.SendService;
|
||||
import com.cisdi.data.sdk.service.ServiceProvider;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DBTask extends Thread {
|
||||
|
||||
Logger logger= LoggerFactory.getLogger(DBTask.class);
|
||||
private ServiceProvider serviceProvider;
|
||||
private SocketGatewayBase socketGateway;
|
||||
private DBReader dbReader;
|
||||
private Long cycleTime;
|
||||
private boolean shouldRun;
|
||||
private String deviceId;
|
||||
private long lastTime=0;
|
||||
private int lastNo=0;
|
||||
public DBTask(ServiceProvider serviceProvider, SocketGatewayBase socketGateway, DBReader dbReader,Long cycleTime,String deviceId) {
|
||||
this.serviceProvider = serviceProvider;
|
||||
this.socketGateway = socketGateway;
|
||||
this.dbReader = dbReader;
|
||||
this.cycleTime=cycleTime;
|
||||
shouldRun=true;
|
||||
this.deviceId=deviceId;
|
||||
}
|
||||
|
||||
public boolean close() throws SQLException {
|
||||
dbReader.close();
|
||||
shouldRun=false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void sendMessage(PDIOVo pdioVo)
|
||||
{
|
||||
dbReader.addPDIOs(pdioVo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (shouldRun)
|
||||
{
|
||||
long startTime=System.currentTimeMillis();
|
||||
while(true)
|
||||
{
|
||||
int total=dbReader.getTotal();
|
||||
List<PDIOVo> pdioVoList=dbReader.getPDIOs(2000);
|
||||
if(pdioVoList!=null&&pdioVoList.size()>0)
|
||||
{
|
||||
List<PDIOVo> successList=new ArrayList<>();
|
||||
List<PDIOVo> errorList=new ArrayList<>();
|
||||
String error="";
|
||||
if(serviceProvider==null||socketGateway==null)
|
||||
{
|
||||
for(PDIOVo pdioVo:pdioVoList)
|
||||
{
|
||||
sendMessage(pdioVo);
|
||||
System.out.println(JSON.toJSONString(pdioVo));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SendService service = (SendService)serviceProvider.getByName(ServiceName.Send);
|
||||
DynamicCodecService dynamicCodecService=(DynamicCodecService)serviceProvider.getByName(ServiceName.DynamicCodec);
|
||||
for(PDIOVo pdioVo:pdioVoList)
|
||||
{
|
||||
try
|
||||
{
|
||||
String paramObj = dynamicCodecService.findByRunIdAndMsgKey(socketGateway.getInstanceVo().getRunId(), pdioVo.getQueueId());
|
||||
if(StringUtils.isBlank(paramObj))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
|
||||
SocketMessage socketMessage = socketGateway.buildSocketMessage();
|
||||
socketMessage.setDeviceId(this.deviceId);
|
||||
socketMessage.setMsgKey(pdioVo.getQueueId());
|
||||
socketMessage.setData(pdioVo.getData().getBytes("GBK"));
|
||||
socketMessage.getPropsMap().put("charset", Charset.forName("GBK"));
|
||||
service.sendMessage(socketMessage);
|
||||
successList.add(pdioVo);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
pdioVo.setDescription(e.getLocalizedMessage());
|
||||
errorList.add(pdioVo);
|
||||
error=e.getLocalizedMessage();
|
||||
}
|
||||
}
|
||||
if(errorList.size() > 0)
|
||||
{
|
||||
dbReader.updateStatus(errorList,'E',error);
|
||||
}
|
||||
if(successList.size() > 0)
|
||||
{
|
||||
dbReader.updateStatus(successList,'O',"");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(pdioVoList.size()==0||pdioVoList.size()==total)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
long endTime=System.currentTimeMillis();
|
||||
try {
|
||||
if(endTime-startTime<=cycleTime)
|
||||
{
|
||||
Thread.sleep(cycleTime-(endTime-startTime));
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
64
src/main/java/com/cisdi/data/DIClient/gateway/MysqlPool.txt
Normal file
64
src/main/java/com/cisdi/data/DIClient/gateway/MysqlPool.txt
Normal file
@ -0,0 +1,64 @@
|
||||
//package com.cisdi.data.DIClient.gateway;
|
||||
//
|
||||
//import org.apache.commons.dbcp2.BasicDataSourceFactory;
|
||||
//
|
||||
//import javax.security.auth.login.Configuration;
|
||||
//import javax.sql.DataSource;
|
||||
//import java.sql.Connection;
|
||||
//import java.sql.SQLException;
|
||||
//import java.util.Properties;
|
||||
//
|
||||
//public class MysqlPool {
|
||||
// private String driver;
|
||||
// private String url;
|
||||
// private String username;
|
||||
// private String password;
|
||||
// private Long removeTimeOut;
|
||||
// private int maxTotal;
|
||||
//
|
||||
// private DataSource dataSource=null;
|
||||
//
|
||||
// public MysqlPool(String driver, String url, String username, String password, Long removeTimeOut, int maxTotal) {
|
||||
// this.driver = driver;
|
||||
// this.url = url;
|
||||
// this.username = username;
|
||||
// this.password = password;
|
||||
// this.removeTimeOut = removeTimeOut;
|
||||
// this.maxTotal = maxTotal;
|
||||
// }
|
||||
//
|
||||
// public boolean init()
|
||||
// {
|
||||
// Properties properties=new Properties();
|
||||
// properties.setProperty("driverClassName",driver);
|
||||
// properties.setProperty("url",url);
|
||||
// properties.setProperty("username",username);
|
||||
// properties.setProperty("password",password);
|
||||
// properties.setProperty("initialSize",String.valueOf(maxTotal));
|
||||
// properties.setProperty("maxTotal",String.valueOf(maxTotal));
|
||||
// properties.setProperty("maxIdle",String.valueOf(maxTotal/2));
|
||||
// properties.setProperty("minIdle",String.valueOf(maxTotal/4));
|
||||
// properties.setProperty("maxWaitMillis",String.valueOf(1000));
|
||||
// properties.setProperty("removeAbandonedTimeout",String.valueOf(removeTimeOut));
|
||||
// properties.setProperty("removeAbandonedOnMaintenance",String.valueOf(true));
|
||||
// properties.setProperty("removeAbandonedOnBorrow",String.valueOf(true));
|
||||
// try {
|
||||
// dataSource= BasicDataSourceFactory.createDataSource(properties);
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// public Connection getConnection()
|
||||
// {
|
||||
// Connection connection=null;
|
||||
// try
|
||||
// {
|
||||
// connection=dataSource.getConnection();
|
||||
// connection.setAutoCommit(false);
|
||||
// } catch (SQLException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// return connection;
|
||||
// }
|
||||
//}
|
@ -0,0 +1,127 @@
|
||||
package com.cisdi.data.DIClient.protocol;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.DIClient.protocol.utils.IXComActionParamDTO;
|
||||
import com.cisdi.data.DIClient.protocol.utils.IXComCodecService;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.gateway.message.SocketMessage;
|
||||
import com.cisdi.data.sdk.procotol.SocketProtocol;
|
||||
import com.cisdi.data.sdk.procotol.base.ProtocolBase;
|
||||
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
|
||||
import com.cisdi.data.sdk.service.DynamicCodecService;
|
||||
import com.cisdi.data.sdk.service.RouteService;
|
||||
import com.cisdi.data.sdk.vo.DecodeVo;
|
||||
import com.cisdi.data.sdk.vo.DeviceVo;
|
||||
import com.cisdi.data.sdk.vo.ReturnVo;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: lhp
|
||||
* @date: 2019/10/8
|
||||
**/
|
||||
public class IXCom29DStringSocketProtocol extends ProtocolBase implements SocketProtocol {
|
||||
|
||||
@Override
|
||||
public DecodeVo deCode(SocketMessage message) {
|
||||
if (message == null || message.getRunId() == null || message.getPropsMap() == null || message.getDeviceId() == null) {
|
||||
throw new BusinessException("解析入参错误1,msg为:" + message.toString());
|
||||
}
|
||||
|
||||
DynamicCodecService service = (DynamicCodecService)serviceProvider.getByName(ServiceName.DynamicCodec);
|
||||
if (service == null || !(service instanceof DynamicCodecService)) {
|
||||
throw new BusinessException("获取DynamicCodecService失败");
|
||||
}
|
||||
String paramObj = service.findByRunIdAndMsgKey(message.getRunId(), message.getMsgKey());
|
||||
Charset charset = Charset.forName(String.valueOf(message.getPropsMap().get("charset")));
|
||||
|
||||
byte[] data = message.getData();
|
||||
|
||||
if(data == null || paramObj == null) {
|
||||
throw new BusinessException("解析入参错误2,msg为:" + message.toString());
|
||||
}
|
||||
|
||||
IXComActionParamDTO dto = JSON.parseObject(paramObj, IXComActionParamDTO.class);
|
||||
dto.setMsgKey(message.getMsgKey());
|
||||
if(dto == null || dto.getPropertyList().size() == 0) {
|
||||
throw new BusinessException("解析入参错误3,msg为:" + message.toString());
|
||||
}
|
||||
|
||||
DecodeVo vo = new DecodeVo();
|
||||
|
||||
IXComCodecService defaultService = new IXComCodecService();
|
||||
|
||||
Map<String,Object> map = defaultService.decode(message.getRunId(), dto, data, charset);
|
||||
vo.setData(map);
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketReturnMessage enCode(ReturnVo returnVo) {
|
||||
|
||||
if (returnVo == null || returnVo.getValue() == null || returnVo.getDeviceId() == null) {
|
||||
throw new BusinessException("解析入参错误1,msg为:" + JSON.toJSONString(returnVo));
|
||||
}
|
||||
|
||||
DynamicCodecService service = (DynamicCodecService)serviceProvider.getByName(ServiceName.DynamicCodec);
|
||||
if (service == null || !(service instanceof DynamicCodecService)) {
|
||||
throw new BusinessException("获取DynamicCodecService失败");
|
||||
}
|
||||
RouteService routeService = (RouteService)serviceProvider.getByName(ServiceName.Route);
|
||||
if (service == null || !(routeService instanceof RouteService)) {
|
||||
throw new BusinessException("获取RouteService失败");
|
||||
}
|
||||
DeviceVo deviceVo=routeService.findDeviceByDeviceId(returnVo.getDeviceId());
|
||||
if(deviceVo==null|| StringUtils.isBlank(deviceVo.getRunId()))
|
||||
{
|
||||
throw new BusinessException("获取DeviceVo失败");
|
||||
}
|
||||
String paramObj = service.findByRunIdAndMsgKey(deviceVo.getRunId(), returnVo.getMsgKey());
|
||||
Charset charset = Charset.forName(String.valueOf(Charset.forName("GBK")));
|
||||
IXComActionParamDTO dto = JSON.parseObject(paramObj, IXComActionParamDTO.class);
|
||||
if(dto == null || dto.getPropertyList().size() == 0) {
|
||||
throw new BusinessException("解析入参错误3,msg为:" + JSON.toJSONString(returnVo));
|
||||
}
|
||||
|
||||
StringBuilder data= new StringBuilder();
|
||||
|
||||
for(IXComActionParamDTO.PropertyConfig propertyConfig:dto.getPropertyList())
|
||||
{
|
||||
if(!returnVo.getValue().containsKey(propertyConfig.getPropertyId()))
|
||||
{
|
||||
throw new BusinessException("解析入参错误4,msg为:" + JSON.toJSONString(returnVo)+"在runId="+deviceVo.getRunId()+";msgKey="+returnVo.getMsgKey()+"的情况下,入参缺失"+propertyConfig.getPropertyId());
|
||||
}
|
||||
StringBuilder tmp= new StringBuilder(String.valueOf(returnVo.getValue().get(propertyConfig.getPropertyId())));
|
||||
int tmpLength= 0;
|
||||
try {
|
||||
tmpLength = tmp.toString().getBytes("GBK").length;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new BusinessException("解析入参错误5,msg为:" + JSON.toJSONString(returnVo)+"在runId="+deviceVo.getRunId()+";msgKey="+returnVo.getMsgKey()+"的情况下,入参"+propertyConfig.getPropertyId()+"转换GBK失败"+e.getLocalizedMessage());
|
||||
}
|
||||
if(propertyConfig.getFixedLength()!=0&&tmpLength<propertyConfig.getFixedLength())
|
||||
{
|
||||
for(int i=0;i<(propertyConfig.getFixedLength()-tmpLength);i++)
|
||||
{
|
||||
tmp.append(" ");
|
||||
}
|
||||
}
|
||||
else if(propertyConfig.getFixedLength()!=0&&tmp.length()>propertyConfig.getFixedLength())
|
||||
{
|
||||
throw new BusinessException("解析入参错误6,msg为:" + JSON.toJSONString(returnVo)+"在runId="+deviceVo.getRunId()+";msgKey="+returnVo.getMsgKey()+"的情况下,入参过长"+propertyConfig.getPropertyId());
|
||||
}
|
||||
data.append(tmp);
|
||||
}
|
||||
|
||||
SocketReturnMessage rt=new SocketReturnMessage();
|
||||
rt.setDeviceId(returnVo.getDeviceId());
|
||||
rt.setMsgId(returnVo.getMsgId());
|
||||
rt.setMsgKey(returnVo.getMsgKey());
|
||||
rt.setData(data.toString().getBytes());
|
||||
return rt;
|
||||
}
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
package com.cisdi.data.DIClient.protocol.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: lhp
|
||||
* @date: 2019/10/8
|
||||
**/
|
||||
|
||||
public class IXComActionParamDTO {
|
||||
|
||||
public enum PropertyType {
|
||||
BYTE,
|
||||
BOOLEAN,
|
||||
SHORT,
|
||||
INT,
|
||||
FLOAT,
|
||||
DOUBLE,
|
||||
STRING,
|
||||
LONG,
|
||||
PLACEHOLDER;
|
||||
}
|
||||
|
||||
/**
|
||||
* 属性列表
|
||||
*/
|
||||
private List<PropertyConfig> propertyList;
|
||||
|
||||
/**
|
||||
* 电文号
|
||||
*/
|
||||
private String msgKey;
|
||||
|
||||
/**
|
||||
* 是否透传
|
||||
*/
|
||||
private Boolean isPassthrough;
|
||||
|
||||
public Boolean getIsPassthrough() {
|
||||
return isPassthrough;
|
||||
}
|
||||
|
||||
public void setIsPassthrough(Boolean isPassthrough) {
|
||||
this.isPassthrough = isPassthrough;
|
||||
}
|
||||
|
||||
public String getMsgKey() {
|
||||
return msgKey;
|
||||
}
|
||||
|
||||
public void setMsgKey(String msgKey) {
|
||||
this.msgKey = msgKey;
|
||||
}
|
||||
|
||||
public void appendProperty(PropertyConfig propertyConfig) {
|
||||
|
||||
if (propertyConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (propertyList == null) {
|
||||
propertyList = new ArrayList<>();
|
||||
}
|
||||
propertyList.add(propertyConfig);
|
||||
}
|
||||
|
||||
public static class PropertyConfig{
|
||||
|
||||
/** 属性Id*/
|
||||
private String propertyId;
|
||||
|
||||
/** 属性类型*/
|
||||
private PropertyType propertyType;
|
||||
|
||||
/**固定长度*/
|
||||
private Integer fixedLength;
|
||||
|
||||
/**精度*/
|
||||
private Integer precision;
|
||||
|
||||
public String getPropertyId() {
|
||||
return propertyId;
|
||||
}
|
||||
|
||||
public void setPropertyId(String propertyId) {
|
||||
this.propertyId = propertyId;
|
||||
}
|
||||
|
||||
public PropertyType getPropertyType() {
|
||||
return propertyType;
|
||||
}
|
||||
|
||||
public void setPropertyType(PropertyType propertyType) {
|
||||
this.propertyType = propertyType;
|
||||
}
|
||||
|
||||
public Integer getFixedLength() {
|
||||
return fixedLength;
|
||||
}
|
||||
|
||||
public void setFixedLength(Integer fixedLength) {
|
||||
this.fixedLength = fixedLength;
|
||||
}
|
||||
|
||||
public Integer getPrecision() {
|
||||
return precision;
|
||||
}
|
||||
|
||||
public void setPrecision(Integer precision) {
|
||||
this.precision = precision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PropertyConfig [propertyId=" + propertyId + ", propertyType=" + propertyType + ", fixedLength="
|
||||
+ fixedLength + ", precision=" + precision + "]";
|
||||
}
|
||||
}
|
||||
|
||||
public List<PropertyConfig> getPropertyList() {
|
||||
return propertyList;
|
||||
}
|
||||
|
||||
public void setPropertyList(List<PropertyConfig> propertyList) {
|
||||
this.propertyList = propertyList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IXComActionParamDTO [propertyList=" + propertyList + ", isPassthrough=" + isPassthrough + "]";
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
package com.cisdi.data.DIClient.protocol.utils;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.service.DynamicCodecService;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: lhp
|
||||
* @date: 2019/10/8
|
||||
**/
|
||||
public class IXComCodecService {
|
||||
|
||||
public Map<String, Object> decode(String runId, IXComActionParamDTO dto, byte[] data, Charset charset) {
|
||||
int sumLen = 0;
|
||||
|
||||
try{
|
||||
sumLen = dto.getPropertyList().stream().mapToInt(IXComActionParamDTO.PropertyConfig::getFixedLength).sum();
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException("连接id:" + String.valueOf(runId) + "电文号:" + String.valueOf(dto.getMsgKey()) +
|
||||
" ixcom29d解析数据长度失败", e);
|
||||
}
|
||||
|
||||
if (sumLen != data.length) {
|
||||
if(dto.getPropertyList().get(dto.getPropertyList().size()-1).getFixedLength()!=0)
|
||||
{
|
||||
throw new BusinessException("连接id:" + String.valueOf(runId) + "电文号:" + String.valueOf(dto.getMsgKey()) +
|
||||
" ixcom29d解析长度与数据长度不一致错误, 解析数据长度为: " + data.length + " 配置长度为: " + sumLen);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(data);
|
||||
|
||||
for(int i=0;i<dto.getPropertyList().size();i++)
|
||||
{
|
||||
if (dto.getPropertyList().get(i) != null) {
|
||||
IXComActionParamDTO.PropertyConfig property=dto.getPropertyList().get(i);
|
||||
if(i==dto.getPropertyList().size()-1&&property.getFixedLength()==0)
|
||||
{
|
||||
property.setFixedLength(byteBuffer.array().length-sumLen);
|
||||
}
|
||||
Object object = IXComConverterUtils.convertProperty(property, byteBuffer, charset,runId,dto.getMsgKey());
|
||||
if (object != null) {
|
||||
map.put(property.getPropertyId(), object);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试类*/
|
||||
public static class TestDynamicCodecHelperImpl implements DynamicCodecService {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findByRunIdAndMsgKey(String runId, String msgKey) {
|
||||
IXComActionParamDTO dto = new IXComActionParamDTO();
|
||||
IXComActionParamDTO.PropertyConfig config = new IXComActionParamDTO.PropertyConfig();
|
||||
config.setPropertyId("boolean");
|
||||
config.setPropertyType(IXComActionParamDTO.PropertyType.BOOLEAN);
|
||||
config.setFixedLength(1);
|
||||
dto.appendProperty(config);
|
||||
IXComActionParamDTO.PropertyConfig config1 = new IXComActionParamDTO.PropertyConfig();
|
||||
config1.setPropertyId("short");
|
||||
config1.setPropertyType(IXComActionParamDTO.PropertyType.SHORT);
|
||||
config1.setFixedLength(1);
|
||||
IXComActionParamDTO.PropertyConfig config2 = new IXComActionParamDTO.PropertyConfig();
|
||||
config2.setPropertyId("int");
|
||||
config2.setPropertyType(IXComActionParamDTO.PropertyType.INT);
|
||||
config2.setFixedLength(4);
|
||||
IXComActionParamDTO.PropertyConfig config3 = new IXComActionParamDTO.PropertyConfig();
|
||||
config3.setPropertyId("long");
|
||||
config3.setPropertyType(IXComActionParamDTO.PropertyType.LONG);
|
||||
config3.setFixedLength(4);
|
||||
IXComActionParamDTO.PropertyConfig config4 = new IXComActionParamDTO.PropertyConfig();
|
||||
config4.setPropertyId("string");
|
||||
config4.setPropertyType(IXComActionParamDTO.PropertyType.STRING);
|
||||
config4.setFixedLength(10);
|
||||
IXComActionParamDTO.PropertyConfig config5 = new IXComActionParamDTO.PropertyConfig();
|
||||
config5.setPropertyId("double");
|
||||
config5.setPropertyType(IXComActionParamDTO.PropertyType.DOUBLE);
|
||||
config5.setFixedLength(8);
|
||||
|
||||
IXComActionParamDTO.PropertyConfig config6 = new IXComActionParamDTO.PropertyConfig();
|
||||
config6.setPropertyId("");
|
||||
config6.setPropertyType(IXComActionParamDTO.PropertyType.PLACEHOLDER);
|
||||
config6.setFixedLength(6);
|
||||
dto.appendProperty(config1);
|
||||
dto.appendProperty(config2);
|
||||
dto.appendProperty(config3);
|
||||
dto.appendProperty(config4);
|
||||
dto.appendProperty(config5);
|
||||
dto.appendProperty(config6);
|
||||
|
||||
return JSON.toJSONString(dto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean judgeBigEndianByRunId(String runId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean judgeBigEndianByDeviceId(String deviceId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findByRunIdAndMsgKeyNoCache(String runId, String msgKey) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void main(String[] args) {
|
||||
IXComCodecService service = new IXComCodecService();
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("boolean", true);
|
||||
map.put("short", Short.valueOf((short) 0xf2));
|
||||
map.put("int", Integer.valueOf(0x03));
|
||||
map.put("long", Long.valueOf(0xf4L));
|
||||
map.put("string",new String("1234567890"));
|
||||
map.put("double", Double.valueOf(-123123213.3));
|
||||
Map<String, Object> map1 = JSON.parseObject(JSON.toJSONString(map));
|
||||
// System.out.println(Arrays.toString(service.encode(map, "1","2", "1")));
|
||||
// System.out.println(service.encode(map, "1","2","1").length);
|
||||
//System.out.println(service.decode(service.encode(map, "1","2","1"), "1", "2", "1"));
|
||||
}
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
package com.cisdi.data.DIClient.protocol.utils;
|
||||
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
|
||||
/**
|
||||
* @author: lhp
|
||||
* @date: 2019/10/8
|
||||
**/
|
||||
public class IXComConverterUtils {
|
||||
private static final char blankspace = ' ';
|
||||
|
||||
/**
|
||||
* 数字数据:则在不满位数时左补0:
|
||||
例如:421: “00421”在5位数字值的情况下
|
||||
-421: “-0421”
|
||||
字符串数据:则在不够长度时右补空格
|
||||
例如:TSB: “TSBDDDD”在7位字符串值的情况
|
||||
* @param config
|
||||
* @param reader
|
||||
* @return
|
||||
*/
|
||||
public static Object convertProperty(IXComActionParamDTO.PropertyConfig config, ByteBuffer reader, Charset charset,String runid,String msgKey) {
|
||||
|
||||
char[] buffer = null;
|
||||
|
||||
try {
|
||||
byte[] subBody = new byte[config.getFixedLength()];
|
||||
reader.get(subBody);
|
||||
|
||||
String subValue = new String(subBody, charset);
|
||||
buffer = subValue.toCharArray();
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException("ixcom29d读取字符数组失败" + e.getLocalizedMessage(), e);
|
||||
}
|
||||
|
||||
String value = new String(buffer);
|
||||
if(config.getPropertyType()!= IXComActionParamDTO.PropertyType.STRING&&StringUtils.isBlank(value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
switch (config.getPropertyType()) {
|
||||
case BYTE:
|
||||
return Byte.valueOf(value.trim());
|
||||
case SHORT:
|
||||
return Short.valueOf(value.trim());
|
||||
case INT:
|
||||
return Integer.valueOf(value.trim());
|
||||
case LONG:
|
||||
return Long.valueOf(value.trim());
|
||||
case BOOLEAN:
|
||||
value = value.trim().replaceFirst("0*", "");
|
||||
|
||||
if("true".equalsIgnoreCase(value) || "1".equals(value)) {
|
||||
return true;
|
||||
}else if("false".equalsIgnoreCase(value) || "0".equals(value)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case FLOAT:
|
||||
case DOUBLE:
|
||||
if(config.getPrecision() != null) {
|
||||
value=value.trim();
|
||||
BigDecimal decimal=null;
|
||||
if(config.getPrecision()!=0)
|
||||
{
|
||||
int splitIndex = value.length() - config.getPrecision();
|
||||
|
||||
if(splitIndex < 0) {
|
||||
throw new BusinessException("config:" + config + ",value:" + value + ",precision error");
|
||||
}
|
||||
|
||||
String prev = value.substring(0, splitIndex-1);
|
||||
String end = value.substring(splitIndex);
|
||||
|
||||
decimal= new BigDecimal(prev + "." + end);
|
||||
}
|
||||
else
|
||||
{
|
||||
decimal=new BigDecimal(value);
|
||||
}
|
||||
|
||||
return decimal;
|
||||
}else {
|
||||
return new BigDecimal(value);
|
||||
}
|
||||
case STRING:
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
int index = buffer.length;
|
||||
for (int i = buffer.length -1 ; i >= 0; i--) {
|
||||
|
||||
if(buffer[i] == blankspace) {
|
||||
index = i;
|
||||
continue;
|
||||
}else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < index; j++) {
|
||||
builder.append(buffer[j]);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
case PLACEHOLDER:
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new BusinessException("连接id:" + String.valueOf(runid) + "电文号:" + msgKey +
|
||||
" 解析数据类型错误:属性ID=" + config.getPropertyId()+"属性类型="+config.getPropertyType()+"属性精度="+config.getPrecision()+"属性长度="+config.getFixedLength()+"对应的值="+value+"错误为:"+e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
throw new BusinessException(config.toString() + "解析失败,ixcom29d");
|
||||
}
|
||||
}
|
138
src/main/java/com/cisdi/data/HJ212/YfHj212SocketGateway.java
Normal file
138
src/main/java/com/cisdi/data/HJ212/YfHj212SocketGateway.java
Normal file
@ -0,0 +1,138 @@
|
||||
package com.cisdi.data.HJ212;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.HJ212.gateway.AliveCheckTask;
|
||||
import com.cisdi.data.HJ212.gateway.Hj212ChannelInitializer;
|
||||
import com.cisdi.data.HJ212.gateway.Hj212FrameDecoder;
|
||||
import com.cisdi.data.HJ212.gateway.Hj212IoSession;
|
||||
import com.cisdi.data.HJ212.gateway.Hj212SessionFactory;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.enums.GatewayState;
|
||||
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
|
||||
import com.cisdi.data.sdk.param.ListenSocketParam;
|
||||
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
|
||||
import com.cisdi.data.sdk.service.RouteService;
|
||||
import com.cisdi.data.sdk.vo.DeviceVo;
|
||||
import com.cisdi.data.sdk.vo.ExeResultVo;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* 扬尘监测网络设备 HJ212协议数据接入
|
||||
* @author cup
|
||||
*
|
||||
*/
|
||||
public class YfHj212SocketGateway extends SocketGatewayBase {
|
||||
private static Logger logger = LoggerFactory.getLogger(YfHj212SocketGateway.class);
|
||||
private TcpIoService ioService = null;
|
||||
private SessionFactory sessionFactory = null;
|
||||
private AtomicBoolean shouldRun = null;
|
||||
private String deviceId;
|
||||
|
||||
@Override
|
||||
public ExeResultVo sendReturnMessage(SocketReturnMessage returnMsg) {
|
||||
throw new BusinessException("hj212网关不支持下发命令");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if(state == GatewayState.RUNNING) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("hj212网关:{}读取启动配置参数:{}",instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
|
||||
RouteService routeService = (RouteService)serviceProvider.getByName(ServiceName.Route);
|
||||
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
|
||||
|
||||
if(deviceVos.size() > 1) {
|
||||
throw new BusinessException("网关Id:" +instanceVo.getRunId() + "为hj212网关,只允许关联一个设备Id");
|
||||
}
|
||||
|
||||
deviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
|
||||
|
||||
if(StringUtils.isEmpty(deviceId)) {
|
||||
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
|
||||
}
|
||||
|
||||
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
|
||||
SessionFactory factory = new Hj212SessionFactory(deviceId);
|
||||
factory.init(serviceProvider, this);
|
||||
|
||||
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
|
||||
|
||||
Hj212ChannelInitializer<Hj212FrameDecoder> channelInitializer =
|
||||
new Hj212ChannelInitializer<Hj212FrameDecoder>(factory);
|
||||
|
||||
defaultIoService.init(instanceVo, factory, channelInitializer);
|
||||
|
||||
ioService = defaultIoService;
|
||||
sessionFactory = factory;
|
||||
|
||||
boolean open = ioService.open();
|
||||
|
||||
if(open == true) {
|
||||
state = GatewayState.RUNNING;
|
||||
logger.info("hj212网关:{}启动成功 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
|
||||
shouldRun = new AtomicBoolean(true);
|
||||
|
||||
Integer keepAlive = socketParam.getKeepAlive();
|
||||
|
||||
if(keepAlive == null || keepAlive < 120) {
|
||||
keepAlive = 120;
|
||||
}else if (keepAlive > 3600) {
|
||||
keepAlive = 3600;
|
||||
}
|
||||
|
||||
AliveCheckTask task = new AliveCheckTask(keepAlive, shouldRun, factory);
|
||||
|
||||
Thread thread = new Thread(task, "hj212-alive-check-thread-" + getInstanceVo().getRunId());
|
||||
thread.start();
|
||||
}else {
|
||||
logger.info("hj212网关:{}启动失败 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if(state == GatewayState.CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(sessionFactory != null) {
|
||||
for (IoSession ioSession : sessionFactory.getSessions()) {
|
||||
Hj212IoSession imsIoSession = (Hj212IoSession)ioSession;
|
||||
imsIoSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
boolean close = ioService.close();
|
||||
if(close == true) {
|
||||
sessionFactory = null;
|
||||
state = GatewayState.CLOSED;
|
||||
logger.info("hj212网关:{}关闭成功", instanceVo.getRunId());
|
||||
}else {
|
||||
logger.info("hj212网关:{}关闭失败", instanceVo.getRunId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getActiveDeviceIds(){
|
||||
Set<String> set = Sets.newHashSet();
|
||||
set.add(deviceId);
|
||||
return set;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package com.cisdi.data.HJ212.gateway;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
|
||||
/**
|
||||
* 保活时间检测,如果超过指定时间,则关闭连接
|
||||
* @author cup
|
||||
*
|
||||
*/
|
||||
public class AliveCheckTask implements Runnable {
|
||||
private static final Logger logger = LoggerFactory.getLogger(AliveCheckTask.class);
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
private AtomicBoolean shouldRun = null;
|
||||
|
||||
/**
|
||||
* 会话允许的保活时间,单位秒
|
||||
*/
|
||||
private int keepAlive;
|
||||
|
||||
private static final double multiply = 1.5;
|
||||
|
||||
private static final int sleepInternal = 1000; // 1秒
|
||||
|
||||
public AliveCheckTask(int keepAlive, AtomicBoolean shouldRun, SessionFactory sessionFactory) {
|
||||
super();
|
||||
this.keepAlive = keepAlive;
|
||||
this.shouldRun = shouldRun;
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
logger.info("启动hj212保活超时检测线程");
|
||||
|
||||
while (shouldRun != null && shouldRun.get() == true) {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
List<IoSession> sessions = sessionFactory.getSessions();
|
||||
|
||||
for (IoSession ioSession : sessions) {
|
||||
Hj212IoSession session = (Hj212IoSession)ioSession;
|
||||
|
||||
// 超出指定倍数保活时间,
|
||||
if((now - session.getLastAliveTime()) > (multiply * keepAlive * 1000)) {
|
||||
session.close();
|
||||
logger.warn("{} 超出指定倍数{}保活时间{},单位秒,关闭通道",
|
||||
session.gwPrefix(), multiply, keepAlive);
|
||||
}
|
||||
}
|
||||
|
||||
Thread.sleep(sleepInternal);
|
||||
} catch (Exception e) {
|
||||
logger.warn(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("结束hj212保活超时检测线程");
|
||||
}
|
||||
}
|
48
src/main/java/com/cisdi/data/HJ212/gateway/CRC16Util.java
Normal file
48
src/main/java/com/cisdi/data/HJ212/gateway/CRC16Util.java
Normal file
@ -0,0 +1,48 @@
|
||||
package com.cisdi.data.HJ212.gateway;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class CRC16Util {
|
||||
public static final Charset UTF8 = Charset.forName("UTF-8");
|
||||
|
||||
/**
|
||||
* HJ212污染监测 CRC16校验算法
|
||||
*
|
||||
* @param dataBody
|
||||
* @return CRC16校验码
|
||||
*/
|
||||
public static String CRC16(String dataBody) {
|
||||
Integer[] regs = new Integer[dataBody.length()];
|
||||
for (int i = 0; i < dataBody.length(); i++) {
|
||||
regs[i] = (int)dataBody.charAt(i);
|
||||
}
|
||||
int por = 0xFFFF;
|
||||
for (int j = 0; j < regs.length; j++) {
|
||||
por = por >> 8;
|
||||
por ^= regs[j];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if ((por & 0x01) == 1) {
|
||||
por = por >> 1;
|
||||
por = por ^ 0xa001;
|
||||
} else
|
||||
por = por >> 1;
|
||||
}
|
||||
}
|
||||
String result = Integer.toHexString(por).toUpperCase();
|
||||
|
||||
while (result.length() < 4) {
|
||||
result = "0" + result;
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String body1 =
|
||||
"QN=20160801085857223;ST=32;CN=1062;PW=100000;MN=010000A8900016F000169DC0;Flag=5;CP=&&RtdInterval=30&&";
|
||||
System.out.println(CRC16(body1)); // should be 1C80
|
||||
|
||||
String body2 = "QN=20120416225111069;ST=91;CN=9021;PW=122333;MN=88888880000006;Flag=1;CP=&&&&";
|
||||
System.out.println(CRC16(body2)); // should be 4100
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.cisdi.data.HJ212.gateway;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractChannelInitializer;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoChannelHandler;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultIoChannelHandler;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
|
||||
public class Hj212ChannelInitializer<I> extends AbstractChannelInitializer<I> {
|
||||
private SessionFactory factory;
|
||||
|
||||
/**
|
||||
* 构造通道初始化器对象
|
||||
* @param factory 会话工厂
|
||||
*/
|
||||
public Hj212ChannelInitializer(SessionFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected AbstractIoChannelHandler<I> getTailHandler() {
|
||||
return new DefaultIoChannelHandler(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ChannelHandler> getHandlers() {
|
||||
List<ChannelHandler> handlers = new ArrayList<ChannelHandler>();
|
||||
handlers.add(new Hj212FrameDecoder());
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IdleStateHandler getIdleStateHandler() {
|
||||
return new IdleStateHandler(15, 15, 30);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChannelHandler getSslChannelHandler(Channel socketChannel) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package com.cisdi.data.HJ212.gateway;
|
||||
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title: 永峰HJ212协议解码</p>
|
||||
* <p>Description: 得到一个完整报文长度</p>
|
||||
*
|
||||
* @author lhp
|
||||
* @version 1.0
|
||||
* @date 2021.05.13
|
||||
*/
|
||||
public class Hj212FrameDecoder extends ByteToMessageDecoder {
|
||||
Logger logger = LoggerFactory.getLogger(Hj212FrameDecoder.class);
|
||||
// 包头2+数据段长度4+数据段0+CRC校验4+包尾2
|
||||
private static final short Min_Length = 12;
|
||||
private static final short Max_Length = 8192;
|
||||
private Charset charset = StandardCharsets.UTF_8;
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf bufferIn, List<Object> out) throws Exception {
|
||||
try {
|
||||
if (bufferIn.readableBytes() < Min_Length) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int beginIndex = bufferIn.readerIndex();
|
||||
|
||||
byte[] headerBytes = new byte[6];
|
||||
bufferIn.readBytes(headerBytes);
|
||||
|
||||
String header = new String(headerBytes, charset);
|
||||
|
||||
// 解析headerString
|
||||
String lendthString = getString(header, 2, 6);
|
||||
|
||||
// 数据段长度
|
||||
int length = Integer.valueOf(lendthString);
|
||||
|
||||
// 数据段长度+其他长度才是总的长度
|
||||
length += 12;
|
||||
|
||||
if (length > Max_Length) {
|
||||
ctx.close();
|
||||
throw new BusinessException("超过协议允许最大报文长度,默认为 " + Max_Length + " byte,当前为" + length + "byte");
|
||||
}
|
||||
|
||||
if (length < Min_Length) {
|
||||
ctx.close();
|
||||
throw new BusinessException(ctx.channel().toString() + "传输数据体长度小于12, 此长度为:" + length);
|
||||
}
|
||||
|
||||
if (bufferIn.readableBytes() < length - 6) { // 拆包
|
||||
bufferIn.readerIndex(beginIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
bufferIn.readerIndex(beginIndex);
|
||||
|
||||
ByteBuf otherByteBufRef = bufferIn.retainedSlice(beginIndex, length);
|
||||
|
||||
bufferIn.readerIndex(beginIndex + length);
|
||||
|
||||
out.add(otherByteBufRef);
|
||||
|
||||
// 处理可能的粘包
|
||||
decode(ctx, bufferIn, out);
|
||||
} catch (Exception e) {
|
||||
logger.error("拆包过程出现异常,原始消息为:{}", bufferIn.toString(charset));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String getString(String header, int start, int end) {
|
||||
char[] dst = new char[end - start];
|
||||
header.getChars(start, end, dst, 0);
|
||||
|
||||
return new String(dst);
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package com.cisdi.data.HJ212.gateway;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class Hj212FrameInputVo {
|
||||
/** 请求编码 精确到毫秒的时间戳:QN=YYYYMMDDhhmmsszzz,用来唯一标识一次命令交互 */
|
||||
private String qn;
|
||||
/** 系统编码 */
|
||||
private String st;
|
||||
/** 命令编码,可以作为电文号 */
|
||||
private String cn;
|
||||
/** 访问密码 */
|
||||
private String pw;
|
||||
/** 设备唯一标识MN */
|
||||
private String mn;
|
||||
/** 拆分包及应答标志 */
|
||||
private Integer flag;
|
||||
/** 指令参数CP */
|
||||
private String cp;
|
||||
/** cp 中包含的 DataTime字段 */
|
||||
private Long dataTime;
|
||||
|
||||
/**
|
||||
* 通过命令上传的数据
|
||||
*/
|
||||
private Map<String, String> dataMap;
|
||||
|
||||
public String getQn() {
|
||||
return qn;
|
||||
}
|
||||
public void setQn(String qn) {
|
||||
this.qn = qn;
|
||||
}
|
||||
public String getSt() {
|
||||
return st;
|
||||
}
|
||||
public void setSt(String st) {
|
||||
this.st = st;
|
||||
}
|
||||
public String getCn() {
|
||||
return cn;
|
||||
}
|
||||
public void setCn(String cn) {
|
||||
this.cn = cn;
|
||||
}
|
||||
public String getPw() {
|
||||
return pw;
|
||||
}
|
||||
public void setPw(String pw) {
|
||||
this.pw = pw;
|
||||
}
|
||||
public String getMn() {
|
||||
return mn;
|
||||
}
|
||||
public void setMn(String mn) {
|
||||
this.mn = mn;
|
||||
}
|
||||
public Integer getFlag() {
|
||||
return flag;
|
||||
}
|
||||
public void setFlag(Integer flag) {
|
||||
this.flag = flag;
|
||||
}
|
||||
public String getCp() {
|
||||
return cp;
|
||||
}
|
||||
public void setCp(String cp) {
|
||||
this.cp = cp;
|
||||
}
|
||||
public Long getDataTime() {
|
||||
return dataTime;
|
||||
}
|
||||
public void setDataTime(Long dataTime) {
|
||||
this.dataTime = dataTime;
|
||||
}
|
||||
public Map<String, String> getDataMap() {
|
||||
return dataMap;
|
||||
}
|
||||
public void setDataMap(Map<String, String> dataMap) {
|
||||
this.dataMap = dataMap;
|
||||
}
|
||||
}
|
124
src/main/java/com/cisdi/data/HJ212/gateway/Hj212IoSession.java
Normal file
124
src/main/java/com/cisdi/data/HJ212/gateway/Hj212IoSession.java
Normal file
@ -0,0 +1,124 @@
|
||||
package com.cisdi.data.HJ212.gateway;
|
||||
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.gateway.message.SocketMessage;
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoSession;
|
||||
import com.cisdi.data.sdk.service.SendService;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
/**
|
||||
*
|
||||
* <p>Title: Hj212IoSession.java</p>
|
||||
* @author lhp
|
||||
* @date 2021年05月13日
|
||||
* @version 1.0
|
||||
*/
|
||||
public class Hj212IoSession extends AbstractIoSession implements IoSession {
|
||||
private long lastAliveTime = System.currentTimeMillis();
|
||||
private static Logger logger = LoggerFactory.getLogger(Hj212IoSession.class);
|
||||
private String deviceId = null;
|
||||
|
||||
public Hj212IoSession(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRead(Object message) {
|
||||
int length = ((ByteBuf)message).readableBytes();
|
||||
ByteBuf inBuf = (ByteBuf)message;
|
||||
|
||||
Hj212FrameInputVo vo = Hj212VoDecode.Decode(inBuf);
|
||||
|
||||
if(socketGateway!= null && Boolean.TRUE.equals(socketGateway.getInstanceVo().getLogOpen())) {
|
||||
logger.info("hj212 {} 报文长度:{} vo:{} ", getChannel(), length, JSON.toJSONString(vo));
|
||||
}
|
||||
//发送的真正电文数据
|
||||
Map<String, Object> realDataMap = Maps.newHashMap(vo.getDataMap());
|
||||
realDataMap.put("dataTime", vo.getDataTime());
|
||||
realDataMap.put("mn", vo.getMn());
|
||||
realDataMap.put("qn", vo.getQn());
|
||||
realDataMap.put("cn", vo.getCn());
|
||||
String msgKey = String.format("%s_%s", vo.getMn(), vo.getCn());
|
||||
|
||||
if(vo != null && serviceProvider != null && socketGateway != null) {
|
||||
SendService service = (SendService)serviceProvider.getByName(ServiceName.Send);
|
||||
|
||||
SocketMessage socketMessage = socketGateway.buildSocketMessage();
|
||||
socketMessage.setDeviceId(deviceId);
|
||||
|
||||
socketMessage.setData(JSON.toJSONString(realDataMap).getBytes(CRC16Util.UTF8));
|
||||
socketMessage.setMsgKey(msgKey);
|
||||
|
||||
service.sendMessage(socketMessage);
|
||||
}else {
|
||||
logger.info("hj212收到 msgkey: {} 消息:{}",msgKey, JSON.toJSONString(realDataMap));
|
||||
}
|
||||
|
||||
byte[] backBodys = Hj212VoEncoder.encode(vo.getSt(), vo.getCn(), vo.getPw(), vo.getMn());
|
||||
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(backBodys);
|
||||
|
||||
getChannel().writeAndFlush(wrappedBuffer);
|
||||
lastAliveTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen() {
|
||||
super.onOpen();
|
||||
logger.info("建立连接,channel:{}", getChannel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if(getChannel() != null) {
|
||||
try {
|
||||
getChannel().close().sync();
|
||||
} catch (InterruptedException e) {
|
||||
logger.warn(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String gwPrefixCache = null;
|
||||
|
||||
public String gwPrefix() {
|
||||
if(gwPrefixCache != null) {
|
||||
return gwPrefixCache;
|
||||
}
|
||||
|
||||
gwPrefixCache = "";
|
||||
if(socketGateway != null && socketGateway.getInstanceVo() != null) {
|
||||
gwPrefixCache = "网关Id:" + socketGateway.getInstanceVo().getRunId() + "连接:" + getChannel() + " ";
|
||||
}else {
|
||||
gwPrefixCache = "连接:" + getChannel() + " ";
|
||||
}
|
||||
|
||||
return gwPrefixCache;
|
||||
}
|
||||
|
||||
public long getLastAliveTime() {
|
||||
return lastAliveTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDeviceIds() {
|
||||
String cpDeviceId = deviceId;
|
||||
String[] result = new String[cpDeviceId == null ? 0 : 1];
|
||||
if(cpDeviceId != null) {
|
||||
result[0] = cpDeviceId;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.cisdi.data.HJ212.gateway;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractSessionFactory;
|
||||
|
||||
public class Hj212SessionFactory extends AbstractSessionFactory {
|
||||
private String deviceId;
|
||||
|
||||
public Hj212SessionFactory(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IoSession newSession() {
|
||||
IoSession session = new Hj212IoSession(deviceId);
|
||||
session.init(UUID.randomUUID().toString(), provider, socketGateway);
|
||||
sessionSet.add(session);
|
||||
return session;
|
||||
}
|
||||
}
|
117
src/main/java/com/cisdi/data/HJ212/gateway/Hj212VoDecode.java
Normal file
117
src/main/java/com/cisdi/data/HJ212/gateway/Hj212VoDecode.java
Normal file
@ -0,0 +1,117 @@
|
||||
package com.cisdi.data.HJ212.gateway;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.tomcat.util.buf.HexUtils;
|
||||
import org.apache.tomcat.util.buf.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.common.utils.Strings;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
public class Hj212VoDecode {
|
||||
private static final Logger log = LoggerFactory.getLogger(Hj212VoDecode.class);
|
||||
|
||||
public static Hj212FrameInputVo Decode(ByteBuf in) {
|
||||
byte[] bytes = new byte[in.readableBytes()];
|
||||
in.readBytes(bytes);
|
||||
String message = new String(bytes, CRC16Util.UTF8);
|
||||
|
||||
String body = message.substring(6, message.length() - 6);
|
||||
String end = message.substring(message.length() - 6, message.length());
|
||||
|
||||
String crcParameter = end.substring(0, 4);
|
||||
String crcResult = CRC16Util.CRC16(body);
|
||||
|
||||
if(Strings.equalsIgnoreCase(crcParameter, crcResult) == false){
|
||||
log.error("hj212 crc16 check fail, input:{}, input-crc:{},cal-crc:{}", body, crcParameter, crcResult);
|
||||
throw new BusinessException("crc16 check fail input-crc=" + crcParameter);
|
||||
}
|
||||
// 解析body字段
|
||||
// 字段与其值用‘=’连接;在数据区中,同一项目的不同分类值间用‘,’来分隔,不同项目之间用‘;’来分隔。
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
|
||||
String[] bodyItems = Strings.split(body.substring(0,body.length()-2), ';');
|
||||
for (String item : bodyItems) {
|
||||
if(item.contains(",")) {
|
||||
String[] itemBodys = Strings.split(item, ',');
|
||||
for (String subItem : itemBodys) {
|
||||
if(subItem.contains("=")) {
|
||||
int indexOp = subItem.indexOf('=');
|
||||
map.put(subItem.substring(0, indexOp), subItem.substring(indexOp + 1));
|
||||
}
|
||||
}
|
||||
}else if(item.contains("=")) {
|
||||
int indexOp = item.indexOf('=');
|
||||
map.put(item.substring(0, indexOp), item.substring(indexOp + 1));
|
||||
}
|
||||
}
|
||||
|
||||
Hj212FrameInputVo value = new Hj212FrameInputVo();
|
||||
|
||||
value.setCn(map.get("CN"));
|
||||
value.setQn(map.get("QN"));
|
||||
value.setSt(map.get("ST"));
|
||||
value.setPw(map.get("PW"));
|
||||
value.setMn(map.get("MN"));
|
||||
if(map.containsKey("Flag")){
|
||||
value.setFlag(Integer.valueOf(map.get("Flag")));
|
||||
}
|
||||
value.setCp(map.get("CP").substring(2));
|
||||
|
||||
// &&DataTime=20190425110800
|
||||
int indexDt = value.getCp().indexOf("DataTime");
|
||||
if(indexDt >= 0) {
|
||||
value.setDataTime(Long.valueOf(value.getCp().substring(indexDt + 9, indexDt + 9 + 14)));
|
||||
}
|
||||
|
||||
map.remove("CN");
|
||||
map.remove("QN");
|
||||
map.remove("ST");
|
||||
map.remove("PW");
|
||||
map.remove("MN");
|
||||
map.remove("Flag");
|
||||
map.remove("CP");
|
||||
|
||||
value.setDataMap(map);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 实时数据
|
||||
// String input = "##0365QN=20190425110900000;ST=22;CN=2011;PW=123456;MN=01004190001003;Flag=5;CP=&&DataTime=20190425110800;a01001-Rtd=0.0,a01001-Flag=N;a01002-Rtd=0.0,a01002-Flag=N;a01006-Rtd=101.09,a01006-Flag=N;a01007-Rtd=0.0,a01007-Flag=N;a01008-Rtd=0,a01008-Flag=N;a34001-Rtd=0.0,a34001-Flag=N;a34002-Rtd=17.8,a34002-Flag=N;a34004-Rtd=7.7,a34004-Flag=N;a50001-Rtd=30.0,a50001-Flag=N;&&0880\r\n";
|
||||
// String input="##0102QN=20211207181139971;ST=31;CN=1011;PW=123456;MN=YFLGZXJCLT0003;Flag=1;CP=&&SystemTime=20211207181139&&4980\r\n";
|
||||
// String input="##0453QN=20211207181137957;ST=31;CN=2051;PW=123456;MN=YFLGZXJCLT0003;CP=&&DataTime=20211207180000;01-ZsAvg=1.38,01-ZsMin=1.25,01-ZsMax=1.54,01-Cou=0.18,01-Avg=1.38,01-Min=1.25,01-Max=1.54;B02-Cou=130926.47,B02-Avg=218.21,B02-Min=206.41,B02-Max=230.95;S03-Avg=16.38,S03-Min=16.30,S03-Max=16.44;S05-Avg=2.31,S05-Min=2.31,S05-Max=2.32;S08-Avg=-0.16,S08-Min=-0.17,S08-Max=-0.14;S02-Avg=12.08,S02-Min=11.42,S02-Max=12.79;S01-Avg=21.17,S01-Min=21.16,S01-Max=21.18&&5280\r\n";
|
||||
// String input="##0279QN=20211207181240386;ST=31;CN=2011;PW=123456;MN=YFLGZXJCLT0003;CP=&&DataTime=20211207181148;01-ZsRtd=1.32,01-Rtd=1.32,01-Flag=N;B02-Rtd=225.99,B02-Flag=N;S03-Rtd=16.29,S03-Flag=N;S05-Rtd=2.31,S05-Flag=N;S08-Rtd=-0.16,S08-Flag=N;S02-Rtd=12.51,S02-Flag=N;S01-Rtd=21.16,S01-Flag=N&&7940\r\n";
|
||||
// String input="##0275QN=20211208195054384;ST=31;CN=2011;PW=123456;MN=SD371300004744;CP=&&DataTime=20211208194952;01-ZsRtd=0.52,01-Rtd=0.52,01-Flag=N;B02-Rtd=38.10,B02-Flag=N;S03-Rtd=8.66,S03-Flag=N;S05-Rtd=1.23,S05-Flag=N;S08-Rtd=0.00,S08-Flag=N;S02-Rtd=1.20,S02-Flag=N;S01-Rtd=21.61,S01-Flag=N&&4040\r\n";
|
||||
// String input="##0102QN=20211208194951184;ST=31;CN=1011;PW=123456;MN=SD371300004744;Flag=1;CP=&&SystemTime=20211208194951&&7F80\r\n";
|
||||
// String input="##0275QN=20211208194952060;ST=31;CN=2011;PW=123456;MN=SD371300004744;CP=&&DataTime=20211208194853;01-ZsRtd=0.52,01-Rtd=0.52,01-Flag=N;B02-Rtd=38.09,B02-Flag=N;S03-Rtd=8.65,S03-Flag=N;S05-Rtd=1.26,S05-Flag=N;S08-Rtd=0.00,S08-Flag=N;S02-Rtd=1.20,S02-Flag=N;S01-Rtd=21.61,S01-Flag=N&&5000\r\n";
|
||||
String input="##0441QN=20211208195157432;ST=31;CN=2051;PW=123456;MN=SD371300004744;CP=&&DataTime=20211208194000;01-ZsAvg=0.52,01-ZsMin=0.52,01-ZsMax=0.52,01-Cou=0.01,01-Avg=0.52,01-Min=0.52,01-Max=0.52;B02-Cou=22469.20,B02-Avg=37.45,B02-Min=34.90,B02-Max=38.10;S03-Avg=8.66,S03-Min=8.65,S03-Max=8.68;S05-Avg=1.27,S05-Min=1.23,S05-Max=1.29;S08-Avg=0.00,S08-Min=-0.01,S08-Max=0.00;S02-Avg=1.18,S02-Min=1.10,S02-Max=1.20;S01-Avg=21.61,S01-Min=21.60,S01-Max=21.62&&F9C1\r\n";
|
||||
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(input.getBytes(CRC16Util.UTF8));
|
||||
|
||||
Hj212FrameInputVo decode = Hj212VoDecode.Decode(wrappedBuffer);
|
||||
wrappedBuffer.release();
|
||||
System.out.println(JSON.toJSONString(decode));
|
||||
|
||||
// String inputDay = "##0638QN=20190425104000000;ST=22;CN=2051;PW=123456;MN=0100410001003;Flag=5;CP=&&DataTime=20190425104000;a01001-Min=0.0,a01001-Avg=0.0,a01001-Max=0.0,a01001-Flag=N;a01002-Min=0.0,a01002-Avg=0.0,a01002-Max=0.0,a01002-Flag=N;a01006-Min=0.00,a01006-Avg=101.08,a01006-Max=101.08,a01006-Flag=N;a01007-Min=0.0,a01007-Avg=0.0,a01007-Max=0.0,a01007-Flag=N;a01008-Min=0,a01008-Avg=0,a01008-Max=0,a01008-Flag=N;a34001-Min=0.0,a34001-Avg=0.0,a34001-Max=0.0,a34001-Flag=N;a34002-Min=0.0,a34002-Avg=21.6,a34002-Max=35.2,a34002-Flag=N;a34004-Min=0.0,a34004-Avg=10.8,a34004-Max=22.7,a34004-Flag=N;a50001-Min=0.0,a50001-Avg=30.0,a50001-Max=30.0,a50001-Flag=N;&&5B40\r\n";
|
||||
// wrappedBuffer = Unpooled.wrappedBuffer(inputDay.getBytes(CRC16Util.UTF8));
|
||||
// decode = Hj212VoDecode.Decode(wrappedBuffer);
|
||||
// wrappedBuffer.release();
|
||||
// System.out.println(JSON.toJSONString(decode));
|
||||
|
||||
|
||||
// // 实时数据
|
||||
// String inputTest = "##0365QN=20190425110900000;ST=22;CN=2011;PW=123456;MN=01004190001003;Flag=5;CP=&&DataTime=20190425110800;a01001-Rtd=0.0,a01001-Flag=N;a01002-Rtd=0.0,a01002-Flag=N;a01006-Rtd=101.09,a01006-Flag=N;a01007-Rtd=0.0,a01007-Flag=N;a01008-Rtd=0,a01008-Flag=N;a34001-Rtd=0.0,a34001-Flag=N;a34002-Rtd=17.8,a34002-Flag=N;a34004-Rtd=7.7,a34004-Flag=N;a50001-Rtd=30.0,a50001-Flag=N;&&0880\r\n";
|
||||
// byte[] inputTestBytes = inputTest.getBytes(CRC16Util.UTF8);
|
||||
// String hexString = HexUtils.toHexString(inputTestBytes);
|
||||
// System.out.print(hexString);
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.cisdi.data.HJ212.gateway;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class Hj212VoEncoder {
|
||||
private static DateFormat qnFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
|
||||
|
||||
public static byte[] encode(String st, String cn, String pw, String mn) {
|
||||
String flag = "4";
|
||||
|
||||
String asciiString = combineAsciiString(null, st, cn, pw, mn, flag);
|
||||
|
||||
return asciiString.getBytes(StandardCharsets.US_ASCII);
|
||||
}
|
||||
|
||||
private static String combineAsciiString(String qn, String st, String cn, String pw, String mn, String flag) {
|
||||
Date date = new Date();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(String.format("QN=%s;", qn == null ? qnFormat.format(date) : qn));
|
||||
builder.append(String.format("ST=%s;", st));
|
||||
builder.append(String.format("CN=%s;", cn));
|
||||
builder.append(String.format("PW=%s;", pw));
|
||||
builder.append(String.format("MN=%s;", mn));
|
||||
builder.append(String.format("Flag=%s;", flag));
|
||||
builder.append("CP=&&&&");
|
||||
|
||||
String dataBody = builder.toString();
|
||||
int dataLength = builder.toString().length();
|
||||
|
||||
builder.insert(0, String.format("##%04d", dataLength));
|
||||
String crc16 = CRC16Util.CRC16(dataBody);
|
||||
builder.append(crc16 + "\r\n");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String combine1 = combineAsciiString("20190425110917290", "22", "9014", "123456", "01004190001003", "4");
|
||||
System.out.println(combine1);
|
||||
|
||||
String combine2 = combineAsciiString("20190425110913469", "22", "9014", "123456", "0100410001003", "4");
|
||||
System.out.println(combine2);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.cisdi.data.HJ212.gateway;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.cisdi.data.HJ212.YfHj212SocketGateway;
|
||||
import com.cisdi.data.sdk.enums.ByteOrder;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
|
||||
import com.cisdi.data.sdk.vo.GatewayVo;
|
||||
|
||||
public class StartHj212Test {
|
||||
private static Logger logger = LoggerFactory.getLogger(YfHj212SocketGateway.class);
|
||||
|
||||
private static TcpIoService ioService = null;
|
||||
@SuppressWarnings("unused")
|
||||
private static SessionFactory sessionFactory = null;
|
||||
|
||||
public static void main(String[] args) {
|
||||
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
|
||||
SessionFactory factory = new Hj212SessionFactory("10000022");
|
||||
|
||||
factory.init(null, null);
|
||||
|
||||
Hj212ChannelInitializer<Hj212FrameInputVo> channelInitializer =
|
||||
new Hj212ChannelInitializer<Hj212FrameInputVo>(factory);
|
||||
|
||||
GatewayVo instanceVo = new GatewayVo();
|
||||
instanceVo.setByteOrder(ByteOrder.BIGENDIAN);
|
||||
instanceVo.setParameter("{\"listenIp\":\"0.0.0.0\",\"listenPort\":9010,\"threadSize\":50,\"timeout\":2000}");
|
||||
|
||||
defaultIoService.init(instanceVo, factory, channelInitializer);
|
||||
|
||||
ioService = defaultIoService;
|
||||
sessionFactory = factory;
|
||||
|
||||
boolean open = ioService.open();
|
||||
|
||||
if(open == true) {
|
||||
|
||||
AtomicBoolean shouldRun = new AtomicBoolean(true);
|
||||
AliveCheckTask task = new AliveCheckTask(120, shouldRun, factory);
|
||||
|
||||
Thread thread = new Thread(task, "Hj212-alive-check-thread");
|
||||
thread.start();
|
||||
|
||||
logger.info("Hj212网关启动成功");
|
||||
}else {
|
||||
logger.info("Hj212网关启动失败");
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(10000000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package com.cisdi.data.IDCardReader;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.IDCardReader.gateway.impl.ZKIDROnlineClient;
|
||||
import com.cisdi.data.IDCardReader.gateway.impl.ZKIDROnlineListener;
|
||||
import com.cisdi.data.IDCardReader.gateway.vo.ZKIDROnlineConfigVo;
|
||||
import com.cisdi.data.IDCardReader.gateway.vo.ZKIDROnlineResponseVo;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.emserver.EmiaProSocketGateway;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.enums.GatewayState;
|
||||
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
|
||||
import com.cisdi.data.sdk.param.ListenSocketParam;
|
||||
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
|
||||
import com.cisdi.data.sdk.service.RouteService;
|
||||
import com.cisdi.data.sdk.vo.DeviceVo;
|
||||
import com.cisdi.data.sdk.vo.ExeResultVo;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class IDCardReaderGateway extends SocketGatewayBase {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(IDCardReaderGateway.class);
|
||||
private ZKIDROnlineClient zkidrOnlineClient=null;
|
||||
private String deviceId;
|
||||
|
||||
@Override
|
||||
public ExeResultVo sendReturnMessage(SocketReturnMessage returnMsg) {
|
||||
ExeResultVo resultVo = new ExeResultVo();
|
||||
resultVo.setMessage("该协议不允许下发数据");
|
||||
resultVo.setSuccess(false);
|
||||
logger.info("网关:{}->设备,消息:{},结果:{}",instanceVo.getRunId(), returnMsg, resultVo);
|
||||
return resultVo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (state == GatewayState.RUNNING) {
|
||||
return;
|
||||
}
|
||||
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
|
||||
|
||||
String otherParameter = socketParam.getOtherParameter();
|
||||
ZKIDROnlineConfigVo zkidrOnlineConfigVo = null;
|
||||
// 处理分组
|
||||
if (StringUtils.isNotBlank(otherParameter)) {
|
||||
zkidrOnlineConfigVo = JSON.parseObject(otherParameter, ZKIDROnlineConfigVo.class);
|
||||
}
|
||||
if (zkidrOnlineConfigVo == null) {
|
||||
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为ZKIDROnline网关,请配置正确的ZKIDROnline配置");
|
||||
}
|
||||
|
||||
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
|
||||
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
|
||||
|
||||
if (deviceVos.size() > 1) {
|
||||
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为ZKIDROnline网关,只允许关联一个设备Id");
|
||||
}
|
||||
|
||||
deviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
|
||||
|
||||
if (StringUtils.isEmpty(deviceId)) {
|
||||
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
|
||||
}
|
||||
logger.info("ZKIDROnline网关:{}读取启动配置参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
|
||||
zkidrOnlineClient=new ZKIDROnlineClient(deviceId,serviceProvider,this,zkidrOnlineConfigVo);
|
||||
Thread thread=new Thread(zkidrOnlineClient);
|
||||
thread.start();
|
||||
state = GatewayState.RUNNING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (state == GatewayState.CLOSED) {
|
||||
return;
|
||||
}
|
||||
if(zkidrOnlineClient.close())
|
||||
{
|
||||
state=GatewayState.CLOSED;
|
||||
logger.info("网关:" + instanceVo.getRunId() + "关闭成功", instanceVo.getRunId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getActiveDeviceIds() {
|
||||
Set<String> set = Sets.newConcurrentHashSet();
|
||||
|
||||
if (StringUtils.isNotEmpty(deviceId)) {
|
||||
set.add(deviceId);
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,80 @@
|
||||
package com.cisdi.data.IDCardReader.gateway.impl;
|
||||
|
||||
import com.cisdi.data.IDCardReader.gateway.vo.ZKIDROnlineConfigVo;
|
||||
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
|
||||
import com.cisdi.data.sdk.service.ServiceProvider;
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
import org.java_websocket.drafts.Draft;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class ZKIDROnlineClient implements Runnable{
|
||||
|
||||
private String deviceId;
|
||||
ServiceProvider serviceProvider;
|
||||
SocketGatewayBase socketGateway;
|
||||
private ZKIDROnlineConfigVo zkidrOnlineConfigVo;
|
||||
private ZKIDROnlineListener zkidrOnlineListener=null;
|
||||
private Logger logger= LoggerFactory.getLogger(ZKIDROnlineClient.class);
|
||||
private AtomicBoolean shouldRun=new AtomicBoolean(true);
|
||||
|
||||
private Boolean isOpen=false;
|
||||
|
||||
public Boolean getOpen() {
|
||||
return isOpen;
|
||||
}
|
||||
|
||||
public Boolean close()
|
||||
{
|
||||
zkidrOnlineListener.setShouldRun(false);
|
||||
shouldRun.set(false);
|
||||
return zkidrOnlineListener.endListen();
|
||||
}
|
||||
|
||||
public ZKIDROnlineClient(String deviceId, ServiceProvider serviceProvider, SocketGatewayBase socketGateway, ZKIDROnlineConfigVo zkidrOnlineConfigVo) {
|
||||
this.deviceId = deviceId;
|
||||
this.serviceProvider = serviceProvider;
|
||||
this.socketGateway = socketGateway;
|
||||
this.zkidrOnlineConfigVo = zkidrOnlineConfigVo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (shouldRun.get())
|
||||
{
|
||||
try {
|
||||
zkidrOnlineListener=new ZKIDROnlineListener(new URI(zkidrOnlineConfigVo.getUri()),deviceId,socketGateway,serviceProvider,zkidrOnlineConfigVo);
|
||||
logger.info("ZKIDROnline网关:{}启动成功 参数:{}", socketGateway.getInstanceVo().getRunId(), socketGateway.getInstanceVo().getParameter());
|
||||
break;
|
||||
} catch (URISyntaxException e) {
|
||||
logger.error("连接ID:"+socketGateway.getInstanceVo().getRunId()+",设备ID:"+deviceId+",自动重连设置:"+zkidrOnlineConfigVo.getAutoReconnect()+"启动失败,错误原因:"+e.getMessage());
|
||||
try {
|
||||
Thread.sleep(zkidrOnlineConfigVo.getReconnectDelay());
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
if(zkidrOnlineConfigVo.getAutoReconnect())
|
||||
{
|
||||
logger.info("连接ID:"+socketGateway.getInstanceVo().getRunId()+",设备ID:"+deviceId+",自动重连设置:"+zkidrOnlineConfigVo.getAutoReconnect()+"启动失败,正在重连");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.info("ZKIDROnline网关:{}启动失败 参数:{}", socketGateway.getInstanceVo().getRunId(), socketGateway.getInstanceVo().getParameter());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(zkidrOnlineListener!=null) {
|
||||
zkidrOnlineListener.start(false);
|
||||
isOpen=true;
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
package com.cisdi.data.IDCardReader.gateway.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.cisdi.data.IDCardReader.gateway.vo.IDCardVo;
|
||||
import com.cisdi.data.IDCardReader.gateway.vo.ZKIDROnlineConfigVo;
|
||||
import com.cisdi.data.IDCardReader.gateway.vo.ZKIDROnlineResponseVo;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.gateway.Gateway;
|
||||
import com.cisdi.data.sdk.gateway.base.GatewayBase;
|
||||
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
|
||||
import com.cisdi.data.sdk.gateway.message.SocketMessage;
|
||||
import com.cisdi.data.sdk.service.SendService;
|
||||
import com.cisdi.data.sdk.service.ServiceProvider;
|
||||
import org.java_websocket.WebSocket;
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class ZKIDROnlineListener extends WebSocketClient {
|
||||
|
||||
private Integer reconnectCount=0;
|
||||
|
||||
private String runId;
|
||||
private String deviceId;
|
||||
private Boolean autoReconnect=false;
|
||||
private Long reconnectDelay =1000L;
|
||||
private ServiceProvider serviceProvider=null;
|
||||
private SocketGatewayBase socketGatewayBase=null;
|
||||
private Logger logger= LoggerFactory.getLogger(ZKIDROnlineListener.class);
|
||||
private ZKIDROnlineConfigVo zkidrOnlineConfigVo=null;
|
||||
private Boolean startFlag=false;
|
||||
private static final String SUCCESS_STR="BeginReadCard Succsefull";
|
||||
private AtomicBoolean shouldRun=new AtomicBoolean(true);
|
||||
|
||||
public void setShouldRun(boolean b)
|
||||
{
|
||||
shouldRun.set(b);
|
||||
}
|
||||
|
||||
public ZKIDROnlineListener(URI serverUri,
|
||||
String deviceId,
|
||||
SocketGatewayBase socketGateway,
|
||||
ServiceProvider serviceProvider,
|
||||
ZKIDROnlineConfigVo zkidrOnlineConfigVo) {
|
||||
super(serverUri);
|
||||
if(socketGateway!=null)
|
||||
{
|
||||
this.runId=socketGateway.getInstanceVo().getRunId();
|
||||
}
|
||||
if(zkidrOnlineConfigVo!=null)
|
||||
{
|
||||
this.autoReconnect=zkidrOnlineConfigVo.getAutoReconnect();
|
||||
this.reconnectDelay =zkidrOnlineConfigVo.getReconnectDelay();
|
||||
}
|
||||
this.deviceId=deviceId;
|
||||
this.socketGatewayBase=socketGateway;
|
||||
this.serviceProvider=serviceProvider;
|
||||
this.zkidrOnlineConfigVo=zkidrOnlineConfigVo;
|
||||
}
|
||||
|
||||
public Boolean endListen()
|
||||
{
|
||||
startFlag=false;
|
||||
autoReconnect=false;
|
||||
this.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean start(boolean reconnect)
|
||||
{
|
||||
startFlag=false;
|
||||
while (shouldRun.get())
|
||||
{
|
||||
try
|
||||
{
|
||||
if(this.getReadyState().equals(READYSTATE.NOT_YET_CONNECTED))
|
||||
{
|
||||
logger.info("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"状态为:"+this.getReadyState()+"准备尝试连接");
|
||||
if(!this.connectBlocking())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
logger.info("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"正在发送启动消息:"+zkidrOnlineConfigVo.getStartMsg());
|
||||
this.send(zkidrOnlineConfigVo.getStartMsg());
|
||||
return true;
|
||||
}
|
||||
else if(this.getReadyState().equals(READYSTATE.CLOSED)||this.getReadyState().equals(READYSTATE.CLOSING))
|
||||
{
|
||||
logger.info("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"状态为:"+this.getReadyState()+"准备尝试重连");
|
||||
if(!this.reconnectBlocking())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
logger.info("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"正在发送启动消息:"+zkidrOnlineConfigVo.getStartMsg());
|
||||
this.send(zkidrOnlineConfigVo.getStartMsg());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.error("连接ID:"+socketGatewayBase.getInstanceVo().getRunId()+",设备ID:"+deviceId+",自动重连设置:"+zkidrOnlineConfigVo.getAutoReconnect()+"启动失败,错误原因:"+e.getLocalizedMessage());
|
||||
try {
|
||||
Thread.sleep(zkidrOnlineConfigVo.getReconnectDelay());
|
||||
} catch (InterruptedException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
if(reconnect)
|
||||
{
|
||||
logger.info("连接ID:"+socketGatewayBase.getInstanceVo().getRunId()+",设备ID:"+deviceId+",自动重连设置:"+zkidrOnlineConfigVo.getAutoReconnect()+"启动失败,正在重连");
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(ServerHandshake handshakedata) {
|
||||
logger.info("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"已经打开连接");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String message) {
|
||||
if(startFlag)
|
||||
{
|
||||
IDCardVo idCardVo=null;
|
||||
try
|
||||
{
|
||||
idCardVo= JSON.parseObject(message,IDCardVo.class);
|
||||
idCardVo.getCertificate().setReadID(deviceId);
|
||||
idCardVo.getCertificate().setReadTime(System.currentTimeMillis()+"");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.error("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"解析数据发生异常:"+e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
if(idCardVo!=null&&serviceProvider!=null&&socketGatewayBase!=null)
|
||||
{
|
||||
SendService service = (SendService)serviceProvider.getByName(ServiceName.Send);
|
||||
SocketMessage socketMessage = socketGatewayBase.buildSocketMessage();
|
||||
socketMessage.setDeviceId(this.deviceId);
|
||||
socketMessage.setMsgKey("default");
|
||||
socketMessage.setData(JSON.toJSONString(idCardVo.getCertificate()).getBytes());
|
||||
socketMessage.getPropsMap().put("charset", Charset.forName("GBK"));
|
||||
service.sendMessage(socketMessage);
|
||||
if(socketGatewayBase.getInstanceVo().getLogOpen())
|
||||
{
|
||||
logger.error("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"收到数据:"+idCardVo.getCertificate());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ZKIDROnlineResponseVo zkidrOnlineResponseVo=null;
|
||||
try
|
||||
{
|
||||
zkidrOnlineResponseVo= JSON.parseObject(message,ZKIDROnlineResponseVo.class);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.error("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"收到无法解析的数据:"+message);
|
||||
}
|
||||
if(zkidrOnlineResponseVo!=null&&SUCCESS_STR.equals(zkidrOnlineResponseVo.getData()))
|
||||
{
|
||||
logger.info("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"请求自动获取身份证信息成功");
|
||||
startFlag=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//this.close();
|
||||
this.start(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int code, String reason, boolean remote) {
|
||||
if(startFlag&&remote)
|
||||
{
|
||||
logger.info("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"正在尝试重连");
|
||||
//this.close();
|
||||
this.start(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.info("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"正在关闭连接");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception ex) {
|
||||
logger.error("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"发生异常:"+ex.getLocalizedMessage());
|
||||
if(autoReconnect)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(reconnectDelay);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
logger.info("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"正在尝试重连");
|
||||
//this.close();
|
||||
this.start(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.warn("连接ID:"+runId+",设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"未配置重连,连接关闭");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package com.cisdi.data.IDCardReader.gateway.vo;
|
||||
|
||||
public class IDCardVo {
|
||||
public class IDCardDataVo{
|
||||
private String IDNumber;
|
||||
private String Name;
|
||||
private String ReadID;
|
||||
private String ReadTime;
|
||||
|
||||
public String getIDNumber() {
|
||||
return IDNumber;
|
||||
}
|
||||
|
||||
public void setIDNumber(String IDNumber) {
|
||||
this.IDNumber = IDNumber;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return Name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public String getReadID() {
|
||||
return ReadID;
|
||||
}
|
||||
|
||||
public void setReadID(String readID) {
|
||||
ReadID = readID;
|
||||
}
|
||||
|
||||
public String getReadTime() {
|
||||
return ReadTime;
|
||||
}
|
||||
|
||||
public void setReadTime(String readTime) {
|
||||
ReadTime = readTime;
|
||||
}
|
||||
}
|
||||
private Integer ret;
|
||||
private IDCardDataVo Certificate;
|
||||
|
||||
public Integer getRet() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void setRet(Integer ret) {
|
||||
this.ret = ret;
|
||||
}
|
||||
|
||||
public IDCardDataVo getCertificate() {
|
||||
return Certificate;
|
||||
}
|
||||
|
||||
public void setCertificate(IDCardDataVo certificate) {
|
||||
Certificate = certificate;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.cisdi.data.IDCardReader.gateway.vo;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
public class ZKIDROnlineConfigVo {
|
||||
private String uri;
|
||||
private Boolean autoReconnect;
|
||||
private String startMsg;
|
||||
private Long reconnectDelay;
|
||||
|
||||
public String getStartMsg() {
|
||||
return startMsg;
|
||||
}
|
||||
|
||||
public void setStartMsg(String startMsg) {
|
||||
this.startMsg = startMsg;
|
||||
}
|
||||
|
||||
public Long getReconnectDelay() {
|
||||
return reconnectDelay;
|
||||
}
|
||||
|
||||
public void setReconnectDelay(Long reconnectDelay) {
|
||||
this.reconnectDelay = reconnectDelay;
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public void setUri(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public Boolean getAutoReconnect() {
|
||||
return autoReconnect;
|
||||
}
|
||||
|
||||
public void setAutoReconnect(Boolean autoReconnect) {
|
||||
this.autoReconnect = autoReconnect;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.cisdi.data.IDCardReader.gateway.vo;
|
||||
|
||||
public class ZKIDROnlineResponseVo {
|
||||
private String data;
|
||||
private String dev;
|
||||
private String ret;
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public String getDev() {
|
||||
return dev;
|
||||
}
|
||||
|
||||
public void setDev(String dev) {
|
||||
this.dev = dev;
|
||||
}
|
||||
|
||||
public String getRet() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void setRet(String ret) {
|
||||
this.ret = ret;
|
||||
}
|
||||
}
|
145
src/main/java/com/cisdi/data/OBLF/OBLFSocketGateway.java
Normal file
145
src/main/java/com/cisdi/data/OBLF/OBLFSocketGateway.java
Normal file
@ -0,0 +1,145 @@
|
||||
package com.cisdi.data.OBLF;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.OBLF.impl.OBLFChannelInitializer;
|
||||
import com.cisdi.data.OBLF.impl.OBLFIoSession;
|
||||
import com.cisdi.data.OBLF.impl.OBLFSessionFactory;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.enums.GatewayState;
|
||||
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
|
||||
import com.cisdi.data.sdk.param.ListenSocketParam;
|
||||
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
|
||||
import com.cisdi.data.sdk.service.PlatformService;
|
||||
import com.cisdi.data.sdk.service.RouteService;
|
||||
import com.cisdi.data.sdk.vo.DeviceVo;
|
||||
import com.cisdi.data.sdk.vo.ExeResultVo;
|
||||
import com.cisdi.data.sdk.vo.SslConfigVo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author cuianbing
|
||||
* @version 1.0
|
||||
* @description: 炼钢OBLF750设备
|
||||
* @date 2021/7/21 11:33
|
||||
*/
|
||||
@Slf4j
|
||||
public class OBLFSocketGateway extends SocketGatewayBase {
|
||||
|
||||
|
||||
TcpIoService ioService = null;
|
||||
SessionFactory sessionFactory = null;
|
||||
|
||||
// 当配置为单个设备模式时,此为该设备id
|
||||
String onlyOneDeviceId = null;
|
||||
|
||||
@Override
|
||||
public ExeResultVo sendReturnMessage(SocketReturnMessage socketReturnMessage) {
|
||||
throw new BusinessException("OBLF750不支持下发服务!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (state == GatewayState.RUNNING) {
|
||||
return;
|
||||
}
|
||||
log.info("网关:{}读取启动配置参数:{},是否支持支持多个设备:{}", instanceVo.getRunId(), instanceVo.getParameter(),
|
||||
instanceVo.getSuportMultiDevice());
|
||||
|
||||
|
||||
// 不支持多个设备,必须强制配置一个设备id
|
||||
if (instanceVo.getSuportMultiDevice() != null && instanceVo.getSuportMultiDevice() == false) {
|
||||
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
|
||||
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
|
||||
|
||||
if (deviceVos.size() > 1) {
|
||||
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为OBLF750网关,当前配置为只支持单个设备,但配置了多个设备。");
|
||||
}
|
||||
|
||||
onlyOneDeviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
|
||||
|
||||
if (StringUtils.isEmpty(onlyOneDeviceId)) {
|
||||
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
|
||||
SessionFactory factory = new OBLFSessionFactory(onlyOneDeviceId);
|
||||
factory.init(serviceProvider, this);
|
||||
|
||||
SslConfigVo sslConfigVo = null;
|
||||
|
||||
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
|
||||
|
||||
if (socketParam != null && Boolean.TRUE.equals(socketParam.getEnableSsl())) {
|
||||
|
||||
PlatformService platformService = (PlatformService) serviceProvider.getByName(ServiceName.Platform);
|
||||
|
||||
sslConfigVo = platformService.getSslConfig();
|
||||
}
|
||||
|
||||
|
||||
OBLFChannelInitializer channelInitializer =
|
||||
new OBLFChannelInitializer(factory, getInstanceVo().getByteOrder(), sslConfigVo);
|
||||
|
||||
defaultIoService.init(instanceVo, factory, channelInitializer);
|
||||
|
||||
ioService = defaultIoService;
|
||||
sessionFactory = factory;
|
||||
|
||||
boolean open = ioService.open();
|
||||
|
||||
if (open == true) {
|
||||
state = GatewayState.RUNNING;
|
||||
log.info("OBLF750网关:{}启动成功 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
|
||||
} else {
|
||||
log.info("OBLF750网关:{}启动失败 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (state == GatewayState.CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sessionFactory != null) {
|
||||
for (IoSession ioSession : sessionFactory.getSessions()) {
|
||||
OBLFIoSession XrfIoSession = (OBLFIoSession) ioSession;
|
||||
XrfIoSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
boolean close = ioService.close();
|
||||
if (close == true) {
|
||||
sessionFactory = null;
|
||||
state = GatewayState.CLOSED;
|
||||
log.info("OBLF750网关:{}关闭成功", instanceVo.getRunId());
|
||||
} else {
|
||||
log.info("OBLF750网关:{}关闭失败", instanceVo.getRunId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getActiveDeviceIds() {
|
||||
if (onlyOneDeviceId != null) {
|
||||
Set<String> set = new HashSet<String>();
|
||||
set.add(onlyOneDeviceId);
|
||||
return set;
|
||||
} else {
|
||||
return sessionFactory.getActiveDeviceIds();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package com.cisdi.data.OBLF.impl;
|
||||
|
||||
import com.cisdi.data.sdk.enums.ByteOrder;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractChannelInitializer;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoChannelHandler;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultIoChannelHandler;
|
||||
import com.cisdi.data.sdk.utils.NettySslUtils;
|
||||
import com.cisdi.data.sdk.vo.SslConfigVo;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author cuianbing
|
||||
* @version 1.0
|
||||
* @description: TODO
|
||||
* @date 2021/7/20 21:27
|
||||
*/
|
||||
@Slf4j
|
||||
public class OBLFChannelInitializer<I> extends AbstractChannelInitializer<I> {
|
||||
private SessionFactory factory;
|
||||
private ByteOrder byteOrder;
|
||||
private SslConfigVo sslConfigVo;
|
||||
|
||||
|
||||
/**
|
||||
* 构造通道初始化器对象
|
||||
*
|
||||
* @param factory 会话工厂
|
||||
* @param byteOrder 大小端
|
||||
* @param sslConfig ssl证书配置,如果不启用tls,传null
|
||||
*/
|
||||
public OBLFChannelInitializer(SessionFactory factory,
|
||||
ByteOrder byteOrder,
|
||||
SslConfigVo sslConfig) {
|
||||
this.factory = factory;
|
||||
this.byteOrder = byteOrder;
|
||||
this.sslConfigVo = sslConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractIoChannelHandler<I> getTailHandler() {
|
||||
return new DefaultIoChannelHandler(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ChannelHandler> getHandlers() {
|
||||
List<ChannelHandler> handlers = new ArrayList<ChannelHandler>();
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IdleStateHandler getIdleStateHandler() {
|
||||
return new IdleStateHandler(15, 15, 30);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChannelHandler getSslChannelHandler(Channel socketChannel) {
|
||||
ChannelHandler sslHandler = null;
|
||||
try {
|
||||
if (sslConfigVo != null) {
|
||||
sslHandler = NettySslUtils.getServerSslHandler((SocketChannel) socketChannel, sslConfigVo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn(e.getLocalizedMessage(), e);
|
||||
}
|
||||
return sslHandler;
|
||||
}
|
||||
}
|
169
src/main/java/com/cisdi/data/OBLF/impl/OBLFIoSession.java
Normal file
169
src/main/java/com/cisdi/data/OBLF/impl/OBLFIoSession.java
Normal file
@ -0,0 +1,169 @@
|
||||
package com.cisdi.data.OBLF.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.gateway.message.SocketMessage;
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoSession;
|
||||
import com.cisdi.data.sdk.service.PassthroughService;
|
||||
import com.cisdi.data.sdk.service.SendService;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @author cuianbing
|
||||
* @version 1.0
|
||||
* @description: TODO
|
||||
* @date 2021/7/20 21:28
|
||||
*/
|
||||
@Slf4j
|
||||
public class OBLFIoSession extends AbstractIoSession implements IoSession {
|
||||
|
||||
private OBLFSessionFactory factory = null;
|
||||
|
||||
private String deviceId = null;
|
||||
/**
|
||||
* 如果有值,代表所有会话都使用这一个设备id,且允许多会话共享此一个设备id,不除旧会话
|
||||
*/
|
||||
private final String onlyOneDeviceId;
|
||||
|
||||
private String gwPrefixCache = null;
|
||||
|
||||
private ByteBuf allBuf = ByteBufAllocator.DEFAULT.buffer();
|
||||
|
||||
|
||||
public OBLFIoSession(OBLFSessionFactory factory, String onlyOneDeviceId) {
|
||||
super();
|
||||
this.factory = factory;
|
||||
this.onlyOneDeviceId = onlyOneDeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDeviceIds() {
|
||||
String cpDeviceId = deviceId;
|
||||
String[] result = new String[cpDeviceId == null ? 0 : 1];
|
||||
if (cpDeviceId != null) {
|
||||
result[0] = cpDeviceId;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRead(Object message) {
|
||||
try {
|
||||
|
||||
ByteBuf inBuf = (ByteBuf) message;
|
||||
if (inBuf != null) {
|
||||
allBuf.writeBytes(inBuf);
|
||||
} else {
|
||||
log.info("电文格式为空");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("电文格式错误!");
|
||||
throw new BusinessException("电文格式错误!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen() {
|
||||
super.onOpen();
|
||||
log.info("建立连接,channel:{}", getChannel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
log.info("onClose");
|
||||
Map<String, String> message = decode(allBuf);
|
||||
|
||||
if (serviceProvider != null && socketGateway != null) {
|
||||
SendService service = (SendService) serviceProvider.getByName(ServiceName.Send);
|
||||
SocketMessage socketMessage = socketGateway.buildSocketMessage();
|
||||
socketMessage.setDeviceId(onlyOneDeviceId);
|
||||
socketMessage.setData(JSON.toJSONString(message).getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
String analysisProgram = message.get("AnalysisProgram_");
|
||||
|
||||
if ("FE 4".equals(analysisProgram)) {
|
||||
socketMessage.setMsgKey("iron");
|
||||
} else {
|
||||
socketMessage.setMsgKey("steel");
|
||||
}
|
||||
|
||||
service.sendMessage(socketMessage);
|
||||
if (socketGateway.getInstanceVo().getLogOpen()) {
|
||||
log.info("类似为:{}:发送消息内容{}", message, message.toString());
|
||||
}
|
||||
|
||||
}
|
||||
super.onClose();
|
||||
factory = null;
|
||||
}
|
||||
|
||||
|
||||
public void close() {
|
||||
if (getChannel() != null) {
|
||||
try {
|
||||
getChannel().close().sync();
|
||||
} catch (InterruptedException e) {
|
||||
log.warn(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t) {
|
||||
// 这里会出现 java.io.IOException: 远程主机强迫关闭了一个现有的连接。
|
||||
log.info("远程主机强迫关闭了一个现有的连接。");
|
||||
// log.error("session exception:{}", t);
|
||||
}
|
||||
|
||||
|
||||
public Map<String, String> decode(ByteBuf byteBuf) {
|
||||
|
||||
List<Map<String, String>> dataList = new ArrayList<>();
|
||||
AtomicInteger dataFlag = new AtomicInteger();
|
||||
|
||||
String msg = byteBuf.toString(StandardCharsets.UTF_8);
|
||||
Map<String, String> data = JSON.parseObject(msg, Map.class);
|
||||
log.debug("收到数据{}", data);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
private void passThrough(ByteBuf passthroughBuf) {
|
||||
try {
|
||||
if (serviceProvider != null && socketGateway != null) {
|
||||
PassthroughService service = (PassthroughService) serviceProvider.getByName(ServiceName.Passthrough);
|
||||
service.transfer(passthroughBuf, socketGateway.getInstanceVo().getPassthroughAddress());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("协议透传失败:" + e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public String gwPrefix() {
|
||||
if (gwPrefixCache != null) {
|
||||
return gwPrefixCache;
|
||||
}
|
||||
|
||||
gwPrefixCache = "";
|
||||
if (socketGateway != null && socketGateway.getInstanceVo() != null) {
|
||||
gwPrefixCache = "网关Id:" + socketGateway.getInstanceVo().getRunId() + "连接:" + getChannel() + " ";
|
||||
} else {
|
||||
gwPrefixCache = "连接:" + getChannel() + " ";
|
||||
}
|
||||
|
||||
return gwPrefixCache;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.cisdi.data.OBLF.impl;
|
||||
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractSessionFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author cuianbing
|
||||
* @version 1.0
|
||||
* @description: TODO
|
||||
* @date 2021/7/20 21:29
|
||||
*/
|
||||
@Slf4j
|
||||
public class OBLFSessionFactory extends AbstractSessionFactory {
|
||||
|
||||
private String onlyOneDeviceId;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @param: onlyOneDeviceId 设备唯一ID
|
||||
* @return: void
|
||||
* @author cuianbing
|
||||
* @date: 2021/7/7 22:10
|
||||
*/
|
||||
public OBLFSessionFactory(String onlyOneDeviceId) {
|
||||
this.onlyOneDeviceId = onlyOneDeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IoSession newSession() {
|
||||
IoSession session = new OBLFIoSession(this, onlyOneDeviceId);
|
||||
session.init(UUID.randomUUID().toString(), provider, socketGateway);
|
||||
sessionSet.add(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.cisdi.data.OBLF.test;
|
||||
|
||||
import com.cisdi.data.sdk.service.Service;
|
||||
import com.cisdi.data.sdk.service.ServiceProvider;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author cuianbing
|
||||
* @version 1.0
|
||||
* @description: TODO
|
||||
* @date 2021/7/7 19:17
|
||||
*/
|
||||
@Slf4j
|
||||
public class ServiceProviderTest implements ServiceProvider {
|
||||
|
||||
@Override
|
||||
public Service getByName(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
65
src/main/java/com/cisdi/data/OBLF/test/StartTest.java
Normal file
65
src/main/java/com/cisdi/data/OBLF/test/StartTest.java
Normal file
@ -0,0 +1,65 @@
|
||||
package com.cisdi.data.OBLF.test;
|
||||
|
||||
import com.cisdi.data.OBLF.impl.OBLFChannelInitializer;
|
||||
import com.cisdi.data.OBLF.impl.OBLFSessionFactory;
|
||||
import com.cisdi.data.sdk.enums.ByteOrder;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
|
||||
import com.cisdi.data.sdk.vo.GatewayVo;
|
||||
import io.netty.handler.ssl.OpenSsl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author cuianbing
|
||||
* @version 1.0
|
||||
* @description: TODO
|
||||
* @date 2021/7/7 19:28
|
||||
*/
|
||||
@Slf4j
|
||||
public class StartTest {
|
||||
|
||||
private static TcpIoService ioService = null;
|
||||
|
||||
private static SessionFactory sessionFactory = null;
|
||||
|
||||
public static void main(String[] args) {
|
||||
boolean available = OpenSsl.isAvailable();
|
||||
log.info("openssl available={}", available);
|
||||
|
||||
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
|
||||
|
||||
SessionFactory factory = new OBLFSessionFactory(null);
|
||||
|
||||
ServiceProviderTest testServiceProvider = new ServiceProviderTest();
|
||||
|
||||
factory.init(testServiceProvider, null);
|
||||
|
||||
OBLFChannelInitializer channelInitializer =
|
||||
new OBLFChannelInitializer(factory, ByteOrder.BIGENDIAN, null);
|
||||
|
||||
GatewayVo instanceVo = new GatewayVo();
|
||||
instanceVo.setByteOrder(ByteOrder.BIGENDIAN);
|
||||
instanceVo.setParameter("{\"listenIp\":\"0.0.0.0\",\"listenPort\":8888,\"threadSize\":50,\"timeout\":2000}");
|
||||
|
||||
defaultIoService.init(instanceVo, factory, channelInitializer);
|
||||
|
||||
ioService = defaultIoService;
|
||||
sessionFactory = factory;
|
||||
|
||||
boolean open = ioService.open();
|
||||
|
||||
if (open == true) {
|
||||
log.info("plc网关启动成功");
|
||||
} else {
|
||||
log.info("plc网关启动失败");
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(10000000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
28
src/main/java/com/cisdi/data/OBLF/util/ByteBufUtil.java
Normal file
28
src/main/java/com/cisdi/data/OBLF/util/ByteBufUtil.java
Normal file
@ -0,0 +1,28 @@
|
||||
package com.cisdi.data.OBLF.util;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import static io.netty.buffer.ByteBufUtil.appendPrettyHexDump;
|
||||
import static io.netty.util.internal.StringUtil.NEWLINE;
|
||||
|
||||
/**
|
||||
* @author cuianbing
|
||||
* @version 1.0
|
||||
* @description: TODO
|
||||
* @date 2021/7/9 15:32
|
||||
*/
|
||||
@Slf4j
|
||||
public class ByteBufUtil {
|
||||
public static void log(ByteBuf byteBuf) {
|
||||
int length = byteBuf.readableBytes();
|
||||
int row = length / 16 + (length % 15 == 0 ? 0 : 1) + 4;
|
||||
StringBuilder buf = new StringBuilder(row * 80 * 2)
|
||||
.append("read index:").append(byteBuf.readerIndex())
|
||||
.append(" write index:").append(byteBuf.writerIndex())
|
||||
.append(" capacity:").append(byteBuf.capacity())
|
||||
.append(NEWLINE);
|
||||
appendPrettyHexDump(buf, byteBuf);
|
||||
log.info(buf.toString());
|
||||
}
|
||||
}
|
27
src/main/java/com/cisdi/data/OBLF/util/HexTransform.java
Normal file
27
src/main/java/com/cisdi/data/OBLF/util/HexTransform.java
Normal file
@ -0,0 +1,27 @@
|
||||
package com.cisdi.data.OBLF.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author cuianbing
|
||||
* @version 1.0
|
||||
* @description: 16进制转换工具类
|
||||
* @date 2021/7/7 21:41
|
||||
*/
|
||||
@Slf4j
|
||||
public class HexTransform {
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @param: hex 16进制字符串
|
||||
* @param: chartSet 字符集 UTF-8 GB2312 ASCII
|
||||
* @return: java.lang.String
|
||||
* @author cuianbing
|
||||
* @date: 2021/7/7 21:43
|
||||
*/
|
||||
public static String HexToString(String hex, String chartSet) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
135
src/main/java/com/cisdi/data/RFID/gateway/RfidClient.java
Normal file
135
src/main/java/com/cisdi/data/RFID/gateway/RfidClient.java
Normal file
@ -0,0 +1,135 @@
|
||||
package com.cisdi.data.RFID.gateway;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.epoll.*;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class RfidClient {
|
||||
private static final Logger logger = LoggerFactory.getLogger(RfidClient.class);
|
||||
private volatile Channel channel = null;
|
||||
private EventLoopGroup workerGroup = null;
|
||||
private RfidTaskStartVo startVo;
|
||||
private Long lastHeartbeatTime = System.currentTimeMillis();
|
||||
|
||||
public RfidClient(RfidTaskStartVo startVo) {
|
||||
this.startVo = startVo;
|
||||
|
||||
if (Epoll.isAvailable()) {
|
||||
logger.info("rfid enable epoll and have tcp SO_KEEPALIVE check");
|
||||
} else {
|
||||
logger.info("rfid disable epoll and not have custom SO_KEEPALIVE check");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean close() {
|
||||
boolean result = false;
|
||||
if (workerGroup == null && channel == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (channel != null) {
|
||||
try {
|
||||
channel.close().sync();
|
||||
channel = null;
|
||||
result = true;
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
if (workerGroup != null) {
|
||||
try {
|
||||
workerGroup.shutdownGracefully().sync();
|
||||
workerGroup = null;
|
||||
result = true;
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("永锋物流rfid到 {}:{}的连接关闭失败,{}",
|
||||
startVo.getSocketParam().getPeerIp(), startVo.getSocketParam().getPeerPort(), e);
|
||||
}
|
||||
}
|
||||
|
||||
if (channel != null || workerGroup != null) {
|
||||
logger.info("channel:{},workgoup:{}", channel, workerGroup);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void run() throws IOException {
|
||||
start();
|
||||
}
|
||||
|
||||
private void start() {
|
||||
lastHeartbeatTime = System.currentTimeMillis();
|
||||
if (channel != null) {
|
||||
close();
|
||||
}
|
||||
|
||||
//设置一个多线程循环器
|
||||
//启动附注类
|
||||
Bootstrap bootstrap = new Bootstrap();
|
||||
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
|
||||
if (Epoll.isAvailable()) {
|
||||
bootstrap.channel(EpollSocketChannel.class);
|
||||
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
|
||||
bootstrap.option(EpollChannelOption.TCP_KEEPIDLE, 10);
|
||||
bootstrap.option(EpollChannelOption.TCP_KEEPINTVL, 5);
|
||||
bootstrap.option(EpollChannelOption.TCP_KEEPCNT, 2);
|
||||
workerGroup = new EpollEventLoopGroup(2);
|
||||
} else {
|
||||
workerGroup = new NioEventLoopGroup(2);
|
||||
bootstrap.channel(NioSocketChannel.class);
|
||||
}
|
||||
|
||||
bootstrap.group(workerGroup);
|
||||
//指定所使用的NIO传输channel
|
||||
//指定客户端初始化处理
|
||||
bootstrap.handler(new RfidClientInitializer(startVo, this));
|
||||
try {
|
||||
channel = bootstrap.connect(startVo.getSocketParam().getPeerIp(),
|
||||
startVo.getSocketParam().getPeerPort()).sync().channel();
|
||||
//channel.closeFuture().sync(); // 如果会话关闭,会退出当前线程
|
||||
} catch (InterruptedException e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void reconnect() {
|
||||
logger.info("永锋物流rfid重新连接中......{}:{}", getIp(), getPort());
|
||||
close();
|
||||
start();
|
||||
}
|
||||
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public void setChannel(Channel channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return startVo.getSocketParam().getPeerIp();
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return startVo.getSocketParam().getPeerPort();
|
||||
}
|
||||
|
||||
public Long getLastHeartbeatTime() {
|
||||
return lastHeartbeatTime;
|
||||
}
|
||||
|
||||
public void setLastHeartbeatTime(Long lastHeartbeatTime) {
|
||||
this.lastHeartbeatTime = lastHeartbeatTime;
|
||||
}
|
||||
}
|
110
src/main/java/com/cisdi/data/RFID/gateway/RfidClientHandler.java
Normal file
110
src/main/java/com/cisdi/data/RFID/gateway/RfidClientHandler.java
Normal file
@ -0,0 +1,110 @@
|
||||
package com.cisdi.data.RFID.gateway;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.gateway.message.SocketMessage;
|
||||
import com.cisdi.data.sdk.service.SendService;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class RfidClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RfidClientHandler.class);
|
||||
private static final Charset Encode_Charset = Charset.forName("UTF-8");
|
||||
private static final String HEARTBEAT_CODE = "HeartBea";
|
||||
|
||||
private RfidClient rfidClient;
|
||||
|
||||
private RfidTaskStartVo startVo;
|
||||
|
||||
public RfidClientHandler(RfidTaskStartVo startVo, RfidClient rfidClient) {
|
||||
this.startVo = startVo;
|
||||
this.rfidClient = rfidClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
|
||||
|
||||
try {
|
||||
List<RfidItemVo> decode = RfidVoDecoder.Decode(msg);
|
||||
if(decode.size() == 1 && HEARTBEAT_CODE.equalsIgnoreCase(decode.get(0).getCode())) {
|
||||
logger.info("永锋物流Rfid {},启用心跳:{} , 心跳 vo:{}", rfidClient.getChannel(),
|
||||
startVo.getCustomParam() == null ? false : startVo.getCustomParam().getEnableHeartbeat(),
|
||||
decode);
|
||||
rfidClient.setLastHeartbeatTime(System.currentTimeMillis());
|
||||
return;
|
||||
}
|
||||
|
||||
decode.forEach((RfidItemVo i) -> {
|
||||
i.setServerIp(startVo.getSocketParam().getPeerIp());
|
||||
i.setServerPort(startVo.getSocketParam().getPeerPort());
|
||||
});
|
||||
|
||||
|
||||
if (startVo.getGatewayBase() != null && Boolean.TRUE.equals(startVo.getGatewayBase().getInstanceVo().getLogOpen())) {
|
||||
logger.info("永锋物流Rfid {} vo:{} ", rfidClient.getChannel(), decode);
|
||||
}
|
||||
|
||||
if (startVo.getGatewayBase() != null && startVo.getServiceProvider() != null) {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
SendService service = (SendService) startVo.getServiceProvider().getByName(ServiceName.Send);
|
||||
SocketMessage socketMessage = startVo.getGatewayBase().buildSocketMessage();
|
||||
socketMessage.setDeviceId(startVo.getDeviceId());
|
||||
socketMessage.setProviderCode(null);
|
||||
socketMessage.setMsgKey("666");
|
||||
data.put("data", decode);
|
||||
String jsonString = JSON.toJSONString(data, SerializerFeature.WriteMapNullValue);
|
||||
byte[] body = jsonString.getBytes(Encode_Charset);
|
||||
socketMessage.setData(body);
|
||||
logger.info("socketMess" + socketMessage.toString());
|
||||
service.sendMessage(socketMessage);
|
||||
} else {
|
||||
logger.info("永锋物流Rfid收到消息{}", decode);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
logger.info("{} channelActive active", ctx.channel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
logger.info("{} channelInactive inactive", ctx.channel());
|
||||
|
||||
try {
|
||||
rfidClient.setChannel(null);
|
||||
logger.info("set channel to null raise reconnect");
|
||||
} finally {
|
||||
// 释放引用
|
||||
rfidClient = null;
|
||||
}
|
||||
|
||||
super.channelInactive(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception {
|
||||
logger.error("exceptionCaught:{}", t);
|
||||
super.exceptionCaught(ctx, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||
logger.error("userEventTriggered:{}", evt);
|
||||
super.userEventTriggered(ctx, evt);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.cisdi.data.RFID.gateway;
|
||||
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
|
||||
public class RfidClientInitializer extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
private RfidClient rfidClient;
|
||||
private RfidTaskStartVo startVo;
|
||||
|
||||
public RfidClientInitializer(RfidTaskStartVo startVo, RfidClient rfidClient) {
|
||||
this.startVo = startVo;
|
||||
this.rfidClient = rfidClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel socketChannel) throws Exception {
|
||||
//注册管道
|
||||
ChannelPipeline pipeline = socketChannel.pipeline();
|
||||
pipeline.addLast(new RfidFrameDecoder(startVo));
|
||||
pipeline.addLast("chat", new RfidClientHandler(startVo, rfidClient));
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.cisdi.data.RFID.gateway;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Rfid server有多个,所以需要支持配置多个服务端地址的
|
||||
* @author cup
|
||||
* @date 2021/03/03
|
||||
*/
|
||||
public class RfidCustomParam implements Serializable {
|
||||
private static final long serialVersionUID = -5017472517219960138L;
|
||||
|
||||
/**
|
||||
* 每个String 如 192.168.1.5:8823 形式
|
||||
*/
|
||||
private List<String> serverList = new ArrayList<String>();
|
||||
|
||||
private Boolean enableHeartbeat = Boolean.FALSE;
|
||||
|
||||
private Integer heartbeatTimeInMs = 5000;
|
||||
private Integer heartbeatMaxLostCount = 3;
|
||||
|
||||
public List<String> getServerList() {
|
||||
return serverList;
|
||||
}
|
||||
|
||||
public void setServerList(List<String> serverList) {
|
||||
this.serverList = serverList;
|
||||
}
|
||||
|
||||
public Boolean getEnableHeartbeat() {
|
||||
return enableHeartbeat;
|
||||
}
|
||||
|
||||
public void setEnableHeartbeat(Boolean enableHeartbeat) {
|
||||
this.enableHeartbeat = enableHeartbeat;
|
||||
}
|
||||
|
||||
public Integer getHeartbeatTimeInMs() {
|
||||
return heartbeatTimeInMs;
|
||||
}
|
||||
|
||||
public void setHeartbeatTimeInMs(Integer heartbeatTimeInMs) {
|
||||
this.heartbeatTimeInMs = heartbeatTimeInMs;
|
||||
}
|
||||
|
||||
public Integer getHeartbeatMaxLostCount() {
|
||||
return heartbeatMaxLostCount;
|
||||
}
|
||||
|
||||
public void setHeartbeatMaxLostCount(Integer heartbeatMaxLostCount) {
|
||||
this.heartbeatMaxLostCount = heartbeatMaxLostCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
|
||||
public static void main(String[] args){
|
||||
RfidCustomParam dto = new RfidCustomParam();
|
||||
dto.getServerList().add("192.168.6.55:10000");
|
||||
dto.getServerList().add("192.168.6.56:10000");
|
||||
dto.getServerList().add("192.165.20.111:10000");
|
||||
dto.getServerList().add("192.165.20.112:10000");
|
||||
dto.getServerList().add("192.165.20.113:10000");
|
||||
dto.getServerList().add("192.165.20.119:10000");
|
||||
dto.getServerList().add("192.165.20.118:10000");
|
||||
dto.getServerList().add("192.165.20.120:10000");
|
||||
dto.getServerList().add("192.165.20.121:10000");
|
||||
dto.getServerList().add("192.165.20.121:10000");
|
||||
List<String> customParams=dto.getServerList().stream().distinct().collect(Collectors.toList());
|
||||
System.out.println(customParams);
|
||||
System.out.println(dto);
|
||||
}
|
||||
}
|
150
src/main/java/com/cisdi/data/RFID/gateway/RfidDaemonTask.java
Normal file
150
src/main/java/com/cisdi/data/RFID/gateway/RfidDaemonTask.java
Normal file
@ -0,0 +1,150 @@
|
||||
package com.cisdi.data.RFID.gateway;
|
||||
|
||||
import com.cisdi.data.common.dto.AlarmDto;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.service.AlarmService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
public class RfidDaemonTask implements Runnable {
|
||||
private static final Logger logger = LoggerFactory.getLogger(RfidDaemonTask.class);
|
||||
|
||||
private RfidClient rfidClient;
|
||||
private RfidTaskStartVo startVo;
|
||||
|
||||
public RfidDaemonTask(RfidClient rfidClient, RfidTaskStartVo startVo) {
|
||||
this.rfidClient = rfidClient;
|
||||
this.startVo = startVo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String channelInfo = null;
|
||||
while (startVo.getShouldRun().get() == true) {
|
||||
channelInfo = String.format("channel:%s, active:%s,open:%s,writable:%s", rfidClient.getChannel(),
|
||||
rfidClient.getChannel() == null ? "" : rfidClient.getChannel().isActive(),
|
||||
rfidClient.getChannel() == null ? "" : rfidClient.getChannel().isOpen(),
|
||||
rfidClient.getChannel() == null ? "" : rfidClient.getChannel().isWritable());
|
||||
try {
|
||||
if (rfidClient != null && rfidClient.getChannel() != null
|
||||
&& rfidClient.getChannel().isActive() == true) {
|
||||
if (startVo.getGatewayBase() != null
|
||||
&& Boolean.TRUE.equals(startVo.getGatewayBase().getInstanceVo().getLogOpen())) {
|
||||
logger.info("当前永锋物流Rfid拉取连接通道处于连接状态,连接id:{},连接信息:{}",
|
||||
startVo.getGatewayBase().getInstanceVo().getRunId(), channelInfo);
|
||||
}
|
||||
|
||||
if(startVo.getCustomParam() != null
|
||||
&& Boolean.TRUE.equals(startVo.getCustomParam().getEnableHeartbeat())
|
||||
&& Math.abs(System.currentTimeMillis() - rfidClient.getLastHeartbeatTime()) >
|
||||
startVo.getCustomParam().getHeartbeatMaxLostCount() * startVo.getCustomParam().getHeartbeatTimeInMs()){
|
||||
logger.warn("当前永锋物流Rfid拉取连接通道心跳启用,且心跳超时,触发重连,连接id:{},连接信息:{}",
|
||||
startVo.getGatewayBase().getInstanceVo().getRunId(), channelInfo);
|
||||
//启用了心跳,且心跳时间超时
|
||||
reconnectToRfid(channelInfo, true);
|
||||
}
|
||||
} else if (rfidClient.getChannel() == null) {
|
||||
String errorMsg = String.format("永锋物流Rfid到%s:%s的连接未建立或已关闭, %s", rfidClient.getIp(),
|
||||
rfidClient.getPort(), channelInfo);
|
||||
logger.warn(errorMsg);
|
||||
sendAlarmToPlatform(errorMsg);
|
||||
reconnectToRfid(channelInfo, false);
|
||||
}
|
||||
else {
|
||||
String errorMsg = String.format("永锋物流Rfid到%s:%s的连接未建立或已关闭, %s", rfidClient.getIp(),
|
||||
rfidClient.getPort(), channelInfo);
|
||||
logger.warn(errorMsg);
|
||||
|
||||
sendAlarmToPlatform(errorMsg);
|
||||
|
||||
if(startVo.getCustomParam() != null
|
||||
&& Boolean.TRUE.equals(startVo.getCustomParam().getEnableHeartbeat())
|
||||
&& Math.abs(System.currentTimeMillis() - rfidClient.getLastHeartbeatTime()) >
|
||||
startVo.getCustomParam().getHeartbeatMaxLostCount() * startVo.getCustomParam().getHeartbeatTimeInMs()){
|
||||
logger.warn("当前永锋物流Rfid拉取连接通道心跳启用,且心跳超时,触发重连,连接id:{},连接信息:{}",
|
||||
startVo.getGatewayBase().getInstanceVo().getRunId(), channelInfo);
|
||||
//启用了心跳,且心跳时间超时
|
||||
reconnectToRfid(channelInfo, true);
|
||||
}
|
||||
}
|
||||
|
||||
Thread.sleep(startVo.getSocketParam().getPullInternal());
|
||||
} catch (Exception e) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
if (rfidClient != null) {
|
||||
rfidClient.close();
|
||||
rfidClient = null;
|
||||
}
|
||||
logger.info("退出永锋物流Rfid拉取连接线程 {}", channelInfo);
|
||||
}
|
||||
|
||||
private void reconnectToRfid(final String copyChannelInfo, boolean forceConnect) throws InterruptedException {
|
||||
Thread.sleep(5000);
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
logger.info("永锋物流Rfid触发重连强制:{}....{}:{} {}", forceConnect, rfidClient.getIp(), rfidClient.getPort(),
|
||||
copyChannelInfo);
|
||||
if (rfidClient.getChannel() == null || forceConnect) {
|
||||
rfidClient.reconnect();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.info(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void forceReconnectToRfid() {
|
||||
String channelInfo = String.format("channel:%s, active:%s,open:%s,writable:%s", rfidClient.getChannel(),
|
||||
rfidClient.getChannel() == null ? "" : rfidClient.getChannel().isActive(),
|
||||
rfidClient.getChannel() == null ? "" : rfidClient.getChannel().isOpen(),
|
||||
rfidClient.getChannel() == null ? "" : rfidClient.getChannel().isWritable());
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
logger.info("永锋物流Rfid触发重连强制:{}....{}:{} {}", true, rfidClient.getIp(), rfidClient.getPort(),
|
||||
channelInfo);
|
||||
rfidClient.reconnect();
|
||||
} catch (Exception e) {
|
||||
logger.info(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendAlarmToPlatform(String detail) {
|
||||
if (startVo.getServiceProvider() != null && startVo.getGatewayBase() != null) {
|
||||
AlarmService alarmService = (AlarmService)startVo.getServiceProvider().getByName(ServiceName.Alarm);
|
||||
if (alarmService != null) {
|
||||
AlarmDto alarmDto = new AlarmDto();
|
||||
|
||||
alarmDto.setAlarmType(AlarmDto.Connect_Fail_Alarm);
|
||||
alarmDto.setDetail(detail);
|
||||
alarmDto.setDeviceId(startVo.getDeviceId());
|
||||
alarmDto.setGatewayId(startVo.getGatewayBase().getInstanceVo().getRunId());
|
||||
alarmDto.setGatewayName(startVo.getGatewayBase().getInstanceVo().getName());
|
||||
alarmDto.setMsgKey(null);
|
||||
alarmDto.setUpper(Boolean.TRUE);
|
||||
alarmDto.setTime(new Date());
|
||||
|
||||
alarmService.raiseAlarm(Arrays.asList(alarmDto));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.cisdi.data.RFID.gateway;
|
||||
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @Description: 获取完整的报文
|
||||
* @Creator: Mo
|
||||
* @Date: 2021/6/2 23:37
|
||||
*/
|
||||
@Slf4j
|
||||
public class RfidFrameDecoder extends ByteToMessageDecoder {
|
||||
private static final Logger logger = LoggerFactory.getLogger(RfidFrameDecoder.class);
|
||||
|
||||
private RfidTaskStartVo startVo;
|
||||
|
||||
private final static Integer MIN_LENGTH = 10;
|
||||
private final byte START_SPLIT = 0x02;
|
||||
private final byte END_SPLIT = 0x03;
|
||||
private final Set<Integer> validDataSizeInByte = new HashSet<Integer>(Arrays.asList(10));
|
||||
|
||||
public RfidFrameDecoder(RfidTaskStartVo startVo) {
|
||||
this.startVo = startVo;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf bufferIn, List<Object> out) throws Exception {
|
||||
if (bufferIn.readableBytes() < MIN_LENGTH) {
|
||||
return;
|
||||
}
|
||||
String channelInfo = ctx.toString();
|
||||
|
||||
// 心跳报文为 02 48 65 61 72 74 42 65 61 03 长度10个字节,拥有独立的起始符和结束符,不会和数据报文共享起始符和结束符
|
||||
// 数据体长度固定为 8,心跳报文数据内容为 HeartBea
|
||||
int beginIndex = bufferIn.readerIndex();
|
||||
|
||||
for (int i = 0; i + 9 < bufferIn.readableBytes(); i += 10) {
|
||||
byte curByte = bufferIn.getByte(beginIndex + i);
|
||||
if(curByte != START_SPLIT){
|
||||
ctx.close();
|
||||
throw new BusinessException(channelInfo + "完整报文第一个字节内容不正确,期望: 0x02,实际:" + curByte);
|
||||
}
|
||||
|
||||
byte endByte = bufferIn.getByte(beginIndex + i + 9);
|
||||
if(endByte != END_SPLIT){
|
||||
ctx.close();
|
||||
throw new BusinessException(channelInfo + "完整报文最后一个字节内容不正确,期望: 0x03,实际:" + endByte);
|
||||
}
|
||||
|
||||
out.add(bufferIn.retainedSlice(beginIndex + i, 10));
|
||||
bufferIn.readerIndex(beginIndex + i + 10);
|
||||
}
|
||||
}
|
||||
}
|
58
src/main/java/com/cisdi/data/RFID/gateway/RfidItemVo.java
Normal file
58
src/main/java/com/cisdi/data/RFID/gateway/RfidItemVo.java
Normal file
@ -0,0 +1,58 @@
|
||||
package com.cisdi.data.RFID.gateway;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 读取到标签或标签离开,解析后的内容都一致
|
||||
*
|
||||
* @author cup
|
||||
* @date 2021/03/03
|
||||
*/
|
||||
public class RfidItemVo implements Serializable {
|
||||
private static final long serialVersionUID = -4290553035349526464L;
|
||||
/**
|
||||
* rfid 服务器Ip
|
||||
*/
|
||||
private String serverIp;
|
||||
|
||||
/**
|
||||
* rfid 服务器端口
|
||||
*/
|
||||
private Integer serverPort;
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
private String code;
|
||||
|
||||
public String getServerIp() {
|
||||
return serverIp;
|
||||
}
|
||||
|
||||
public void setServerIp(String serverIp) {
|
||||
this.serverIp = serverIp;
|
||||
}
|
||||
|
||||
public Integer getServerPort() {
|
||||
return serverPort;
|
||||
}
|
||||
|
||||
public void setServerPort(Integer serverPort) {
|
||||
this.serverPort = serverPort;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
package com.cisdi.data.RFID.gateway;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.common.utils.Strings;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.enums.GatewayState;
|
||||
import com.cisdi.data.sdk.gateway.base.PulledSocketGatewayBase;
|
||||
import com.cisdi.data.sdk.param.PullSocketParam;
|
||||
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
|
||||
import com.cisdi.data.sdk.service.RouteService;
|
||||
import com.cisdi.data.sdk.vo.DeviceVo;
|
||||
import com.cisdi.data.sdk.vo.ExeResultVo;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 物流 rfid 驱动,平台:客户端 rfid:server,多个server,使用tcp协议
|
||||
*
|
||||
* @author cup
|
||||
* @date 2021/03/04
|
||||
*/
|
||||
public class RfidPullSocketGateway extends PulledSocketGatewayBase {
|
||||
private static Logger logger = LoggerFactory.getLogger(RfidPullSocketGateway.class);
|
||||
|
||||
private String deviceId;
|
||||
private AtomicBoolean shouldRun = null;
|
||||
private static final int Min_Pull_Internal = 1; // 允许最小的拉取间隔为1毫秒
|
||||
private static final int Min_Timeout = 1000; // 允许最小的超时时间间隔,为1000毫秒
|
||||
|
||||
@Override
|
||||
public ExeResultVo sendReturnMessage(SocketReturnMessage returnMsg) {
|
||||
throw new BusinessException("永锋物流Rfid协议不支持下发命令。");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (state == GatewayState.RUNNING) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
startInternal();
|
||||
state = GatewayState.RUNNING;
|
||||
logger.info("永锋物流Rfid报警socket拉取网关:{}启动成功", instanceVo.getRunId());
|
||||
} catch (Exception e) {
|
||||
logger.error("永锋物流Rfid报警socket拉取网关:{}启动失败", instanceVo.getRunId());
|
||||
logger.error(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void startInternal() {
|
||||
socketParam = JSON.parseObject(getInstanceVo().getParameter(), PullSocketParam.class);
|
||||
|
||||
if (StringUtils.isEmpty(socketParam.getPeerIp()) || socketParam.getPeerPort() == null) {
|
||||
throw new BusinessException("未正确配置拉取对端ip地址和对端端口。");
|
||||
}
|
||||
|
||||
if (socketParam.getPullInternal() == null) {
|
||||
throw new BusinessException("未正确配置拉取间隔");
|
||||
}
|
||||
|
||||
if (socketParam.getTimeout() == null) {
|
||||
throw new BusinessException("未正确配置拉取超时时间");
|
||||
}
|
||||
|
||||
socketParam.setPullInternal(socketParam.getPullInternal() < Min_Pull_Internal ?
|
||||
Min_Pull_Internal : socketParam.getPullInternal());
|
||||
|
||||
socketParam.setTimeout(socketParam.getTimeout() < Min_Timeout ? Min_Timeout : socketParam.getTimeout());
|
||||
|
||||
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
|
||||
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
|
||||
|
||||
if (deviceVos.size() > 1) {
|
||||
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为永锋物流Rfid报警socket拉取网关,只允许关联一个设备Id");
|
||||
}
|
||||
|
||||
deviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
|
||||
|
||||
if (StringUtils.isEmpty(deviceId)) {
|
||||
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
|
||||
}
|
||||
|
||||
logger.info("永锋物流Rfid报警socket拉取网关:{}读取启动配置参数:{}", getInstanceVo().getRunId(), socketParam);
|
||||
|
||||
closePrevState();
|
||||
shouldRun = new AtomicBoolean(true);
|
||||
|
||||
String parameter = socketParam.getOtherParameter();
|
||||
Set<String> targetServerSet = new HashSet<String>();
|
||||
targetServerSet.add(String.format("%s:%s", socketParam.getPeerIp(), socketParam.getPeerPort()));
|
||||
RfidCustomParam customParam = null;
|
||||
if (parameter != null) {
|
||||
customParam = JSON.parseObject(parameter, RfidCustomParam.class);
|
||||
if (customParam != null) {
|
||||
/**
|
||||
* RFID服务端参数去重
|
||||
*/
|
||||
customParam.setServerList(customParam.getServerList().stream().distinct().collect(Collectors.toList()));
|
||||
for (String server : customParam.getServerList()) {
|
||||
targetServerSet.add(server.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int index = 1;
|
||||
for (String server : targetServerSet) {
|
||||
// 复制已有参数
|
||||
PullSocketParam serverParam = JSON.parseObject(JSON.toJSONString(socketParam), PullSocketParam.class);
|
||||
|
||||
serverParam.setPeerIp(Strings.split(server, ":")[0]);
|
||||
serverParam.setPeerPort(Integer.valueOf(Strings.split(server, ":")[1]));
|
||||
|
||||
// 启动线程
|
||||
RfidTaskStartVo startVo = new RfidTaskStartVo();
|
||||
startVo.setDeviceId(deviceId);
|
||||
startVo.setGatewayBase(this);
|
||||
startVo.setServiceProvider(serviceProvider);
|
||||
startVo.setSocketParam(serverParam);
|
||||
startVo.setShouldRun(shouldRun);
|
||||
startVo.setCustomParam(customParam);
|
||||
|
||||
RfidClient fireClient = new RfidClient(startVo);
|
||||
RfidDaemonTask daemonTask = new RfidDaemonTask(fireClient, startVo);
|
||||
startVo.setRfidDaemonTask(daemonTask);
|
||||
Thread thread = new Thread(daemonTask, "Fire-Daemon-Task-runid-" + instanceVo.getRunId() + "-s" + index++);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
|
||||
state = GatewayState.RUNNING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (state == GatewayState.CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
closePrevState();
|
||||
|
||||
logger.info("永锋物流Rfid报警socket拉取网关:{}关闭中", getInstanceVo().getRunId());
|
||||
|
||||
state = GatewayState.CLOSED;
|
||||
|
||||
logger.info("永锋物流Rfid报警socket拉取网关:{}关闭成功", getInstanceVo().getRunId());
|
||||
}
|
||||
|
||||
private void closePrevState() {
|
||||
if (shouldRun != null) {
|
||||
shouldRun.set(false);
|
||||
shouldRun = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getActiveDeviceIds() {
|
||||
Set<String> set = new HashSet<String>();
|
||||
if (deviceId != null) {
|
||||
set.add(deviceId);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.cisdi.data.RFID.gateway;
|
||||
|
||||
import com.cisdi.data.sdk.gateway.base.PulledSocketGatewayBase;
|
||||
import com.cisdi.data.sdk.param.PullSocketParam;
|
||||
import com.cisdi.data.sdk.service.ServiceProvider;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class RfidTaskStartVo {
|
||||
private AtomicBoolean shouldRun;
|
||||
private ServiceProvider serviceProvider;
|
||||
private String deviceId;
|
||||
private PulledSocketGatewayBase gatewayBase;
|
||||
private PullSocketParam socketParam;
|
||||
private RfidCustomParam customParam;
|
||||
private RfidDaemonTask rfidDaemonTask;
|
||||
|
||||
public AtomicBoolean getShouldRun() {
|
||||
return shouldRun;
|
||||
}
|
||||
public void setShouldRun(AtomicBoolean shouldRun) {
|
||||
this.shouldRun = shouldRun;
|
||||
}
|
||||
public ServiceProvider getServiceProvider() {
|
||||
return serviceProvider;
|
||||
}
|
||||
public void setServiceProvider(ServiceProvider serviceProvider) {
|
||||
this.serviceProvider = serviceProvider;
|
||||
}
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
public PulledSocketGatewayBase getGatewayBase() {
|
||||
return gatewayBase;
|
||||
}
|
||||
public void setGatewayBase(PulledSocketGatewayBase gatewayBase) {
|
||||
this.gatewayBase = gatewayBase;
|
||||
}
|
||||
public PullSocketParam getSocketParam() {
|
||||
return socketParam;
|
||||
}
|
||||
public void setSocketParam(PullSocketParam socketParam) {
|
||||
this.socketParam = socketParam;
|
||||
}
|
||||
public RfidCustomParam getCustomParam() {
|
||||
return customParam;
|
||||
}
|
||||
public void setCustomParam(RfidCustomParam customParam) {
|
||||
this.customParam = customParam;
|
||||
}
|
||||
|
||||
public RfidDaemonTask getRfidDaemonTask() {
|
||||
return rfidDaemonTask;
|
||||
}
|
||||
|
||||
public void setRfidDaemonTask(RfidDaemonTask rfidDaemonTask) {
|
||||
this.rfidDaemonTask = rfidDaemonTask;
|
||||
}
|
||||
}
|
87
src/main/java/com/cisdi/data/RFID/gateway/RfidVoDecoder.java
Normal file
87
src/main/java/com/cisdi/data/RFID/gateway/RfidVoDecoder.java
Normal file
@ -0,0 +1,87 @@
|
||||
package com.cisdi.data.RFID.gateway;
|
||||
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.util.HexUtil;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RfidVoDecoder {
|
||||
|
||||
public static List<RfidItemVo> Decode(ByteBuf in) {
|
||||
RfidItemVo vo = new RfidItemVo();
|
||||
List<RfidItemVo> result = new ArrayList<>();
|
||||
//消息体部分
|
||||
int length;
|
||||
if (in == null) {
|
||||
throw new BusinessException("ByteBuf 入参为null");
|
||||
} else if (in.readableBytes() == 10) {
|
||||
length = 8;
|
||||
}
|
||||
else {
|
||||
throw new BusinessException("报文长度不匹配 ,期望:10,实际:" + in.readableBytes());
|
||||
}
|
||||
//去掉报文头 和 结束符
|
||||
ByteBuf proceedIn = in.retainedSlice(1, length);
|
||||
result.add(split(proceedIn));
|
||||
ReferenceCountUtil.release(proceedIn);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param in 去掉头尾的报文
|
||||
* @Description: 拆分报文
|
||||
* @author: Mo
|
||||
* @Date: 2021/6/2 10:51
|
||||
* @return: com.cisdi.data.RFID.gateway.RfidItemVo
|
||||
*/
|
||||
public static RfidItemVo split(ByteBuf in) {
|
||||
RfidItemVo rfidItemVo = new RfidItemVo();
|
||||
ByteBuf buf = in.readBytes(8);
|
||||
// 编号
|
||||
String code = buf.toString(CharsetUtil.UTF_8);
|
||||
rfidItemVo.setCode(code);
|
||||
ReferenceCountUtil.release(buf);
|
||||
return rfidItemVo;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// 标签读取
|
||||
// byte[] readBytes1 = HexUtil.hexStringToBytes("001c1952000b000e3000eabcdef01234567890003001000400000501");
|
||||
// ByteBuf copiedBuffer = Unpooled.copiedBuffer(readBytes1);
|
||||
// RfidItemVo decoderVo = RfidVoDecoder.Decode(copiedBuffer);
|
||||
// logger.info("vo1={}", decoderVo);
|
||||
//
|
||||
// // 标签离开
|
||||
// readBytes1 = HexUtil.hexStringToBytes("00161942050c000e3000eabcdef01234567890003001");
|
||||
// copiedBuffer = Unpooled.copiedBuffer(readBytes1);
|
||||
// decoderVo = RfidVoDecoder.Decode(copiedBuffer);
|
||||
// logger.info("vo1={}", decoderVo);
|
||||
|
||||
//标签读取
|
||||
|
||||
|
||||
|
||||
byte[] readBytes1 = HexUtil.hexStringToBytes("02524630313030303103");
|
||||
ByteBuf copiedBuff = Unpooled.copiedBuffer(readBytes1);
|
||||
List<RfidItemVo> rfidItemVoList = RfidVoDecoder.Decode(copiedBuff);
|
||||
rfidItemVoList.forEach(System.out::println);
|
||||
|
||||
|
||||
readBytes1 = HexUtil.hexStringToBytes("0248656172744265617403");
|
||||
copiedBuff = Unpooled.copiedBuffer(readBytes1);
|
||||
rfidItemVoList = RfidVoDecoder.Decode(copiedBuff);
|
||||
rfidItemVoList.forEach(System.out::println);
|
||||
|
||||
RfidFrameDecoder decoder = new RfidFrameDecoder(null);
|
||||
readBytes1 = HexUtil.hexStringToBytes("0248656172744265617403");
|
||||
copiedBuff = Unpooled.copiedBuffer(readBytes1);
|
||||
decoder.decode(null, copiedBuff, new ArrayList<Object>());
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
package com.cisdi.data.Spectrograph8860;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.Spectrograph8860.impl.SGSessionFactory;
|
||||
import com.cisdi.data.Spectrograph8860.impl.SGChannelInitializer;
|
||||
import com.cisdi.data.Spectrograph8860.impl.SGIoSession;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.enums.GatewayState;
|
||||
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
|
||||
import com.cisdi.data.sdk.param.ListenSocketParam;
|
||||
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
|
||||
import com.cisdi.data.sdk.service.PlatformService;
|
||||
import com.cisdi.data.sdk.service.RouteService;
|
||||
import com.cisdi.data.sdk.vo.DeviceVo;
|
||||
import com.cisdi.data.sdk.vo.ExeResultVo;
|
||||
import com.cisdi.data.sdk.vo.SslConfigVo;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class SGSocketGateway extends SocketGatewayBase {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(SGSocketGateway.class);
|
||||
|
||||
TcpIoService ioService = null;
|
||||
SessionFactory sessionFactory = null;
|
||||
|
||||
// 当配置为单个设备模式时,此为该设备id
|
||||
String onlyOneDeviceId = null;
|
||||
|
||||
/**
|
||||
* 下发的时候,查配置路由,如果配置路由里面有匹配的,则走配置路由;如果没有匹配的,则原路返回
|
||||
*/
|
||||
@Override
|
||||
public ExeResultVo sendReturnMessage(SocketReturnMessage returnMsg) {
|
||||
throw new BusinessException("光谱仪8860不支持下发服务!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (state == GatewayState.RUNNING) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("plc网关:{}读取启动配置参数:{},支持多个设备:{}", instanceVo.getRunId(), instanceVo.getParameter(),
|
||||
instanceVo.getSuportMultiDevice());
|
||||
|
||||
// 不支持多个设备,必须强制配置一个设备id
|
||||
if (instanceVo.getSuportMultiDevice() != null && instanceVo.getSuportMultiDevice() == false) {
|
||||
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
|
||||
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
|
||||
|
||||
if (deviceVos.size() > 1) {
|
||||
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为光谱仪8860网关,当前配置为只支持单个设备,但配置了多个设备。");
|
||||
}
|
||||
|
||||
onlyOneDeviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
|
||||
|
||||
if (StringUtils.isEmpty(onlyOneDeviceId)) {
|
||||
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
|
||||
SessionFactory factory = new SGSessionFactory(onlyOneDeviceId);
|
||||
factory.init(serviceProvider, this);
|
||||
|
||||
SslConfigVo sslConfigVo = null;
|
||||
|
||||
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
|
||||
|
||||
if (socketParam != null && Boolean.TRUE.equals(socketParam.getEnableSsl())) {
|
||||
|
||||
PlatformService platformService = (PlatformService) serviceProvider.getByName(ServiceName.Platform);
|
||||
|
||||
sslConfigVo = platformService.getSslConfig();
|
||||
}
|
||||
|
||||
|
||||
SGChannelInitializer channelInitializer =
|
||||
new SGChannelInitializer(factory, getInstanceVo().getByteOrder(), sslConfigVo);
|
||||
|
||||
defaultIoService.init(instanceVo, factory, channelInitializer);
|
||||
|
||||
ioService = defaultIoService;
|
||||
sessionFactory = factory;
|
||||
|
||||
boolean open = ioService.open();
|
||||
|
||||
if (open == true) {
|
||||
state = GatewayState.RUNNING;
|
||||
logger.info("光谱仪8860网关:{}启动成功 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
|
||||
} else {
|
||||
logger.info("光谱仪8860网关:{}启动失败 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (state == GatewayState.CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sessionFactory != null) {
|
||||
for (IoSession ioSession : sessionFactory.getSessions()) {
|
||||
SGIoSession SGIoSession = (SGIoSession) ioSession;
|
||||
SGIoSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
boolean close = ioService.close();
|
||||
if (close == true) {
|
||||
sessionFactory = null;
|
||||
state = GatewayState.CLOSED;
|
||||
logger.info("光谱仪8860网关:{}关闭成功", instanceVo.getRunId());
|
||||
} else {
|
||||
logger.info("光谱仪8860网关:{}关闭失败", instanceVo.getRunId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getActiveDeviceIds() {
|
||||
if (onlyOneDeviceId != null) {
|
||||
Set<String> set = new HashSet<String>();
|
||||
set.add(onlyOneDeviceId);
|
||||
return set;
|
||||
} else {
|
||||
return sessionFactory.getActiveDeviceIds();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package com.cisdi.data.Spectrograph8860.impl;
|
||||
|
||||
import com.cisdi.data.sdk.enums.ByteOrder;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractChannelInitializer;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoChannelHandler;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultIoChannelHandler;
|
||||
import com.cisdi.data.sdk.utils.NettySslUtils;
|
||||
import com.cisdi.data.sdk.vo.SslConfigVo;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SGChannelInitializer<I> extends AbstractChannelInitializer<I> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SGChannelInitializer.class);
|
||||
|
||||
private SessionFactory factory;
|
||||
private ByteOrder byteOrder;
|
||||
private SslConfigVo sslConfigVo;
|
||||
|
||||
/**
|
||||
* 构造通道初始化器对象
|
||||
*
|
||||
* @param factory 会话工厂
|
||||
* @param byteOrder 大小端
|
||||
* @param sslConfig ssl证书配置,如果不启用tls,传null
|
||||
*/
|
||||
public SGChannelInitializer(SessionFactory factory,
|
||||
ByteOrder byteOrder,
|
||||
SslConfigVo sslConfig) {
|
||||
this.factory = factory;
|
||||
this.byteOrder = byteOrder;
|
||||
this.sslConfigVo = sslConfig;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected AbstractIoChannelHandler<I> getTailHandler() {
|
||||
return new DefaultIoChannelHandler(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ChannelHandler> getHandlers() {
|
||||
List<ChannelHandler> handlers = new ArrayList<ChannelHandler>();
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IdleStateHandler getIdleStateHandler() {
|
||||
return new IdleStateHandler(15, 15, 30);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChannelHandler getSslChannelHandler(Channel socketChannel) {
|
||||
ChannelHandler sslHandler = null;
|
||||
try {
|
||||
if (sslConfigVo != null) {
|
||||
sslHandler = NettySslUtils.getServerSslHandler((SocketChannel) socketChannel, sslConfigVo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn(e.getLocalizedMessage(), e);
|
||||
}
|
||||
return sslHandler;
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
@ -0,0 +1,23 @@
|
||||
package com.cisdi.data.Spectrograph8860.impl;
|
||||
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractSessionFactory;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SGSessionFactory extends AbstractSessionFactory {
|
||||
|
||||
private String onlyOneDeviceId;
|
||||
|
||||
public SGSessionFactory(String onlyoneDeviceId) {
|
||||
this.onlyOneDeviceId = onlyoneDeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IoSession newSession() {
|
||||
IoSession session = new SGIoSession(this, onlyOneDeviceId);
|
||||
session.init(UUID.randomUUID().toString(), provider, socketGateway);
|
||||
sessionSet.add(session);
|
||||
return session;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.cisdi.data.Spectrograph8860.test;
|
||||
|
||||
import com.cisdi.data.sdk.service.Service;
|
||||
import com.cisdi.data.sdk.service.ServiceProvider;
|
||||
|
||||
public class ServiceProviderTest implements ServiceProvider {
|
||||
|
||||
@Override
|
||||
public Service getByName(String name) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package com.cisdi.data.Spectrograph8860.test;
|
||||
|
||||
import com.cisdi.data.Spectrograph8860.SGSocketGateway;
|
||||
import com.cisdi.data.Spectrograph8860.impl.SGSessionFactory;
|
||||
import com.cisdi.data.Spectrograph8860.impl.SGChannelInitializer;
|
||||
import com.cisdi.data.sdk.enums.ByteOrder;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
|
||||
import com.cisdi.data.sdk.vo.GatewayVo;
|
||||
import io.netty.handler.ssl.OpenSsl;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class StartPlcTest {
|
||||
private static Logger logger = LoggerFactory.getLogger(SGSocketGateway.class);
|
||||
|
||||
private static TcpIoService ioService = null;
|
||||
@SuppressWarnings("unused")
|
||||
private static SessionFactory sessionFactory = null;
|
||||
|
||||
public static void main(String[] args) {
|
||||
boolean available = OpenSsl.isAvailable();
|
||||
logger.info("openssl available={}", available);
|
||||
|
||||
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
|
||||
SessionFactory factory = new SGSessionFactory(null);
|
||||
|
||||
ServiceProviderTest testServiceProvider = new ServiceProviderTest();
|
||||
//String passthroughAddress = "192.168.235.1:9098";
|
||||
|
||||
factory.init(testServiceProvider, null);
|
||||
|
||||
SGChannelInitializer channelInitializer =
|
||||
new SGChannelInitializer(factory, ByteOrder.BIGENDIAN, null);
|
||||
|
||||
GatewayVo instanceVo = new GatewayVo();
|
||||
instanceVo.setByteOrder(ByteOrder.BIGENDIAN);
|
||||
instanceVo.setParameter("{\"listenIp\":\"10.76.49.121\",\"listenPort\":5002,\"threadSize\":50,\"timeout\":2000}");
|
||||
|
||||
defaultIoService.init(instanceVo, factory, channelInitializer);
|
||||
|
||||
ioService = defaultIoService;
|
||||
sessionFactory = factory;
|
||||
|
||||
boolean open = ioService.open();
|
||||
|
||||
if (open == true) {
|
||||
logger.info("plc网关启动成功");
|
||||
} else {
|
||||
logger.info("plc网关启动失败");
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(10000000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
145
src/main/java/com/cisdi/data/XRFLEFT/XRFLEFTSocketGateway.java
Normal file
145
src/main/java/com/cisdi/data/XRFLEFT/XRFLEFTSocketGateway.java
Normal file
@ -0,0 +1,145 @@
|
||||
package com.cisdi.data.XRFLEFT;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.XRFLEFT.impl.XRFLeftChannelInitializer;
|
||||
import com.cisdi.data.XRFLEFT.impl.XRFLeftIoSession;
|
||||
import com.cisdi.data.XRFLEFT.impl.XRFLeftSessionFactory;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.enums.GatewayState;
|
||||
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
|
||||
import com.cisdi.data.sdk.param.ListenSocketParam;
|
||||
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
|
||||
import com.cisdi.data.sdk.service.PlatformService;
|
||||
import com.cisdi.data.sdk.service.RouteService;
|
||||
import com.cisdi.data.sdk.vo.DeviceVo;
|
||||
import com.cisdi.data.sdk.vo.ExeResultVo;
|
||||
import com.cisdi.data.sdk.vo.SslConfigVo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @description: 左侧荧光仪 10.233.2.132
|
||||
* @author cuianbing
|
||||
* @date 2021/7/15 9:27
|
||||
* @version 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class XRFLEFTSocketGateway extends SocketGatewayBase {
|
||||
|
||||
|
||||
TcpIoService ioService = null;
|
||||
SessionFactory sessionFactory = null;
|
||||
|
||||
// 当配置为单个设备模式时,此为该设备id
|
||||
String onlyOneDeviceId = null;
|
||||
|
||||
@Override
|
||||
public ExeResultVo sendReturnMessage(SocketReturnMessage socketReturnMessage) {
|
||||
throw new BusinessException("X射线荧光光谱仪不支持下发服务!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (state == GatewayState.RUNNING){
|
||||
return;
|
||||
}
|
||||
log.info("网关:{}读取启动配置参数:{},是否支持支持多个设备:{}", instanceVo.getRunId(), instanceVo.getParameter(),
|
||||
instanceVo.getSuportMultiDevice());
|
||||
|
||||
|
||||
// 不支持多个设备,必须强制配置一个设备id
|
||||
if (instanceVo.getSuportMultiDevice() != null && instanceVo.getSuportMultiDevice() == false) {
|
||||
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
|
||||
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
|
||||
|
||||
if (deviceVos.size() > 1) {
|
||||
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为X射线荧光光谱仪网关,当前配置为只支持单个设备,但配置了多个设备。");
|
||||
}
|
||||
|
||||
onlyOneDeviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
|
||||
|
||||
if (StringUtils.isEmpty(onlyOneDeviceId)) {
|
||||
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
|
||||
SessionFactory factory = new XRFLeftSessionFactory(onlyOneDeviceId);
|
||||
factory.init(serviceProvider, this);
|
||||
|
||||
SslConfigVo sslConfigVo = null;
|
||||
|
||||
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
|
||||
|
||||
if (socketParam != null && Boolean.TRUE.equals(socketParam.getEnableSsl())) {
|
||||
|
||||
PlatformService platformService = (PlatformService) serviceProvider.getByName(ServiceName.Platform);
|
||||
|
||||
sslConfigVo = platformService.getSslConfig();
|
||||
}
|
||||
|
||||
|
||||
XRFLeftChannelInitializer channelInitializer =
|
||||
new XRFLeftChannelInitializer(factory, getInstanceVo().getByteOrder(), sslConfigVo);
|
||||
|
||||
defaultIoService.init(instanceVo, factory, channelInitializer);
|
||||
|
||||
ioService = defaultIoService;
|
||||
sessionFactory = factory;
|
||||
|
||||
boolean open = ioService.open();
|
||||
|
||||
if (open == true) {
|
||||
state = GatewayState.RUNNING;
|
||||
log.info("X射线荧光光谱仪网关:{}启动成功 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
|
||||
} else {
|
||||
log.info("X射线荧光光谱仪网关:{}启动失败 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (state == GatewayState.CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sessionFactory != null) {
|
||||
for (IoSession ioSession : sessionFactory.getSessions()) {
|
||||
XRFLeftIoSession XrfIoSession = (XRFLeftIoSession) ioSession;
|
||||
XrfIoSession.close();
|
||||
}
|
||||
}
|
||||
|
||||
boolean close = ioService.close();
|
||||
if (close == true) {
|
||||
sessionFactory = null;
|
||||
state = GatewayState.CLOSED;
|
||||
log.info("X射线荧光光谱仪网关:{}关闭成功", instanceVo.getRunId());
|
||||
} else {
|
||||
log.info("X射线荧光光谱仪网关:{}关闭失败", instanceVo.getRunId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getActiveDeviceIds() {
|
||||
if (onlyOneDeviceId != null) {
|
||||
Set<String> set = new HashSet<String>();
|
||||
set.add(onlyOneDeviceId);
|
||||
return set;
|
||||
} else {
|
||||
return sessionFactory.getActiveDeviceIds();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package com.cisdi.data.XRFLEFT.impl;
|
||||
|
||||
import com.cisdi.data.sdk.enums.ByteOrder;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractChannelInitializer;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoChannelHandler;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultIoChannelHandler;
|
||||
import com.cisdi.data.sdk.utils.NettySslUtils;
|
||||
import com.cisdi.data.sdk.vo.SslConfigVo;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author cuianbing
|
||||
* @version 1.0
|
||||
* @description: TODO
|
||||
* @date 2021/7/7 18:57
|
||||
*/
|
||||
@Slf4j
|
||||
public class XRFLeftChannelInitializer<I> extends AbstractChannelInitializer<I> {
|
||||
|
||||
private SessionFactory factory;
|
||||
private ByteOrder byteOrder;
|
||||
private SslConfigVo sslConfigVo;
|
||||
|
||||
|
||||
/**
|
||||
* 构造通道初始化器对象
|
||||
* @param factory 会话工厂
|
||||
* @param byteOrder 大小端
|
||||
* @param sslConfig ssl证书配置,如果不启用tls,传null
|
||||
*/
|
||||
public XRFLeftChannelInitializer(SessionFactory factory,
|
||||
ByteOrder byteOrder,
|
||||
SslConfigVo sslConfig) {
|
||||
this.factory = factory;
|
||||
this.byteOrder = byteOrder;
|
||||
this.sslConfigVo = sslConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractIoChannelHandler<I> getTailHandler() {
|
||||
return new DefaultIoChannelHandler(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ChannelHandler> getHandlers() {
|
||||
List<ChannelHandler> handlers = new ArrayList<ChannelHandler>();
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IdleStateHandler getIdleStateHandler() {
|
||||
return new IdleStateHandler(15, 15, 30);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChannelHandler getSslChannelHandler(Channel socketChannel) {
|
||||
ChannelHandler sslHandler = null;
|
||||
try {
|
||||
if(sslConfigVo != null) {
|
||||
sslHandler = NettySslUtils.getServerSslHandler((SocketChannel)socketChannel, sslConfigVo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn(e.getLocalizedMessage(), e);
|
||||
}
|
||||
return sslHandler;
|
||||
}
|
||||
}
|
198
src/main/java/com/cisdi/data/XRFLEFT/impl/XRFLeftIoSession.java
Normal file
198
src/main/java/com/cisdi/data/XRFLEFT/impl/XRFLeftIoSession.java
Normal file
@ -0,0 +1,198 @@
|
||||
package com.cisdi.data.XRFLEFT.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.cisdi.data.common.exception.BusinessException;
|
||||
import com.cisdi.data.sdk.consts.ServiceName;
|
||||
import com.cisdi.data.sdk.gateway.message.SocketMessage;
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoSession;
|
||||
import com.cisdi.data.sdk.service.PassthroughService;
|
||||
import com.cisdi.data.sdk.service.SendService;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @description: 荧光光谱仪左侧解码
|
||||
* @author cuianbing
|
||||
* @date 2021/7/15 9:19
|
||||
* @version 1.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class XRFLeftIoSession extends AbstractIoSession implements IoSession {
|
||||
|
||||
private XRFLeftSessionFactory factory = null;
|
||||
|
||||
private String deviceId = null;
|
||||
/**
|
||||
* 如果有值,代表所有会话都使用这一个设备id,且允许多会话共享此一个设备id,不除旧会话
|
||||
*/
|
||||
private final String onlyOneDeviceId;
|
||||
|
||||
private String gwPrefixCache = null;
|
||||
|
||||
private ByteBuf allBuf = ByteBufAllocator.DEFAULT.buffer();
|
||||
|
||||
|
||||
public XRFLeftIoSession(XRFLeftSessionFactory factory, String onlyOneDeviceId) {
|
||||
super();
|
||||
this.factory = factory;
|
||||
this.onlyOneDeviceId = onlyOneDeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDeviceIds() {
|
||||
String cpDeviceId = deviceId;
|
||||
String[] result = new String[cpDeviceId == null ? 0 : 1];
|
||||
if (cpDeviceId != null) {
|
||||
result[0] = cpDeviceId;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRead(Object message) {
|
||||
try {
|
||||
|
||||
ByteBuf inBuf = (ByteBuf) message;
|
||||
if (inBuf != null) {
|
||||
allBuf.writeBytes(inBuf);
|
||||
}else {
|
||||
log.info("电文格式为空");
|
||||
}
|
||||
}catch (Exception e){
|
||||
log.error("电文格式错误!");
|
||||
throw new BusinessException("电文格式错误!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen() {
|
||||
super.onOpen();
|
||||
log.info("建立连接,channel:{}", getChannel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
log.info("onClose");
|
||||
List<Map<String,String>> messages = decode(allBuf);
|
||||
Map<String, Object> sendMessage =new HashMap<>();
|
||||
|
||||
if (serviceProvider != null && socketGateway != null) {
|
||||
for (Map<String,String> message : messages){
|
||||
sendMessage.put("data",message);
|
||||
SendService service = (SendService) serviceProvider.getByName(ServiceName.Send);
|
||||
SocketMessage socketMessage = socketGateway.buildSocketMessage();
|
||||
socketMessage.setDeviceId(onlyOneDeviceId);
|
||||
socketMessage.setData(JSON.toJSONString(sendMessage).getBytes(StandardCharsets.UTF_8));
|
||||
socketMessage.setMsgKey("default");
|
||||
service.sendMessage(socketMessage);
|
||||
if (socketGateway.getInstanceVo().getLogOpen()) {
|
||||
log.info("类似为:{}:发送消息内容{}", sendMessage.get("data"), sendMessage.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onClose();
|
||||
factory = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void close() {
|
||||
if (getChannel() != null) {
|
||||
try {
|
||||
getChannel().close().sync();
|
||||
} catch (InterruptedException e) {
|
||||
log.warn(e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onError(Throwable t) {
|
||||
// 这里会出现 java.io.IOException: 远程主机强迫关闭了一个现有的连接。
|
||||
log.info("远程主机强迫关闭了一个现有的连接。");
|
||||
// log.error("session exception:{}", t);
|
||||
}
|
||||
|
||||
|
||||
public List<Map<String,String>> decode(ByteBuf byteBuf){
|
||||
|
||||
List<Map<String,String>> dataList= new ArrayList<>();
|
||||
AtomicInteger dataFlag = new AtomicInteger();
|
||||
Map<String,String> data = null;
|
||||
|
||||
String msg = byteBuf.toString(Charset.forName("GB2312"));
|
||||
|
||||
log.debug("{}",msg);
|
||||
String[] split = msg.split("\n\r");
|
||||
for (String s: split){
|
||||
char tag = s.charAt(0);
|
||||
if (tag == '3'){
|
||||
String[] dataArray = s.split("\\s+");
|
||||
if (dataArray.length > 1){ // 分析错误会出现 `3 (Error) `的数据
|
||||
assert data != null;
|
||||
data.put(dataArray[1],dataArray[2]);
|
||||
}
|
||||
}else if (tag == '2'){
|
||||
if (dataFlag.getAndIncrement() > 0){
|
||||
log.debug("解析的数据为:{}",data);
|
||||
dataList.add(data);
|
||||
}
|
||||
data = new HashMap<>();
|
||||
//2 高炉渣 323 2021- 7-14 15:41 101
|
||||
String[] dateArray = s.split("\\s+");
|
||||
StringBuilder builder = new StringBuilder();
|
||||
// 时间会出现多余空格的问题 2021- 7-14 15:41 ,但是10月之后就可以
|
||||
for (int i = 3 , j = dateArray.length - 1 ; i < j ; i++){
|
||||
builder.append(dateArray[i]);
|
||||
}
|
||||
data.put("分析方法",dateArray[1]);
|
||||
data.put("样品名称",dateArray[2]);
|
||||
data.put("分析时间",builder.toString());
|
||||
}else if(tag == '5'){
|
||||
dataList.add(data);
|
||||
log.debug("解析的数据为:{}",data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
allBuf.clear();
|
||||
log.info("所有的的数据为:{}",dataList);
|
||||
return dataList;
|
||||
}
|
||||
|
||||
|
||||
private void passThrough(ByteBuf passthroughBuf) {
|
||||
try {
|
||||
if (serviceProvider != null && socketGateway != null) {
|
||||
PassthroughService service = (PassthroughService) serviceProvider.getByName(ServiceName.Passthrough);
|
||||
service.transfer(passthroughBuf, socketGateway.getInstanceVo().getPassthroughAddress());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("荧光光谱仪协议透传失败:" + e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public String gwPrefix() {
|
||||
if (gwPrefixCache != null) {
|
||||
return gwPrefixCache;
|
||||
}
|
||||
|
||||
gwPrefixCache = "";
|
||||
if (socketGateway != null && socketGateway.getInstanceVo() != null) {
|
||||
gwPrefixCache = "网关Id:" + socketGateway.getInstanceVo().getRunId() + "连接:" + getChannel() + " ";
|
||||
} else {
|
||||
gwPrefixCache = "连接:" + getChannel() + " ";
|
||||
}
|
||||
|
||||
return gwPrefixCache;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.cisdi.data.XRFLEFT.impl;
|
||||
|
||||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractSessionFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author cuianbing
|
||||
* @version 1.0
|
||||
* @description: TODO
|
||||
* @date 2021/7/7 18:52
|
||||
*/
|
||||
@Slf4j
|
||||
public class XRFLeftSessionFactory extends AbstractSessionFactory {
|
||||
|
||||
private String onlyOneDeviceId;
|
||||
|
||||
/**
|
||||
* @description:
|
||||
* @param: onlyOneDeviceId 设备唯一ID
|
||||
* @return: void
|
||||
* @author cuianbing
|
||||
* @date: 2021/7/7 22:10
|
||||
*/
|
||||
public XRFLeftSessionFactory(String onlyOneDeviceId) {
|
||||
this.onlyOneDeviceId = onlyOneDeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IoSession newSession() {
|
||||
IoSession session = new XRFLeftIoSession(this, onlyOneDeviceId);
|
||||
session.init(UUID.randomUUID().toString(), provider, socketGateway);
|
||||
sessionSet.add(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.cisdi.data.XRFLEFT.test;
|
||||
|
||||
import com.cisdi.data.sdk.service.Service;
|
||||
import com.cisdi.data.sdk.service.ServiceProvider;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author cuianbing
|
||||
* @version 1.0
|
||||
* @description: TODO
|
||||
* @date 2021/7/7 19:17
|
||||
*/
|
||||
@Slf4j
|
||||
public class ServiceProviderTest implements ServiceProvider {
|
||||
|
||||
@Override
|
||||
public Service getByName(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
65
src/main/java/com/cisdi/data/XRFLEFT/test/StartTest.java
Normal file
65
src/main/java/com/cisdi/data/XRFLEFT/test/StartTest.java
Normal file
@ -0,0 +1,65 @@
|
||||
package com.cisdi.data.XRFLEFT.test;
|
||||
|
||||
import com.cisdi.data.XRFRIGHT.impl.XRFRightChannelInitializer;
|
||||
import com.cisdi.data.XRFRIGHT.impl.XRFRightSessionFactory;
|
||||
import com.cisdi.data.sdk.enums.ByteOrder;
|
||||
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
|
||||
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
|
||||
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
|
||||
import com.cisdi.data.sdk.vo.GatewayVo;
|
||||
import io.netty.handler.ssl.OpenSsl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author cuianbing
|
||||
* @version 1.0
|
||||
* @description: TODO
|
||||
* @date 2021/7/7 19:28
|
||||
*/
|
||||
@Slf4j
|
||||
public class StartTest {
|
||||
|
||||
private static TcpIoService ioService = null;
|
||||
|
||||
private static SessionFactory sessionFactory = null;
|
||||
|
||||
public static void main(String[] args) {
|
||||
boolean available = OpenSsl.isAvailable();
|
||||
log.info("openssl available={}", available);
|
||||
|
||||
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
|
||||
|
||||
SessionFactory factory = new XRFRightSessionFactory(null);
|
||||
|
||||
ServiceProviderTest testServiceProvider = new ServiceProviderTest();
|
||||
|
||||
factory.init(testServiceProvider, null);
|
||||
|
||||
XRFRightChannelInitializer channelInitializer =
|
||||
new XRFRightChannelInitializer(factory, ByteOrder.BIGENDIAN, null);
|
||||
|
||||
GatewayVo instanceVo = new GatewayVo();
|
||||
instanceVo.setByteOrder(ByteOrder.BIGENDIAN);
|
||||
instanceVo.setParameter("{\"listenIp\":\"0.0.0.0\",\"listenPort\":8888,\"threadSize\":50,\"timeout\":2000}");
|
||||
|
||||
defaultIoService.init(instanceVo, factory, channelInitializer);
|
||||
|
||||
ioService = defaultIoService;
|
||||
sessionFactory = factory;
|
||||
|
||||
boolean open = ioService.open();
|
||||
|
||||
if (open == true) {
|
||||
log.info("plc网关启动成功");
|
||||
} else {
|
||||
log.info("plc网关启动失败");
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(10000000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user