From c6aa16c782fb09c153d464251418db4ae62d06ab Mon Sep 17 00:00:00 2001 From: htjcAdmin Date: Fri, 1 Aug 2025 09:51:42 +0800 Subject: [PATCH] =?UTF-8?q?/*=E4=B8=8A=E7=BA=A7=E7=B3=BB=E7=BB=9F=E6=A8=A1?= =?UTF-8?q?=E6=8B=9F=E5=99=A8=E4=BB=A3=E7=A0=81=E5=88=9D=E6=AC=A1=E6=8F=90?= =?UTF-8?q?=E4=BA=A4*/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 37 ++ Dockerfile | 29 + README.md | 4 + mvnw | 310 ++++++++++ mvnw.cmd | 182 ++++++ pom.xml | 180 ++++++ proguard.cfg | 65 ++ .../upstream/InspectUpstreamApplication.java | 31 + .../cofiguration/DeviceServerProperties.java | 29 + .../UpSystemServerProperties.java | 23 + .../upstream/cofiguration/WebConfig.java | 95 +++ .../inspect/upstream/constant/Constant.java | 24 + .../upstream/controller/ClientController.java | 59 ++ .../controller/DeviceServerController.java | 56 ++ .../inspect/upstream/domain/AjaxResult.java | 84 +++ .../inspect/upstream/domain/HttpStatus.java | 83 +++ .../com/inspect/upstream/domain/Result.java | 34 + .../com/inspect/upstream/tcp/BaseControl.java | 559 +++++++++++++++++ .../com/inspect/upstream/tcp/BinaryModel.java | 13 + .../com/inspect/upstream/tcp/ByteUtils.java | 258 ++++++++ .../inspect/upstream/tcp/ChannelCache.java | 65 ++ .../com/inspect/upstream/tcp/CommonUtils.java | 13 + .../inspect/upstream/tcp/DownXml2Json.java | 283 +++++++++ .../com/inspect/upstream/tcp/MyDecoder.java | 80 +++ .../com/inspect/upstream/tcp/SystemType.java | 82 +++ .../com/inspect/upstream/tcp/UpJson2Xml.java | 267 ++++++++ .../upstream/tcp/UpstreamMockNettyServer.java | 584 ++++++++++++++++++ .../tcp/UpstreamMockNettyServerHandler.java | 92 +++ .../upstream/tcp/UpstreamServerStart.java | 22 + .../java/com/inspect/upstream/util/Color.java | 11 + .../util/FastJson2JsonRedisSerializer.java | 58 ++ .../com/inspect/upstream/util/HexUtils.java | 16 + .../com/inspect/upstream/util/ProtoDef.java | 86 +++ .../util/SpringApplicationContext.java | 46 ++ src/main/resources/application-dev.yml | 41 ++ src/main/resources/application-prod.yml | 42 ++ src/main/resources/application-test.yml | 42 ++ src/main/resources/application.yml | 42 ++ src/main/resources/logback.xml | 79 +++ .../InspectUpstreamApplicationTests.java | 13 + 40 files changed, 4119 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 mvnw create mode 100644 mvnw.cmd create mode 100644 pom.xml create mode 100644 proguard.cfg create mode 100644 src/main/java/com/inspect/upstream/InspectUpstreamApplication.java create mode 100644 src/main/java/com/inspect/upstream/cofiguration/DeviceServerProperties.java create mode 100644 src/main/java/com/inspect/upstream/cofiguration/UpSystemServerProperties.java create mode 100644 src/main/java/com/inspect/upstream/cofiguration/WebConfig.java create mode 100644 src/main/java/com/inspect/upstream/constant/Constant.java create mode 100644 src/main/java/com/inspect/upstream/controller/ClientController.java create mode 100644 src/main/java/com/inspect/upstream/controller/DeviceServerController.java create mode 100644 src/main/java/com/inspect/upstream/domain/AjaxResult.java create mode 100644 src/main/java/com/inspect/upstream/domain/HttpStatus.java create mode 100644 src/main/java/com/inspect/upstream/domain/Result.java create mode 100644 src/main/java/com/inspect/upstream/tcp/BaseControl.java create mode 100644 src/main/java/com/inspect/upstream/tcp/BinaryModel.java create mode 100644 src/main/java/com/inspect/upstream/tcp/ByteUtils.java create mode 100644 src/main/java/com/inspect/upstream/tcp/ChannelCache.java create mode 100644 src/main/java/com/inspect/upstream/tcp/CommonUtils.java create mode 100644 src/main/java/com/inspect/upstream/tcp/DownXml2Json.java create mode 100644 src/main/java/com/inspect/upstream/tcp/MyDecoder.java create mode 100644 src/main/java/com/inspect/upstream/tcp/SystemType.java create mode 100644 src/main/java/com/inspect/upstream/tcp/UpJson2Xml.java create mode 100644 src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServer.java create mode 100644 src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServerHandler.java create mode 100644 src/main/java/com/inspect/upstream/tcp/UpstreamServerStart.java create mode 100644 src/main/java/com/inspect/upstream/util/Color.java create mode 100644 src/main/java/com/inspect/upstream/util/FastJson2JsonRedisSerializer.java create mode 100644 src/main/java/com/inspect/upstream/util/HexUtils.java create mode 100644 src/main/java/com/inspect/upstream/util/ProtoDef.java create mode 100644 src/main/java/com/inspect/upstream/util/SpringApplicationContext.java create mode 100644 src/main/resources/application-dev.yml create mode 100644 src/main/resources/application-prod.yml create mode 100644 src/main/resources/application-test.yml create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/logback.xml create mode 100644 src/test/java/com/inspect/upstream/InspectUpstreamApplicationTests.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0695458 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ +/upstream.log +/.mvn/ +/upstream.2022-04-21.log +/log/ +/logs/ +/logs/inspect-upstream/info.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6bd1c40 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,29 @@ +FROM openjdk:8 + +MAINTAINER zk <546285615@qq.com> + + +# Set environment variables. +ENV HOME /work +ENV JAVA_OPTS "-Xms512m -Xmx512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200" + +ADD ./target/upstream-0.0.1-SNAPSHOT.jar /work/upstream.jar + +ENV DEFAULT_OPTS "" +ENV OTHER_OPTS "" + +# 开放端口 +EXPOSE 22508 + +#设置时区 +RUN echo "Asia/Shanghai" > /etc/timezone; + +# 配置容器启动后执行的命令 +ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -jar /work/upstream.jar $DEFAULT_OPTS $OTHER_OPTS" ] + +# Define working directory. +WORKDIR /work + + +# Define default command. +CMD ["bash"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..1218f52 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ + +电力500协议中转站 + + diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..a16b543 --- /dev/null +++ b/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + 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 + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..c8d4337 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. 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, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d8f7928 --- /dev/null +++ b/pom.xml @@ -0,0 +1,180 @@ + + + 4.0.0 + com.inspect + inspect-upstream + 1.0.0 + inspect-upstream + inspect-upstream + + + 1.8 + UTF-8 + UTF-8 + 2.3.7.RELEASE + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + com.thoughtworks.xstream + xstream + 1.4.21 + + + com.alibaba + fastjson + 1.2.73 + + + dom4j + dom4j + 1.6.1 + + + io.netty + netty-all + 4.1.77.Final + + + net.sf.kxml + kxml2 + 2.3.0 + + + xmlpull + xmlpull + 1.1.3.4d_b4_min + + + org.apache.commons + commons-lang3 + + + org.springframework.boot + spring-boot-starter-amqp + + + biz.paluch.logging + logstash-gelf + 1.13.0 + + + + commons-codec + commons-codec + 1.15 + + + + javolution + javolution + 5.5.1 + + + + org.projectlombok + lombok + 1.18.24 + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + ${project.artifactId} + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + UTF-8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.3.7.RELEASE + + com.inspect.upstream.InspectUpstreamApplication + + + + repackage + + repackage + + + + + + + + diff --git a/proguard.cfg b/proguard.cfg new file mode 100644 index 0000000..b4545d7 --- /dev/null +++ b/proguard.cfg @@ -0,0 +1,65 @@ +-target 1.8 ##Specify the java version number +-dontshrink ##Default is enabled, here the shrink is turned off, that is, the unused classes/members are not deleted. +-dontoptimize ##Default is enabled, here to turn off bytecode level optimization +-useuniqueclassmembernames ## Take a unique strategy for confusing the naming of class members +-adaptclassstrings ## After confusing the class name, replace it with a place like Class.forName('className') +-dontnote +-ignorewarnings ## warnings are ignored +-dontwarn +-keep public class * extends org.springframework.boot.web.support.SpringBootServletInitializer +-keepdirectories ## Keep the package structure +-keepclasseswithmembers public class * { public static void main(java.lang.String[]);} ##Maintain the class of the main method and its method name +-keepclassmembers enum * { *; } ##Reserving enumeration members and methods +-keepclassmembers class * { + @org.springframework.beans.factory.annotation.Autowired *; + @org.springframework.beans.factory.annotation.Qualifier *; + @org.springframework.beans.factory.annotation.Value *; + @org.springframework.beans.factory.annotation.Required *; + @org.springframework.context.annotation.Bean *; + @org.springframework.context.annotation.Primary *; + @org.springframework.boot.context.properties.ConfigurationProperties *; + @org.springframework.boot.context.properties.EnableConfigurationProperties *; + @javax.inject.Inject *; + @javax.annotation.PostConstruct *; + @javax.annotation.PreDestroy *; +} +-keep @org.springframework.cache.annotation.EnableCaching class * +-keep @org.springframework.context.annotation.Configuration class * +-keep @org.springframework.boot.context.properties.ConfigurationProperties class * +-keep @org.springframework.boot.autoconfigure.SpringBootApplication class * +-allowaccessmodification +-keepattributes *Annotation* +-keepdirectories com.jayk.springboot.proguard.obfuscationdemo +-keepdirectories org.springframework.boot.autoconfigure +## Do not change names of the getters and setter, if you remove this ##thymeleaf unable to find the getter and setter i.e: ##${greetingDTO.message} +-keepclassmembers class * { + *** get*(); + void set*(***); +} +-keepclassmembernames class * { + java.lang.Class class$(java.lang.String); + java.lang.Class class$(java.lang.String, boolean); +} +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); + public static ** fromValue(java.lang.String); +} +-keepnames class * implements java.io.Serializable +-keepclassmembernames public class com.test.blah.config.liquibase.AsyncSpringLiquibase +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; + !static !transient ; + !private ; + !private ; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); +} +-keepclassmembers class * { + @org.springframework.beans.factory.annotation.Autowired ; + @org.springframework.beans.factory.annotation.Autowired ; + @org.springframework.security.access.prepost.PreAuthorize ; +} \ No newline at end of file diff --git a/src/main/java/com/inspect/upstream/InspectUpstreamApplication.java b/src/main/java/com/inspect/upstream/InspectUpstreamApplication.java new file mode 100644 index 0000000..509d987 --- /dev/null +++ b/src/main/java/com/inspect/upstream/InspectUpstreamApplication.java @@ -0,0 +1,31 @@ +package com.inspect.upstream; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.scheduling.annotation.EnableAsync; + +@Slf4j +@SpringBootApplication +@EnableAsync +public class InspectUpstreamApplication { + public static class CustomGenerator implements BeanNameGenerator { + + @Override + public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { + return definition.getBeanClassName(); + } + } + + public static void main(String[] args) { + new SpringApplicationBuilder(InspectUpstreamApplication.class) + .beanNameGenerator(new CustomGenerator()) + .run(args); + + log.info("\n<=====☆ UPSTREAM MODULE ☆ =====> \n .-------. ____ __ \n | _ _ \\ \\ \\ / / \n | ( ' ) | \\ _. / ' \n |(_ o _) / _( )_ .' \n | (_,_).' __ ___(_ o _)' \n | |\\ \\ | || |(_,_)' \n | | \\ `' /| `-' / \n | | \\ / \\ / \n ''-' `'-' `-..-' "); + } + +} diff --git a/src/main/java/com/inspect/upstream/cofiguration/DeviceServerProperties.java b/src/main/java/com/inspect/upstream/cofiguration/DeviceServerProperties.java new file mode 100644 index 0000000..89598bd --- /dev/null +++ b/src/main/java/com/inspect/upstream/cofiguration/DeviceServerProperties.java @@ -0,0 +1,29 @@ +package com.inspect.upstream.cofiguration; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +@PropertySource("classpath:application.yml") +@Component +public class DeviceServerProperties { + + @Value("${deviceServer.serverIp}") + public String ip; + + @Value("${deviceServer.serverPort}") + public Integer port; + + @Value("${deviceServer.deviceServerCode}") + public String deviceServerCode; + + @Value("${deviceServer.deviceCode}") + public String deviceCode; + + @Value("${deviceServer.robotCode}") + public String robotCode; + + @Value("${deviceServer.nestCode}") + public String nestCode; + +} diff --git a/src/main/java/com/inspect/upstream/cofiguration/UpSystemServerProperties.java b/src/main/java/com/inspect/upstream/cofiguration/UpSystemServerProperties.java new file mode 100644 index 0000000..993e29e --- /dev/null +++ b/src/main/java/com/inspect/upstream/cofiguration/UpSystemServerProperties.java @@ -0,0 +1,23 @@ +package com.inspect.upstream.cofiguration; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +@PropertySource("classpath:application.yml") +@Component +public class UpSystemServerProperties { + + @Value("${upSystemServer.serverIp}") + public String ip; + + @Value("${upSystemServer.serverPort}") + public Integer port; + + @Value("${upSystemServer.upCode}") + public String upCode; + + @Value("${upSystemServer.iipCode}") + public String iipCode; + +} diff --git a/src/main/java/com/inspect/upstream/cofiguration/WebConfig.java b/src/main/java/com/inspect/upstream/cofiguration/WebConfig.java new file mode 100644 index 0000000..3f8b402 --- /dev/null +++ b/src/main/java/com/inspect/upstream/cofiguration/WebConfig.java @@ -0,0 +1,95 @@ +package com.inspect.upstream.cofiguration; + +import com.inspect.upstream.constant.Constant; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import com.inspect.upstream.util.FastJson2JsonRedisSerializer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.*; +import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.web.client.RestTemplate; + +import java.nio.charset.StandardCharsets; + +@Slf4j +@Configuration +public class WebConfig { + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory factory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(factory); + + FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); + + ObjectMapper mapper = new ObjectMapper(); + mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); + serializer.setObjectMapper(mapper); + + // 使用StringRedisSerializer来序列化和反序列化redis的key值 + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(serializer); + + // Hash的key也采用StringRedisSerializer的序列化方式 + template.setHashKeySerializer(new StringRedisSerializer()); + template.setHashValueSerializer(serializer); + + template.afterPropertiesSet(); + + return template; + } + + @Bean + public RabbitTemplate rabbitTemplate(CachingConnectionFactory connectionFactory) { + return new RabbitTemplate(connectionFactory); + } + + + /** + * 申明交换机 + */ + @Bean(Constant.EX_CHANGE_NAME) + public Exchange directExchange() { + // 申明路由交换机,durable:在rabbitmq重启后,交换机还在 + return ExchangeBuilder.directExchange(Constant.EX_CHANGE_NAME).durable(true).build(); + } + + /** + * 申明Blog队列 + * + * @return + */ + @Bean(Constant.QUEUE_NAME) + public Queue deviceQueue() { + return new Queue(Constant.QUEUE_NAME, true); + } + + + /** + * 绑定交换机-路由键 + * + * @return + */ + @Bean + public Binding bindRouting(Queue deviceQueue, Exchange directExchange) { + return BindingBuilder.bind(deviceQueue).to(directExchange).with(Constant.ROUTING_KEY_NAME).noargs(); + } + + @Bean + public RestTemplate restTemplate() { + RestTemplate restTemplate = new RestTemplate(); + restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); + return restTemplate; + } +} diff --git a/src/main/java/com/inspect/upstream/constant/Constant.java b/src/main/java/com/inspect/upstream/constant/Constant.java new file mode 100644 index 0000000..b11d21e --- /dev/null +++ b/src/main/java/com/inspect/upstream/constant/Constant.java @@ -0,0 +1,24 @@ +package com.inspect.upstream.constant; + +public class Constant { + + /** + * 设备上报的mq routing key 路由键 + */ + public static final String ROUTING_KEY_NAME = "springboot.montdata"; + + /** + * 设备上报的交换机名 + */ + public static final String EX_CHANGE_NAME = "exchange-montdata"; + + /** + * 设备上报的队列 + */ + public static final String QUEUE_NAME = "queue-montdata"; + + /** + * 和基础数据定义的预置点转发type 类型 + */ + public static final String MODEL_UP_TYPE = "modelup-1024"; +} diff --git a/src/main/java/com/inspect/upstream/controller/ClientController.java b/src/main/java/com/inspect/upstream/controller/ClientController.java new file mode 100644 index 0000000..1c4637c --- /dev/null +++ b/src/main/java/com/inspect/upstream/controller/ClientController.java @@ -0,0 +1,59 @@ +package com.inspect.upstream.controller; + +import com.alibaba.fastjson.JSONObject; +import com.inspect.upstream.domain.AjaxResult; +import com.inspect.upstream.util.Color; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.MDC; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.UUID; + +@Slf4j +@RestController +@RequestMapping("/client") +public class ClientController { + + @GetMapping("gray") + public String gray() { + + String uuid = UUID.randomUUID().toString().replaceAll("-", ""); + MDC.put("traceId", uuid); + + log.info("这是一个来自springboot,logback的info级别的日志"); + log.warn("这是一条来自springboot,logback的warn级别的日志"); + log.warn("这是一条来自springboot,logback的warn级别的日志2"); + log.error("这是一条来自springboot,logback的error级别的日志", new Exception("系统错误")); + return "success"; + } + + /** + * 调用客户端发送消息 + */ + @PostMapping("sendMsg") + public AjaxResult sendMsg(String uuid, @RequestBody String msg) { + try { + if (StringUtils.isBlank(msg)) { + return AjaxResult.fail("500", "消息为空"); + } + + JSONObject jsonObject = JSONObject.parseObject(msg); + if (null == jsonObject) { + return AjaxResult.fail("500", "消息JSON解析失败"); + } + + msg = msg.replaceAll("sendCode", "SendCode"); + msg = msg.replaceAll("receiveCode", "ReceiveCode"); + msg = msg.replaceAll("type", "Type"); + //logger.info("###### 会话:{}, 巡视主机客户端接收到消息, 发送到上级 ######\n{}", uuid, msg); + //nettyClient.sendJsonMessage(uuid, msg); + return AjaxResult.success(); + } catch (Exception e) { + log.error(Color.RED + "###### 会话:{}, 客户端发送消息捕获异常:{} ######" + Color.END, uuid, e.getMessage()); + return AjaxResult.fail(500, "数据格式不正确"); + } + } + +} diff --git a/src/main/java/com/inspect/upstream/controller/DeviceServerController.java b/src/main/java/com/inspect/upstream/controller/DeviceServerController.java new file mode 100644 index 0000000..7cc5d67 --- /dev/null +++ b/src/main/java/com/inspect/upstream/controller/DeviceServerController.java @@ -0,0 +1,56 @@ +package com.inspect.upstream.controller; + +import com.alibaba.fastjson.JSONObject; +import com.inspect.upstream.domain.AjaxResult; +import com.inspect.upstream.cofiguration.DeviceServerProperties; +import com.inspect.upstream.tcp.UpstreamMockNettyServer; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Slf4j +@RestController +@RequestMapping("/deviceServer") +public class DeviceServerController { + + @Resource + UpstreamMockNettyServer server; + + @Resource + DeviceServerProperties deviceServerProperties; + + /** + * 下发命令到设备端 + */ + @PostMapping("/sendCommand") + public AjaxResult sendCommand(@RequestBody String json) { + + try { + log.info("设备接入层server-接口,接到命令:{}", json); + // 调用设备接入层,下发命令到设备 + JSONObject jsonObject = JSONObject.parseObject(json); + + String sendCode = jsonObject.getString("SendCode"); + + String receiveCode = jsonObject.getString("ReceiveCode"); + + if (StringUtils.isEmpty(sendCode) || StringUtils.isEmpty(receiveCode)) { + log.error("SendCoded或ReceiveCode为空"); + return AjaxResult.fail(500, "SendCoded或ReceiveCode为空"); + } else { + server.sendXmlMessage(jsonObject);// to device + return AjaxResult.success(); + } + + } catch (Exception e) { + log.error("设备接入服务,处理命令下发捕获异常", e); + return AjaxResult.fail(500); + } + } + +} diff --git a/src/main/java/com/inspect/upstream/domain/AjaxResult.java b/src/main/java/com/inspect/upstream/domain/AjaxResult.java new file mode 100644 index 0000000..69f8cb0 --- /dev/null +++ b/src/main/java/com/inspect/upstream/domain/AjaxResult.java @@ -0,0 +1,84 @@ +package com.inspect.upstream.domain; + +import java.util.HashMap; + +public class AjaxResult extends HashMap { + private static final long serialVersionUID = 1L; + + public static final String CODE_TAG = "code"; + + public static final String MSG_TAG = "msg"; + + public static final String DATA_TAG = "data"; + + public AjaxResult() { + } + + public AjaxResult(int code, String msg) { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + } + + public AjaxResult(int code, String msg, Object data) { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + if (null != data) { + super.put(DATA_TAG, data); + } + } + + @Override + public AjaxResult put(String key, Object value) { + super.put(key, value); + return this; + } + + public static AjaxResult success() { + return AjaxResult.success("操作成功"); + } + + public static AjaxResult success(Object data) { + return AjaxResult.success("操作成功", data); + } + + public static AjaxResult success(String msg) { + return AjaxResult.success(msg, null); + } + + public static AjaxResult success(String msg, Object data) { + return new AjaxResult(HttpStatus.SUCCESS, msg, data); + } + + public static AjaxResult error() { + return AjaxResult.error("操作失败"); + } + + public static AjaxResult error(String msg) { + return AjaxResult.error(msg, null); + } + + public static AjaxResult error(String msg, Object data) { + return new AjaxResult(HttpStatus.ERROR, msg, data); + } + + public static AjaxResult error(int code, String msg) { + return new AjaxResult(code, msg, null); + } + + public static AjaxResult fail(Integer code, String msg, Object data) { + return new AjaxResult(code, msg, data); + } + + public static AjaxResult fail(String msg, Object data) { + return new AjaxResult(HttpStatus.ERROR, msg, data); + } + + public static AjaxResult fail(Integer code, String msg) { + return new AjaxResult(code, msg, null); + } + + public static AjaxResult fail(Integer code) { + return new AjaxResult(code, null, null); + } + +} diff --git a/src/main/java/com/inspect/upstream/domain/HttpStatus.java b/src/main/java/com/inspect/upstream/domain/HttpStatus.java new file mode 100644 index 0000000..ff7716d --- /dev/null +++ b/src/main/java/com/inspect/upstream/domain/HttpStatus.java @@ -0,0 +1,83 @@ +package com.inspect.upstream.domain; + +public class HttpStatus { + /** + * 操作成功 + */ + public static final int SUCCESS = 200; + + /** + * 对象创建成功 + */ + public static final int CREATED = 201; + + /** + * 请求已经被接受 + */ + public static final int ACCEPTED = 202; + + /** + * 操作已经执行成功,但是没有返回数据 + */ + public static final int NO_CONTENT = 204; + + /** + * 资源已被移除 + */ + public static final int MOVED_PERM = 301; + + /** + * 重定向 + */ + public static final int SEE_OTHER = 303; + + /** + * 资源没有被修改 + */ + public static final int NOT_MODIFIED = 304; + + /** + * 参数列表错误(缺少,格式不匹配) + */ + public static final int BAD_REQUEST = 400; + + /** + * 未授权 + */ + public static final int UNAUTHORIZED = 401; + + /** + * 访问受限,授权过期 + */ + public static final int FORBIDDEN = 403; + + /** + * 资源,服务未找到 + */ + public static final int NOT_FOUND = 404; + + /** + * 不允许的http方法 + */ + public static final int BAD_METHOD = 405; + + /** + * 资源冲突,或者资源被锁 + */ + public static final int CONFLICT = 409; + + /** + * 不支持的数据,媒体类型 + */ + public static final int UNSUPPORTED_TYPE = 415; + + /** + * 系统内部错误 + */ + public static final int ERROR = 500; + + /** + * 接口未实现 + */ + public static final int NOT_IMPLEMENTED = 501; +} diff --git a/src/main/java/com/inspect/upstream/domain/Result.java b/src/main/java/com/inspect/upstream/domain/Result.java new file mode 100644 index 0000000..1105ce7 --- /dev/null +++ b/src/main/java/com/inspect/upstream/domain/Result.java @@ -0,0 +1,34 @@ +package com.inspect.upstream.domain; + +public class Result { + + private String code; + + private String msg; + + private String data; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/BaseControl.java b/src/main/java/com/inspect/upstream/tcp/BaseControl.java new file mode 100644 index 0000000..50e17f2 --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/BaseControl.java @@ -0,0 +1,559 @@ +package com.inspect.upstream.tcp; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +import java.util.List; + +public class BaseControl { + public String SendCode; + public String ReceiveCode; + public String Type; + public String Code; + public String Command; + public String Time; +} + +class ResponseControl extends BaseControl { + public String Items; +} + + +class RegisterResponseControl extends BaseControl { + public List Items; +} + +//注册响应消息 +@XStreamAlias("Item") +class RegisterResponseModel { + @XStreamAsAttribute + public String heart_beat_interval; //心跳间隔 + @XStreamAsAttribute + public String patroldevice_run_interval; //巡视设备运行数据间隔 + @XStreamAsAttribute + public String nest_run_interval; //无人机机巢运行数据间隔 + @XStreamAsAttribute + public String weather_interval; //微气象数据间隔 + @XStreamAsAttribute + public String env_interval; //环境数据间隔 +} + +class RobotControl extends BaseControl { + public List Items; +} + +//机器人、无人机控制 +@XStreamAlias("Item") +class RobotModel { + @XStreamAsAttribute + public String value; +} + +class TaskSendControl extends BaseControl { + public List Items; +} + +//任务下发 +@XStreamAlias("Item") +class TaskSendModel { + @XStreamAsAttribute + public String task_code; //任务编码 + @XStreamAsAttribute + public String task_name; //任务名称 + @XStreamAsAttribute + public String priority; //优先级 + @XStreamAsAttribute + public String device_level; //设备层级 + @XStreamAsAttribute + public String device_list; //设备列表 格式:多个ID,采用“,”分隔" + @XStreamAsAttribute + public String fixed_start_time; //定期开始时间 + @XStreamAsAttribute + public String cycle_month; //周期(月) + @XStreamAsAttribute + public String cycle_week; //周期(周) + @XStreamAsAttribute + public String cycle_execute_time; //周期(执行时间) + @XStreamAsAttribute + public String cycle_start_time; //周期开始时间 + @XStreamAsAttribute + public String cycle_end_time; //周期结束时间 + @XStreamAsAttribute + public String interval_number; //间隔(数量) + @XStreamAsAttribute + public String interval_type; //间隔(类型) + @XStreamAsAttribute + public String interval_execute_time; //间隔(执行时间) + @XStreamAsAttribute + public String interval_start_time; //间隔开始时间 + @XStreamAsAttribute + public String interval_end_time; //间隔结束时间 + @XStreamAsAttribute + public String invalid_start_time; //不可用开始时间 + @XStreamAsAttribute + public String invalid_end_time; //不可用结束时间 + @XStreamAsAttribute + public String isenable; //是否可用 + @XStreamAsAttribute + public String creator; //编制人 + @XStreamAsAttribute + public String create_time; //编制时间 + @XStreamAsAttribute + public String type; //类型 + +} + +class LinkageTaskControl extends BaseControl { + public List Items; +} + +//联动任务下发 +@XStreamAlias("Item") +class LinkageTaskModel { + @XStreamAsAttribute + public String task_code; //任务编码 + @XStreamAsAttribute + public String task_name; //任务名称 + @XStreamAsAttribute + public String priority; //优先级 + @XStreamAsAttribute + public String device_level; //设备层级 + @XStreamAsAttribute + public String device_list; //设备列表 格式:多个ID,采用“,”分隔" +} + + +class AreaControl extends BaseControl { + public List Items; +} + +//检修区域 +@XStreamAlias("Item") +class AreaModel { + @XStreamAsAttribute + public String config_code; //配置编码 检修区域配置编码 + @XStreamAsAttribute + public String enable; //是否有效 + @XStreamAsAttribute + public String start_time; //检修开始时间 + @XStreamAsAttribute + public String end_time; //检修结束时间 + @XStreamAsAttribute + public String device_level; //设备层级 + @XStreamAsAttribute + public String device_list; //检修设备列表 + @XStreamAsAttribute + public String coordinate_pixel; //检修区域坐标框 +} + +class ModelControl extends BaseControl { + public List Items; +} + +@XStreamAlias("Item") +class ModelPath { + @XStreamAsAttribute + public String device_file_path; + @XStreamAsAttribute + public String robot_file_path; + @XStreamAsAttribute + public String host_file_path; + @XStreamAsAttribute + public String video_file_path; + @XStreamAsAttribute + public String drone_file_path; + @XStreamAsAttribute + public String voice_file_path; + @XStreamAsAttribute + public String task_file_path; + @XStreamAsAttribute + public String overhaularea_file_path; + @XStreamAsAttribute + public String map_file_path; + @XStreamAsAttribute + public String total_num; + @XStreamAsAttribute + public String valid_num; + @XStreamAsAttribute + public String percent; + @XStreamAsAttribute + public String error_code; + @XStreamAsAttribute + public String task_patrolled_id; + +} + +//巡视结果统计查询 +class ResultControl extends BaseControl { + public List Items; +} + +@XStreamAlias("Item") +class Result { + @XStreamAsAttribute + public String begin_time; + @XStreamAsAttribute + public String end_time; +} + +class PatrolDeviceStateControl extends BaseControl { + public List Items; +} + +//巡视设备状态数据 +@XStreamAlias("Item") +class PatrolDeviceStateModel { + @XStreamAsAttribute + public String patroldevice_name;//巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code;//巡视设备编码 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + +class PatrolDeviceRunningControl extends BaseControl { + public List Items; +} + +//巡视设备运行数据 +@XStreamAlias("Item") +class PatrolDeviceRunningModel { + @XStreamAsAttribute + public String patroldevice_name;//巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code;//巡视设备编码 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + + +class NestStateControl extends BaseControl { + public List Items; +} + +//无人机机巢状态数据 +@XStreamAlias("Item") +class NestStateModel { + @XStreamAsAttribute + public String nest_name; //机巢名称 + @XStreamAsAttribute + public String nest_code; //机巢编码 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + + +class NestRunningControl extends BaseControl { + public List Items; +} + +//无人机机巢运行数据 +@XStreamAlias("Item") +class NestRunningModel { + @XStreamAsAttribute + public String nest_name; //机巢名称 + @XStreamAsAttribute + public String nest_code; //机巢编码 + @XStreamAsAttribute + public String module_no; //模块序号 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + +class RouteControl extends BaseControl { + public List Items; +} + +class LocationControl extends BaseControl { + public List Items; +} + +//巡视设备坐标 +@XStreamAlias("Item") +class LocationModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String coordinate_pixel; //坐标 + @XStreamAsAttribute + public String coordinate_geography; //经纬度 +} + + +class AlarmControl extends BaseControl { + public List Items; +} + +//巡视设备异常告警数据 +@XStreamAlias("Item") +class AlarmModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String content; //告警描述 +} + + +class EnvironmentControl extends BaseControl { + public List Items; +} + +//环境数据 +@XStreamAlias("Item") +class EnvironmentModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + + +class TaskStateControl extends BaseControl { + public List Items; +} + +//任务状态数据 +@XStreamAlias("Item") +class TaskStateModel { + @XStreamAsAttribute + public String task_patrolled_id; //巡视任务执行ID + @XStreamAsAttribute + public String task_name; //任务名称 + @XStreamAsAttribute + public String task_code; //任务编码 + @XStreamAsAttribute + public String task_state; //任务状态 + @XStreamAsAttribute + public String plan_start_time; //计划开始时间 + @XStreamAsAttribute + public String start_time; //开始时间 + @XStreamAsAttribute + public String task_progress; //任务进度 + @XStreamAsAttribute + public String task_estimated_time; //任务预计剩余时间 + @XStreamAsAttribute + public String description; //描述 +} + + +class TaskResultControl extends BaseControl { + public List Items; +} + +//巡视结果 +@XStreamAlias("Item") +class TaskResultModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String task_name; //任务名称 + @XStreamAsAttribute + public String task_code; //任务编码 + @XStreamAsAttribute + public String device_name; //设备点位名称 + @XStreamAsAttribute + public String device_id; //设备点位ID + @XStreamAsAttribute + public String value_type; //值类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String recognition_type; //识别类型 + @XStreamAsAttribute + public String file_type; //采集文件类型 + @XStreamAsAttribute + public String file_path; //文件名称 + @XStreamAsAttribute + public String rectangle; //图像框 + @XStreamAsAttribute + public String task_patrolled_id; //巡视任务执行ID + @XStreamAsAttribute + public String valid; //结论 + @XStreamAsAttribute + public String data_type; //巡视结果数据来源 0x01摄像机,0x02机器人,0x03无人机,0x04声纹,0x05在线监测 + @XStreamAsAttribute + public String material_id; //实物ID +} + +class AnalysisControl extends BaseControl { + public List Items; +} + +//静默监视告警数据 +@XStreamAlias("Item") +class AnalysisModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String task_name; //任务名称 + @XStreamAsAttribute + public String task_code; //任务编码 + @XStreamAsAttribute + public String device_name; //设备点位名称 + @XStreamAsAttribute + public String device_id; //设备点位ID + @XStreamAsAttribute + public String alarm_level; //告警等级 + @XStreamAsAttribute + public String alarm_type; //告警类型 + @XStreamAsAttribute + public String recognition_type; //识别类型 + @XStreamAsAttribute + public String file_type; //告警文件类型 + @XStreamAsAttribute + public String task_patrolled_id; //巡视任务执行ID + @XStreamAsAttribute + public String file_path; //文件路径 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String content; //告警描述 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + + +class MonitorControl extends BaseControl { + public List Items; +} + +//静默监视告警数据 +@XStreamAlias("Item") +class MonitorModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String alarm_level; //告警等级 + @XStreamAsAttribute + public String monitor_type; //静默监视类型 + @XStreamAsAttribute + public String file_type; //告警文件类型 + @XStreamAsAttribute + public String content; //告警描述 + @XStreamAsAttribute + public String file_path; //文件名称 + @XStreamAsAttribute + public String time; //时间 +} + +class TotalControl extends BaseControl { + public List Items; +} + +//巡视结果统计 +@XStreamAlias("Item") +class TotalModel { + @XStreamAsAttribute + public String total_num; //满足查询条件总数 + @XStreamAsAttribute + public String valid_num; //查询有效数据 + @XStreamAsAttribute + public String percent; //统计百分比,有效值 保留小数点后3位 +} + + +class ReportControl extends BaseControl { + public List Items; +} + +//巡视设备统计信息上报 +@XStreamAlias("Item") +class ReportModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String commission_time; //投运时间 + @XStreamAsAttribute + public String report_time; //上报时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + +class UpdateModelControl extends BaseControl { + public List Items; +} + +//模型更新上报指令 +@XStreamAlias("Item") +class UpdateModel { + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String file_path; //路径 +} \ No newline at end of file diff --git a/src/main/java/com/inspect/upstream/tcp/BinaryModel.java b/src/main/java/com/inspect/upstream/tcp/BinaryModel.java new file mode 100644 index 0000000..24ee06a --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/BinaryModel.java @@ -0,0 +1,13 @@ +package com.inspect.upstream.tcp; + +import io.netty.buffer.ByteBuf; + +public class BinaryModel { + public long sendIndex; + public long receiveIndex; + public byte sourceFlag; + public int dataLength; + public ByteBuf dataBuf; + public String id; + public String uuid; +} diff --git a/src/main/java/com/inspect/upstream/tcp/ByteUtils.java b/src/main/java/com/inspect/upstream/tcp/ByteUtils.java new file mode 100644 index 0000000..709a05d --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/ByteUtils.java @@ -0,0 +1,258 @@ +package com.inspect.upstream.tcp; + +import java.io.*; +import java.nio.charset.Charset; +import java.util.Arrays; + +public class ByteUtils { + private static final byte[] BUILD_BYTE_TABLE = new byte[]{(byte) 128, (byte) 64, (byte) 32, (byte) 16, (byte) 8, (byte) 4, (byte) 2, (byte) 1}; + + private ByteUtils() { + } + + public static String byte2Hex(byte[] bytes) { + StringBuffer stringBuffer = new StringBuffer(); + String temp = null; + for (int i = 0; i < bytes.length; i++) { + temp = Integer.toHexString(bytes[i] & 0xFF); + if (temp.length() == 1) { + //1得到一位的进行补0操作 + stringBuffer.append("0"); + } + stringBuffer.append(temp); + } + return stringBuffer.toString(); + } + + public static byte[] shortToByte(short number) { + byte[] b = new byte[2]; + for (int i = 1; i >= 0; i--) { + b[i] = (byte) (number % 256); + number >>= 8; + } + return b; + } + + public static short byteToShort(byte[] b) { + return (short) ((((b[0] & 0xff) << 8) | b[1] & 0xff)); + } + + public static byte[] intToByte(int number) { + byte[] b = new byte[4]; + for (int i = 3; i >= 0; i--) { + b[i] = (byte) (number % 256); + number >>= 8; + } + return b; + } + + public static int byteToInt(byte[] b) { + return ((((b[0] & 0xff) << 24) | ((b[1] & 0xff) << 16) | ((b[2] & 0xff) << 8) | (b[3] & 0xff))); + } + + public static byte[] longToByte(long number) { + byte[] b = new byte[8]; + for (int i = 7; i >= 0; i--) { + b[i] = (byte) (number % 256); + number >>= 8; + } + return b; + } + + public static long byteToLong(byte[] b) { + return ((((long) b[0] & 0xff) << 56) | (((long) b[1] & 0xff) << 48) | (((long) b[2] & 0xff) << 40) | (((long) b[3] & 0xff) << 32) | (((long) b[4] & 0xff) << 24) + | (((long) b[5] & 0xff) << 16) | (((long) b[6] & 0xff) << 8) | ((long) b[7] & 0xff)); + } + + public static byte[] doubleToByte(double d) { + byte[] bytes = new byte[8]; + long l = Double.doubleToLongBits(d); + for (int i = 0; i < bytes.length; i++) { + bytes[i] = Long.valueOf(l).byteValue(); + l = l >> 8; + } + return bytes; + } + + public static double byteToDouble(byte[] b) { + long l; + l = b[0]; + l &= 0xff; + l |= ((long) b[1] << 8); + l &= 0xffff; + l |= ((long) b[2] << 16); + l &= 0xffffff; + l |= ((long) b[3] << 24); + l &= 0xffffffffl; + l |= ((long) b[4] << 32); + l &= 0xffffffffffl; + + l |= ((long) b[5] << 40); + l &= 0xffffffffffffl; + l |= ((long) b[6] << 48); + l &= 0xffffffffffffffl; + + l |= ((long) b[7] << 56); + + return Double.longBitsToDouble(l); + } + + public static byte[] floatToByte(float d) { + byte[] bytes = new byte[4]; + int l = Float.floatToIntBits(d); + for (int i = 0; i < bytes.length; i++) { + bytes[i] = Integer.valueOf(l).byteValue(); + l = l >> 8; + } + return bytes; + } + + public static float byteToFloat(byte[] b) { + int l; + l = b[0]; + l &= 0xff; + l |= ((long) b[1] << 8); + l &= 0xffff; + l |= ((long) b[2] << 16); + l &= 0xffffff; + l |= ((long) b[3] << 24); + l &= 0xffffffffl; + + return Float.intBitsToFloat(l); + } + + public static byte[] stringToByte(String s, Charset charset) { + return s.getBytes(charset); + } + + public static String byteToString(byte[] b, Charset charset) { + return new String(b, charset); + } + + public static byte[] objectToByte(Object obj) throws IOException { + ByteArrayOutputStream buff = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(buff); + out.writeObject(obj); + try { + return buff.toByteArray(); + } finally { + out.close(); + } + } + + public static Object byteToObject(byte[] b) throws IOException, ClassNotFoundException { + ByteArrayInputStream buff = new ByteArrayInputStream(b); + ObjectInputStream in = new ObjectInputStream(buff); + Object obj = in.readObject(); + try { + return obj; + } finally { + in.close(); + } + } + + public static boolean equalsBit(byte a, byte b) { + return Arrays.equals(byteToBitArray(a), byteToBitArray(b)); + } + + public static boolean equalsBit(byte[] a, byte[] b) { + if (a == b) { + return true; + } + if (a == null || b == null) { + return false; + } + + int length = a.length; + if (b.length != length) { + return false; + } + + for (int count = 0; count < a.length; count++) { + if (!equalsBit(a[count], b[count])) { + return false; + } + } + return true; + } + + public static String bitString(byte b) { + StringBuilder buff = new StringBuilder(); + boolean[] array = byteToBitArray(b); + for (int i = 0; i < array.length; i++) { + buff.append(array[i] ? 1 : 0); + } + return buff.toString(); + } + + public static boolean[] byteToBitArray(byte b) { + boolean[] buff = new boolean[8]; + int index = 0; + for (int i = 7; i >= 0; i--) { + buff[index++] = ((b >>> i) & 1) == 1; + } + return buff; + } + + public static boolean byteBitValue(byte b, int index) { + return byteToBitArray(b)[index]; + } + + public static byte buildNewByte(boolean[] values) { + byte b = 0; + for (int i = 0; i < 8; i++) { + if (values[i]) { + b |= BUILD_BYTE_TABLE[i]; + } + } + return b; + } + + public static byte changeByteBitValue(byte b, int index, boolean newValue) { + boolean[] bitValues = byteToBitArray(b); + bitValues[index] = newValue; + return buildNewByte(bitValues); + } + + public static byte[] ipAddressBytes(String address) { + if (address == null || address.length() < 0 || address.length() > 15) { + throw new IllegalArgumentException("Invalid IP address."); + } + + final int ipSize = 4;// 最大IP位数 + final char ipSpace = '.';// IP数字的分隔符 + int[] ipNums = new int[ipSize]; + StringBuilder number = new StringBuilder();// 当前操作的数字 + StringBuilder buff = new StringBuilder(address); + int point = 0;// 当前操作的数字下标,最大到3. + char currentChar; + for (int i = 0; i < buff.length(); i++) { + currentChar = buff.charAt(i); + if (ipSpace == currentChar) { + // 当前位置等于最大于序号后,还有字符没有处理表示这是一个错误的IP. + if (point == ipSize - 1 && buff.length() - (i + 1) > 0) { + throw new IllegalArgumentException("Invalid IP address."); + } + ipNums[point++] = Integer.parseInt(number.toString()); + number.delete(0, number.length()); + } else { + number.append(currentChar); + } + } + ipNums[point] = Integer.parseInt(number.toString()); + + byte[] ipBuff = new byte[ipSize]; + int pointNum = 0; + for (int i = 0; i < 4; i++) { + pointNum = Math.abs(ipNums[i]); + if (pointNum > 255) { + throw new IllegalArgumentException("Invalid IP address."); + } + ipBuff[i] = (byte) (pointNum & 0xff); + } + + return ipBuff; + } +} + + diff --git a/src/main/java/com/inspect/upstream/tcp/ChannelCache.java b/src/main/java/com/inspect/upstream/tcp/ChannelCache.java new file mode 100644 index 0000000..4a53b2f --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/ChannelCache.java @@ -0,0 +1,65 @@ +package com.inspect.upstream.tcp; + +import io.netty.channel.ChannelHandlerContext; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class ChannelCache { + private static final Map channelPool = new ConcurrentHashMap<>(); + + public int size() { + return channelPool.size(); + } + + public static ChannelCache getInstance() { + return ChannelCacheHolder.instance; + } + + public static class ChannelCacheHolder { + public static ChannelCache instance = new ChannelCache(); + } + + public ChannelHandlerContext get(String handle) { + return channelPool.get(handle); + } + + public void add(String handle, ChannelHandlerContext ctx) { + channelPool.put(handle, ctx); + } + + public String addIfAbsent(String devId, ChannelHandlerContext ctx) { + for (Map.Entry entry : channelPool.entrySet()) { + if (entry.getValue() == ctx) { + String key = (String) entry.getKey(); + return devId.equals(key) ? null : key; + } + } + channelPool.put(devId, ctx); + return null; + } + + public void remove(ChannelHandlerContext ctx) { + for (Map.Entry entry : channelPool.entrySet()) { + if (entry.getValue() == ctx) { + channelPool.remove(entry.getKey()); + break; + } + } + } + + public void replace(String newKey, ChannelHandlerContext ctx) { + for (Map.Entry entry : channelPool.entrySet()) { + if (entry.getValue() == ctx) { + channelPool.remove(entry.getKey()); + channelPool.put(newKey, ctx); + break; + } + } + } + + public Set getClients() { + return channelPool.keySet(); + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/CommonUtils.java b/src/main/java/com/inspect/upstream/tcp/CommonUtils.java new file mode 100644 index 0000000..6d5b0df --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/CommonUtils.java @@ -0,0 +1,13 @@ +package com.inspect.upstream.tcp; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class CommonUtils { + public static String GetNowDateString() { + Date date = new Date(); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return formatter.format(date); + } + +} diff --git a/src/main/java/com/inspect/upstream/tcp/DownXml2Json.java b/src/main/java/com/inspect/upstream/tcp/DownXml2Json.java new file mode 100644 index 0000000..aeb9f93 --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/DownXml2Json.java @@ -0,0 +1,283 @@ +package com.inspect.upstream.tcp; + +import com.alibaba.fastjson.JSON; +import com.inspect.upstream.util.Color; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.naming.NoNameCoder; +import com.thoughtworks.xstream.io.xml.Xpp3Driver; +import com.thoughtworks.xstream.security.AnyTypePermission; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class DownXml2Json { + + /** + * 默认为对上级的客户端的别名 + */ + private String alias; + + private String deviceAlias = "PatrolDevice"; + + private XStream getXmlStreamInstance() { + return new XStream(new Xpp3Driver(new NoNameCoder())); + } + + public DownXml2Json(String alias) { + this.alias = alias; + } + + public String DownStreamJson2Xml(String uuid, String id, String xml, Class clazz) { + try { + XStream xStream = getXmlStreamInstance(); + xStream.alias(alias, clazz); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + T obj = (T) xStream.fromXML(xml); + return JSON.toJSONString(obj); + } catch (com.thoughtworks.xstream.XStreamException e) { + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(deviceAlias, clazz); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + T obj = (T) xStream.fromXML(xml); + return JSON.toJSONString(obj); + } catch (com.thoughtworks.xstream.XStreamException ex) { + log.error(Color.RED + "###### 客户:{}, DownStreamJson2Xml解析失败:{} ######" + Color.END, id, e.getMessage()); + return null; + } + } + } + + //任务下发 + public String TaskSendControlXml2Json(String xml) { + XStream xStream = getXmlStreamInstance(); + xStream.alias(alias, TaskSendControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + TaskSendControl obj = (TaskSendControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //联动任务下发 + public String LinkageTaskControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, LinkageTaskControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + LinkageTaskControl obj = (LinkageTaskControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //检修去下发 + public String AreaControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, AreaControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + AreaControl obj = (AreaControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //机器人控制下发 + public String RobotControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, RobotControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + RobotControl obj = (RobotControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //无人机控制下发 + public String UavControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, RobotControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + RobotControl obj = (RobotControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //任务控制和同步指令 + public String BaseControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, BaseControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + BaseControl obj = (BaseControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //上级查询巡视结果指令 + public String ResultControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, ResultControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + ResultControl obj = (ResultControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //模型同步同步指令 + public String ModelControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, ModelControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + BaseControl obj = (BaseControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //巡检设备状态数据 + public String PatrolDeviceStateControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, PatrolDeviceStateControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + PatrolDeviceStateControl obj = (PatrolDeviceStateControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //巡检设备运行数据 + public String PatrolDeviceRunningControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, PatrolDeviceRunningControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + PatrolDeviceRunningControl obj = (PatrolDeviceRunningControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //机巢状态数据 + public String NestStateControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, NestStateControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + NestStateControl obj = (NestStateControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //机巢运行数据 + public String NestRunningControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, NestRunningControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + NestRunningControl obj = (NestRunningControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //坐标数据 + public String LocationControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, LocationControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + LocationControl obj = (LocationControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //巡视路线 + public String RouteControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, RouteControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + RouteControl obj = (RouteControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //设备告警数据 + public String AlarmControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + //xStream.alias(alias, AlarmControl.class); + log.info("[XML] AlarmControlXml2Json alias:{}", alias); + xStream.alias(alias, AlarmControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + AlarmControl obj = (AlarmControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //环境数据 + public String EnvironmentControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, EnvironmentControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + EnvironmentControl obj = (EnvironmentControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //任务状态 + public String TaskStateControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, TaskStateControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + TaskStateControl obj = (TaskStateControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //巡视结果 + public String TaskResultControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, TaskResultControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + TaskResultControl obj = (TaskResultControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //巡检告警数据 + public String AnalysisControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, AnalysisControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + AnalysisControl obj = (AnalysisControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/MyDecoder.java b/src/main/java/com/inspect/upstream/tcp/MyDecoder.java new file mode 100644 index 0000000..c104509 --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/MyDecoder.java @@ -0,0 +1,80 @@ +package com.inspect.upstream.tcp; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.RandomStringUtils; + +import java.util.List; + +@Slf4j +public class MyDecoder extends ByteToMessageDecoder { + + private final int BASE_LENGTH = 2 + 8 + 8 + 1 + 4 + 2; + + private Integer printRecvData = 0; + + public MyDecoder(Integer printRecvData) { + this.printRecvData = printRecvData; + } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + try { + int length = in.readableBytes(); + if (length < BASE_LENGTH) { +// log.error("not enough readableBytes: {}", length); + return; + } + + final String uuid = RandomStringUtils.randomAlphanumeric(16); + + if(printRecvData > 0) { + ByteBuf forPrint = in.copy(); + log.info("###### 会话:{}, 客户:{}, 上行原始报文 ######\n {}", uuid, ctx.channel().id().asShortText(), ByteBufUtil.hexDump(forPrint)); + forPrint.release(); + } + + do { + byte[] start = new byte[2]; + in.readBytes(start); + if (start[0] == -21 && start[1] == -112) { + long sendIndex = in.readLongLE(); + long receiveIndex = in.readLongLE(); + byte sourceFlag = in.readByte(); + int xmlLength = in.readIntLE(); + length = in.readableBytes(); + if (length >= xmlLength + 2) { + byte[] payload = new byte[xmlLength]; + in.readBytes(payload); + in.skipBytes(2); + + BinaryModel binaryModel = new BinaryModel(); + binaryModel.receiveIndex = receiveIndex; + binaryModel.sendIndex = sendIndex; + binaryModel.sourceFlag = sourceFlag; + binaryModel.dataLength = xmlLength; + binaryModel.dataBuf = Unpooled.copiedBuffer(payload); + binaryModel.uuid = uuid; + out.add(binaryModel); + break; + } else { + in.readerIndex(in.readerIndex() - 23); +// log.error("wrong xml length: {}, total length: {}", xmlLength, length); + } + } else { + in.readerIndex(in.readerIndex() - 2); +// log.error("wrong start flag: [{},{}]", start[0], start[1]); + } + + in.readByte(); + length = in.readableBytes(); + } while (length >= BASE_LENGTH); + } catch (Exception e) { + log.error("error" , e); + } + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/SystemType.java b/src/main/java/com/inspect/upstream/tcp/SystemType.java new file mode 100644 index 0000000..62ba09c --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/SystemType.java @@ -0,0 +1,82 @@ +package com.inspect.upstream.tcp; + +public class SystemType { + public static final int system = 251; + public static final int register_request = 1; + public static final int heart_request = 2; + public static final int has_response = 4; + public static final int no_response = 3; +} + +class RobotType { + public static final int robot = 1; + public static final int robotCar = 2; + public static final int robotPtz = 3; + public static final int robotFz = 4; + public static final int robotVl = 21; + public static final int robotIr = 22; +} + +class UAVType { + public static final int uav = 20001; + public static final int uavKz = 20002; + public static final int uavYt = 20003; + public static final int uavXj = 20004; + public static final int nest = 20005; +} + +class NestCtlType { + public static final int courseReversal = 20001; // + public static final int suddenStop = 20002; // + public static final int ptzPitch = 20003; // + public static final int picModelSet = 20004; // + public static final int nestSuddenStop = 20005; // +} + +class TaskType { + public static final int taskControl = 41; + public static final int taskSend = 101; + public static final int lendonTask = 102; + public static final int taskArea = 81; +} + +class ModelType { + public static final int modelSync = 61; + public static final int modelUpdate = 11; +} + +class QueryType { + public static final int queryResult = 121; +} + +class ResponseType { + public static final String retry = "100"; + public static final String succeed = "200"; + public static final String reject = "400"; + public static final String fault = "500"; +} + +class PushType { + public static final int patrolDeviceState = 1; + public static final int patrolDeviceRunning = 2; + public static final int nestState = 20001; + public static final int nestRunning = 10004; + public static final int location = 3; + public static final int route = 4; + public static final int alarm = 5; + public static final int environment = 21; + public static final int taskState = 41; + public static final int result = 61; + public static final int analysisAlarm = 62; + public static final int monitor = 63; + public static final int total = 81; +} + +class ConfigType { + public static final int dataLength = 25; + public static final String heart_beat_interval = "30"; + public static final String patroldevice_run_interval = "300"; + public static final String nest_run_interval = "300"; + public static final String env_interval = "300"; + public static final String weather_interval = "300"; +} diff --git a/src/main/java/com/inspect/upstream/tcp/UpJson2Xml.java b/src/main/java/com/inspect/upstream/tcp/UpJson2Xml.java new file mode 100644 index 0000000..c5483fd --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/UpJson2Xml.java @@ -0,0 +1,267 @@ +package com.inspect.upstream.tcp; + +import com.alibaba.fastjson.JSON; +import com.inspect.upstream.util.Color; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.naming.NoNameCoder; +import com.thoughtworks.xstream.io.xml.Xpp3Driver; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class UpJson2Xml { + + private String deviceAlias = "PatrolDevice"; + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + /** + * 默认为对上级的客户端的别名 + */ + private String alias; + + public UpJson2Xml(String alias) { + // 设备接入服务 + this.alias = alias; + } + + public String UpStreamJson2Xml(String json, Class clazz) { + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, clazz); + T obj = JSON.parseObject(json, clazz); + return xStream.toXML(obj); + } catch (com.thoughtworks.xstream.XStreamException e) { + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(deviceAlias, clazz); + T obj = JSON.parseObject(json, clazz); + return xStream.toXML(obj); + } catch (com.thoughtworks.xstream.XStreamException ex) { + log.error(Color.RED + "###### UpStreamJson2Xml解析失败:{} ######" + Color.END, ex.getMessage()); + return null; + } + } + } + + //模型更新上报指令 + public String UpdateModelJson2Xml(String json) { + UpdateModelControl obj = JSON.parseObject(json, UpdateModelControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, UpdateModelControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //任务控制和模型同步 + public String ResponseJson2Xml(String json) { + ResponseControl obj = JSON.parseObject(json, ResponseControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, ResponseControl.class); + obj.Items = ""; + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //模型同步 + public String ModelJson2Xml(String json) { + BaseControl obj = JSON.parseObject(json, ModelControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, ModelControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //机器人控制指令 + public String RobotJson2Xml(String json) { + RobotControl obj = JSON.parseObject(json, RobotControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, RobotControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //无人机控制指令 + public String UavControlJson2Xml(String json) { + RobotControl obj = JSON.parseObject(json, RobotControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, RobotControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //任务下发指令 + public String TaskSendJson2Xml(String json) { + TaskSendControl obj = JSON.parseObject(json, TaskSendControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, TaskSendControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //联动任务下发指令 + public String LinkageTaskJson2Xml(String json) { + LinkageTaskControl obj = JSON.parseObject(json, LinkageTaskControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, LinkageTaskControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //检修区域指令 + public String AreaJson2Xml(String json) { + AreaControl obj = JSON.parseObject(json, AreaControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, AreaControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + + //-----------------------------------------上行数据----------------------------------// + //巡视设备状态数据 + public String PatrolDeviceStateControlJson2Xml(String json) { + PatrolDeviceStateControl obj = JSON.parseObject(json, PatrolDeviceStateControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, PatrolDeviceStateControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //巡视设备运行数据 + public String PatrolDeviceRunningControlJson2Xml(String json) { + PatrolDeviceRunningControl obj = JSON.parseObject(json, PatrolDeviceRunningControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, PatrolDeviceRunningControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //无人机机巢状态数据 + public String NestStateJson2Xml(String json) { + NestStateControl obj = JSON.parseObject(json, NestStateControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, NestStateControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //无人机机巢运行数据 + public String NestRunningJson2Xml(String json) { + NestRunningControl obj = JSON.parseObject(json, NestRunningControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, NestRunningControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + + //巡视设备坐标 + public String LocationControlJson2Xml(String json) { + LocationControl obj = JSON.parseObject(json, LocationControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, LocationControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //巡视路线 + public String RouteControlJson2Xml(String json) { + RouteControl obj = JSON.parseObject(json, RouteControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, RouteControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //巡视设备异常告警数据 + public String AlarmControlJson2Xml(String json) { + AlarmControl obj = JSON.parseObject(json, AlarmControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, AlarmControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //环境数据 + public String EnvironmentControlJson2Xml(String json) { + EnvironmentControl obj = JSON.parseObject(json, EnvironmentControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, EnvironmentControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //任务状态数据 + public String TaskStateControlJson2Xml(String json) { + TaskStateControl obj = JSON.parseObject(json, TaskStateControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, TaskStateControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //巡视结果 + public String TaskResultControlJson2Xml(String json) { + TaskResultControl obj = JSON.parseObject(json, TaskResultControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, TaskResultControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //静默监视告警数据 + public String MonitorControlJson2Xml(String json) { + MonitorControl obj = JSON.parseObject(json, MonitorControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, MonitorControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //巡视设备统计信息上报 + public String ReportControlJson2Xml(String json) { + ReportControl obj = JSON.parseObject(json, ReportControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, ReportControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //巡检告警数据 + public String AnalysisControlJson2Xml(String json) { + AnalysisControl obj = JSON.parseObject(json, AnalysisControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, AnalysisControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServer.java b/src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServer.java new file mode 100644 index 0000000..fccf2b0 --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServer.java @@ -0,0 +1,584 @@ +package com.inspect.upstream.tcp; + +import com.alibaba.fastjson.JSONObject; +import com.inspect.upstream.constant.Constant; +import com.inspect.upstream.controller.ClientController; +import com.inspect.upstream.cofiguration.DeviceServerProperties; +import com.inspect.upstream.util.Color; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.naming.NoNameCoder; +import com.thoughtworks.xstream.io.xml.Xpp3Driver; +import com.thoughtworks.xstream.security.AnyTypePermission; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import io.netty.util.CharsetUtil; +import io.netty.util.internal.StringUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.io.ByteArrayInputStream; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.concurrent.*; + +@Slf4j +@Component +public class UpstreamMockNettyServer { + /** + * 接收/发送报文xml外层别名 + */ + private final String aliasHost = "PatrolHost"; + + private final String aliasDevice = "PatrolDevice"; + + @Resource + private ClientController clientController; + private EventLoopGroup bossGroup; + private EventLoopGroup workGroup; + private long sendIndex = 0; //若重启系统后还要延续之前的序列号则需要把序列号存入redis中 + private long receiveIndex = 0; + private DownXml2Json downXml2Json = new DownXml2Json(aliasHost); + private UpJson2Xml upJson2Xml = new UpJson2Xml(aliasHost); + private UpstreamMockNettyServerHandler upstreamMockNettyServerHandler; + + @Resource + DeviceServerProperties deviceServerProperties; + + @Resource(name = "stringRedisTemplate") + private RedisTemplate redisTemplate; + + @Resource + private RabbitTemplate rabbitTemplate; + + @Value("${iip_server.authDevice.url}") + String iipAuthDeviceUrl; + + @Value("${print_recv_data:1}") + Integer printRecvData; + + @Value("${separate_packages:0}") + Integer separatePackages; + + private int serverPort; + + public void init() { + log.info("print_recv_data config: {}", printRecvData); + log.info("separate_packages config: {}", separatePackages); + + this.serverPort = deviceServerProperties.port; + upJson2Xml = new UpJson2Xml(aliasHost); + downXml2Json = new DownXml2Json(aliasHost); + } + + @Async + public void startServer() { + // 初始化 + init(); + + //new 一个主线程组 + bossGroup = new NioEventLoopGroup(); + //new 一个工作线程组 + workGroup = new NioEventLoopGroup(); + ServerBootstrap bootstrap = new ServerBootstrap() + .group(bossGroup, workGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + if(separatePackages > 0) { + ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, Integer.MAX_VALUE, 19, 4, 2, 0, true)); + } + ch.pipeline().addLast(new MyDecoder(printRecvData)); + upstreamMockNettyServerHandler = new UpstreamMockNettyServerHandler(UpstreamMockNettyServer.this); + ch.pipeline().addLast(upstreamMockNettyServerHandler); + } + }) + .localAddress(serverPort) + .option(ChannelOption.SO_BACKLOG, 1024) + .option(ChannelOption.SO_REUSEADDR, true) + .childOption(ChannelOption.SO_KEEPALIVE, true) + .childOption(ChannelOption.SO_LINGER, 10); + try { + ChannelFuture future = bootstrap.bind(serverPort).sync(); + log.info("###### 上级系统模拟服务器启动 ######"); + future.channel().closeFuture().sync(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + close(); + } + } + + //释放资源 + public void close() { + if (bossGroup != null) { + bossGroup.shutdownGracefully(); + } + if (workGroup != null) { + workGroup.shutdownGracefully(); + } + } + + private String compact(String xml) { + String compactXml = xml + .replaceAll(">\\s+<", "><") // 处理标签间的空白 + .replaceAll("\\s+", " "); // 压缩连续空格(可选) + return compactXml; + } + + //发送消息 + public void flushMsgToDevice(String uuid, String clientKey, boolean request, String xml) { + if (ChannelCache.getInstance().get(clientKey) != null) { + if(clientKey.startsWith("areaPatrolServer")) { + xml = xml.replace("", ""); + xml = xml.replace("", ""); + } else { + xml = xml.replace("", ""); + xml = xml.replace("", ""); + } + ByteBuf byteBuf = Unpooled.copiedBuffer(xml, CharsetUtil.UTF_8); + int length = byteBuf.readableBytes(); + ByteBuf allBuf = Unpooled.buffer(length + ConfigType.dataLength); + allBuf.writeByte(0xEB); + allBuf.writeByte(0x90); + allBuf.writeLongLE(sendIndex); + allBuf.writeLongLE(receiveIndex); + allBuf.writeByte(request ? 0x00 : 0x01); + allBuf.writeIntLE(length); + allBuf.writeBytes(byteBuf); + allBuf.writeByte(0xEB); + allBuf.writeByte(0x90); + redisTemplate.opsForValue().set(String.valueOf(sendIndex), allBuf.toString(CharsetUtil.US_ASCII), 60L, TimeUnit.SECONDS); + upstreamMockNettyServerHandler.sendMsg(uuid, clientKey, allBuf, compact(xml), request); + sendIndex++; + } else { + log.warn(Color.RED + "###### 客户端[{}]离线! ######" + Color.END, clientKey); + } + } + + public void flushMsgToDeviceBroadcast(String uuid, String clientKey, boolean request, String xml) { + for (String client : ChannelCache.getInstance().getClients()) { + if(clientKey.startsWith("areaPatrolServer")) { + xml = xml.replace("", ""); + xml = xml.replace("", ""); + } else { + xml = xml.replace("", ""); + xml = xml.replace("", ""); + } + ByteBuf byteBuf = Unpooled.copiedBuffer(xml, CharsetUtil.UTF_8); + int length = byteBuf.readableBytes(); + ByteBuf allBuf = Unpooled.buffer(length + ConfigType.dataLength); + allBuf.writeByte(0xEB); + allBuf.writeByte(0x90); + allBuf.writeLongLE(sendIndex); + allBuf.writeLongLE(receiveIndex); + allBuf.writeByte(request ? 0x00 : 0x01); + allBuf.writeIntLE(length); + allBuf.writeBytes(byteBuf); + allBuf.writeByte(0xEB); + allBuf.writeByte(0x90); + redisTemplate.opsForValue().set(String.valueOf(sendIndex), allBuf.toString(CharsetUtil.US_ASCII), 60L, TimeUnit.SECONDS); + upstreamMockNettyServerHandler.sendMsg(uuid, client, allBuf, compact(xml), request); + sendIndex++; + try { + Thread.sleep(1); + } catch (InterruptedException e) {} + } + } + + //开启线程处理消息 + public void receiveMsg(BinaryModel binaryModel, ChannelHandlerContext context) { +// executorService.execute(() -> { + try { + dealMsgInThreadPool(binaryModel, context); + } catch (Exception e) { + log.error("error", e); + } +// }); + } + + //重新发送 + public void resetSendMsg(long sendIndex, String sendCode) { + // 获取缓存的中的值 + String msg = redisTemplate.opsForValue().get(String.valueOf(sendIndex)); + if (!StringUtil.isNullOrEmpty(msg)) { + ByteBuf allBuf = Unpooled.copiedBuffer(msg, CharsetUtil.US_ASCII); + flushMsgToDevice("", sendCode, true, msg); + } + } + + //处理接收消息 + private void dealMsgInThreadPool(BinaryModel binaryModel, ChannelHandlerContext context) throws DocumentException { + String xml = binaryModel.dataBuf.toString(CharsetUtil.UTF_8); + receiveIndex = binaryModel.sendIndex; + SAXReader saxReader = new SAXReader(); + Document document = saxReader.read(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))); + Element root = document.getRootElement(); + String sendCode = root.element("SendCode").getText(); + String receiveCode = root.element("ReceiveCode").getText(); + ChannelCache.getInstance().replace(sendCode, context); + int type = 0; + if (null != root.element("Type") && !StringUtil.isNullOrEmpty(root.element("Type").getText())) { + type = Integer.parseInt(root.element("Type").getText()); + } + int command = 0; + if (null != root.element("Command") && !StringUtil.isNullOrEmpty(root.element("Command").getText())) { + command = Integer.parseInt(root.element("Command").getText()); + } + + String compactXml = compact(xml); +// log.info(Color.YELLOW + "###### 会话:{}, 客户:[{}], 消息类型:{}, 命令:{}, 消息体: ######\n{}" + Color.END, binaryModel.uuid, sendCode, type, command, compactXml); + //判断是否重发 + if (type == SystemType.system) { + if (command == SystemType.has_response || command == SystemType.no_response) { + if (null != root.element("Code")) { + String code = root.element("Code").getText(); + if (code.equals(ResponseType.retry)) { + resetSendMsg(binaryModel.receiveIndex, sendCode); + return; + } else if (code.equals(ResponseType.succeed)) { + log.info(Color.YELLOW + "###### 客户端[{}]响应结果为成功 ######" + Color.END, sendCode); + if(command == SystemType.no_response) { + return; + } + } else if (code.equals(ResponseType.fault)) { + log.warn(Color.RED + "###### 客户端[{}]响应结果为失败 ######" + Color.END, sendCode); + return; + } else if (code.equals(ResponseType.reject)) { + log.warn(Color.RED + "###### 客户端[{}]响应结果为拒绝 ######" + Color.END, sendCode); + return; + } + } + } + } + String json = null; + switch (type) { + case SystemType.system: + switch (command) { + case SystemType.register_request: + // 收到接入侧注册信息 + log.info(Color.YELLOW + "###### 客户端[{}]注册 ######" + Color.END, sendCode); + dealRegister(binaryModel.uuid, compactXml); + break; + case SystemType.heart_request: + // 处理心跳请求响应 + log.info(Color.YELLOW + "###### 客户端[{}]上报心跳 ######" + Color.END, sendCode); + sendHeartBeat(binaryModel.uuid, compactXml); + break; + case SystemType.has_response: + // 处理有返回值的消息响应 + if (null != root.element("Items") && null != root.element("Items").element("Item")) { + // 处理设备上报的模型同步响应 + if (null != root.element("Items").element("Item").attribute("device_file_path")) { + // 收到接入侧模型同步数据 + log.info(Color.YELLOW + "###### 模型同步收到客户端[{}]响应数据 ######" + Color.END, sendCode); + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, ModelControl.class); + JSONObject jsonObject = JSONObject.parseObject(json); + jsonObject.put("uuid", binaryModel.uuid); + jsonObject.put("Type", Constant.MODEL_UP_TYPE); + rabbitTemplate.convertAndSend(Constant.EX_CHANGE_NAME, Constant.ROUTING_KEY_NAME, jsonObject.toJSONString()); + } + // 任务控制响应任务执行ID + if (null != root.element("Items").element("Item").attribute("task_patrolled_id")) { + // 收到接入侧任务下发或控制回复数据 + log.info(Color.YELLOW + "###### 任务下发收到客户端[{}]响应数据 ######" + Color.END, sendCode); + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, ModelControl.class); + JSONObject jsonObject = JSONObject.parseObject(json); + jsonObject.put("SendCode", ""); + clientController.sendMsg(binaryModel.uuid, jsonObject.toJSONString()); + } + } else { + log.warn(Color.RED + "###### 客户端[{}]响应数据没有items ######" + Color.END, sendCode); + } + break; + default: + log.warn(Color.RED + "###### 客户端[{}]非法的消息不予处理 ######" + Color.END, sendCode); + } + break; + case PushType.patrolDeviceState:// insert into basedata_mont_patdevstadata + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, PatrolDeviceStateControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报设备状态数据 ######" + Color.END, sendCode); + break; + case PushType.patrolDeviceRunning:// insert into basedata_mont_patdevrundata + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, PatrolDeviceRunningControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报设备运行数据 ######" + Color.END, sendCode); + break; + case PushType.nestState:// insert into basedata_mont_neststadata + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, NestStateControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报机巢状态数据 ######" + Color.END, sendCode); + break; + case PushType.nestRunning:// insert into basedata_mont_nestrundata + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, NestRunningControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报机巢运行数据 ######" + Color.END, sendCode); + break; + case PushType.location:// insert into basedata_mont_patdevcoord + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, LocationControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报设备坐标 ######" + Color.END, sendCode); + break; + case PushType.route:// insert into basedata_mont_patdevpatroute + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, RouteControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报设备路线 ######" + Color.END, sendCode); + break; + case PushType.alarm:// insert into basedata_mont_patdevalmabn + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, AlarmControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报设备异常告警 ######" + Color.END, sendCode); + break; + case PushType.environment:// insert into basedata_mont_evndata + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, EnvironmentControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报设备环境数据 ######" + Color.END, sendCode); + break; + case PushType.taskState:// insert into basedata_mont_taskstadata and patrol_task_status + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, TaskStateControl.class); + //root@Linx:/home/atia/data/log/inspect-main# grep -rn "type:41, messageBody:" info.log + log.info(Color.YELLOW + "###### 客户端[{}]上报设备任务状态 ######" + Color.END, sendCode); + break; + case PushType.result:// insert into basedata_mont_taskresult and patrol_task_result_main + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, TaskResultControl.class); + //root@Linx:/home/atia/data/log/inspect-main# grep -rn "type:61, messageBody:" info.log + log.info(Color.YELLOW + "###### 客户端[{}]上报巡视结果 ######" + Color.END, sendCode); + break; + default: + log.info(Color.RED + "###### 客户端[{}]上报的非法消息不予处理 ######" + Color.END, sendCode); + } + if (type != SystemType.system && !StringUtil.isNullOrEmpty(json)) { + if ((type == NestCtlType.courseReversal && command == 3)) { // 处理用SSCOM模拟的数据, 向无人机发送控制指令 + log.info("###### 向客户端[{}]透传200001控制指令 ######", sendCode); + flushMsgToDeviceBroadcast(binaryModel.uuid, receiveCode, false, compactXml); + } else { + JSONObject jsonObject = JSONObject.parseObject(json); + jsonObject.put("uuid", binaryModel.uuid); + json = jsonObject.toJSONString(); + // send to BasedataMontDataMqAcceptHandle + rabbitTemplate.convertAndSend(Constant.EX_CHANGE_NAME, Constant.ROUTING_KEY_NAME, json); + boolean isHost = json.contains(aliasHost); + sendResponseToDevice(binaryModel.uuid, receiveCode, sendCode, isHost); + } + } else { + if ((type == NestCtlType.suddenStop && command == 7) + || (type == NestCtlType.ptzPitch && command == 6) + || (type == NestCtlType.picModelSet && command == 1) + || (type == NestCtlType.nestSuddenStop && command == 2)) {// 处理用SSCOM模拟的数据, 向无人机发送控制指令 + log.info("###### 向客户端[{}]透传200002~20005控制指令 ######", sendCode); + flushMsgToDeviceBroadcast(binaryModel.uuid, receiveCode, false, compactXml); + } + } + } + + public void sendResponseToDevice(String uuid, String sendCode, String receiveCode, boolean isHost) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(isHost ? aliasHost : aliasDevice, ResponseControl.class); + xStream.autodetectAnnotations(true); + ResponseControl responseControl = new ResponseControl(); + responseControl.SendCode = sendCode; + responseControl.ReceiveCode = receiveCode; + responseControl.Type = String.valueOf(SystemType.system); + responseControl.Code = ResponseType.succeed; + responseControl.Command = String.valueOf(SystemType.no_response); + responseControl.Time = CommonUtils.GetNowDateString(); + responseControl.Items = ""; + String xml = xStream.toXML(responseControl); + flushMsgToDevice(uuid, receiveCode, false, xml); + } + + //处理注册应答 + public void dealRegister(String uuid, String xml) { + BaseControl obj = new BaseControl(); + try { + XStream xStream = getXmlStreamInstance(); + xStream.alias(aliasHost, BaseControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + obj = (BaseControl) xStream.fromXML(xml); + } catch (com.thoughtworks.xstream.XStreamException e) { + try { + XStream xStreamEx = getXmlStreamInstance(); + xStreamEx.alias(aliasDevice, BaseControl.class); + xStreamEx.autodetectAnnotations(true); + xStreamEx.ignoreUnknownElements(); + xStreamEx.addPermission(AnyTypePermission.ANY); + obj = (BaseControl) xStreamEx.fromXML(xml); + } catch (com.thoughtworks.xstream.XStreamException e2) { + log.error(Color.RED + "###### dealRegister解析失败:{} ######" + Color.END, e2.getMessage()); + } + } + + RegisterResponseControl responseControl = new RegisterResponseControl(); + responseControl.SendCode = obj.ReceiveCode; + responseControl.ReceiveCode = obj.SendCode; + responseControl.Type = String.valueOf(SystemType.system); + responseControl.Command = String.valueOf(SystemType.has_response); + responseControl.Time = CommonUtils.GetNowDateString(); + + // 调用基础服务鉴权设备 + if (authDevice(obj.SendCode)) { + //鉴权通过 + responseControl.Code = ResponseType.succeed; + responseControl.Items = new ArrayList<>(); + RegisterResponseModel model = new RegisterResponseModel(); + model.patroldevice_run_interval = ConfigType.patroldevice_run_interval; + model.heart_beat_interval = ConfigType.heart_beat_interval; + model.env_interval = ConfigType.env_interval; + //model.weather_interval= ConfigType.weather_interval; + + // 当连接客户端为无人机机巢时,报文中增加机巢运行数据上报间隔 + if (obj.SendCode.equals(deviceServerProperties.nestCode)) { + model.nest_run_interval = ConfigType.nest_run_interval; + } + responseControl.Items.add(model); + + // 推送消息到mq + JSONObject jsonObject = new JSONObject(); + jsonObject.put("uuid", uuid); + jsonObject.put("patroldevice_code", obj.SendCode); + jsonObject.put("SendCode", obj.SendCode); + jsonObject.put("Type", "heartbeat"); + jsonObject.put("eventType", "connect"); + jsonObject.put("HeartBeatInterval", ConfigType.heart_beat_interval); + + rabbitTemplate.convertAndSend(Constant.EX_CHANGE_NAME, Constant.ROUTING_KEY_NAME, jsonObject.toJSONString()); + } else { + // 鉴权不通过 + responseControl.Code = ResponseType.fault; + } + sendRegisterResponse(uuid, responseControl, obj.SendCode); + } + + private XStream getXmlStreamInstance() { + return new XStream(new Xpp3Driver(new NoNameCoder())); + } + + /** + * 鉴权巡视设备 + * + * @param sendCode 巡视设备(机器人、无人机)唯一标识 + * @return + */ + public boolean authDevice(String sendCode) { + return true; + } + + public void sendRegisterResponse(String uuid, RegisterResponseControl responseControl, String sendCode) { + String xml = ""; + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(aliasHost, RegisterResponseControl.class); + xStream.autodetectAnnotations(true); + xml = xStream.toXML(responseControl); + } catch (com.thoughtworks.xstream.XStreamException e) { + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(aliasDevice, RegisterResponseControl.class); + xStream.autodetectAnnotations(true); + xml = xStream.toXML(responseControl); + } catch (com.thoughtworks.xstream.XStreamException e2) { + log.error(Color.RED + "###### sendRegisterResponse解析失败:{} ######" + Color.END, e2.getMessage()); + } + } + flushMsgToDevice(uuid, sendCode, false, xml); + } + + public void sendHeartBeat(final String uuid, String xml) { + boolean isHost = true; + BaseControl obj = new BaseControl(); + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(aliasHost, BaseControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + obj = (BaseControl) xStream.fromXML(xml); + } catch (com.thoughtworks.xstream.XStreamException e) { + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(aliasDevice, BaseControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + obj = (BaseControl) xStream.fromXML(xml); + isHost = false; + } catch (com.thoughtworks.xstream.XStreamException e2) { + log.error(Color.RED + "###### sendHeartBeat解析失败:{} ######" + Color.END, e2.getMessage()); + } + } + + sendResponseToDevice(uuid, obj.ReceiveCode, obj.SendCode, isHost); + + // 推送消息到mq + JSONObject jsonObject = new JSONObject(); + jsonObject.put("uuid", uuid); + jsonObject.put("SendCode", obj.SendCode); + jsonObject.put("Type", "heartbeat"); + jsonObject.put("eventType", "heart"); + jsonObject.put("HeartBeatInterval", ConfigType.heart_beat_interval); + + rabbitTemplate.convertAndSend(Constant.EX_CHANGE_NAME, Constant.ROUTING_KEY_NAME, jsonObject.toJSONString()); + } + + public void sendXmlMessage(JSONObject obj) { + int type = obj.getInteger("Type"); + String receiveCode = obj.getString("ReceiveCode"); + String json = obj.toJSONString(); + + String xml = null; + switch (type) { + case RobotType.robotVl: + case RobotType.robot: + case RobotType.robotCar: + case RobotType.robotFz: + case RobotType.robotIr: + case RobotType.robotPtz: + xml = upJson2Xml.UpStreamJson2Xml(json, RobotControl.class); + break; + case UAVType.uav: + case UAVType.uavXj: + case UAVType.uavKz: + case UAVType.uavYt: + case UAVType.nest: + xml = upJson2Xml.UpStreamJson2Xml(json, RobotControl.class); + break; + case TaskType.taskControl: + xml = upJson2Xml.UpStreamJson2Xml(json, ResponseControl.class); + break; + case TaskType.taskSend: + xml = upJson2Xml.UpStreamJson2Xml(json, TaskSendControl.class); + break; + case TaskType.taskArea: + xml = upJson2Xml.UpStreamJson2Xml(json, AreaControl.class); + break; + case ModelType.modelSync: + xml = upJson2Xml.UpStreamJson2Xml(json, ResponseControl.class); + break; + case TaskType.lendonTask: + xml = upJson2Xml.UpStreamJson2Xml(json, LinkageTaskControl.class); + break; + default: + log.error(Color.RED + "###### 向设备端下发命令, 类型:{}错误, 不予处理 ######" + Color.END, type); + + } + if (!StringUtils.isEmpty(xml)) { + flushMsgToDevice("", receiveCode, true, xml); + } else { + log.error(Color.RED + "###### xml is empty ######" + Color.END, type); + } + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServerHandler.java b/src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServerHandler.java new file mode 100644 index 0000000..8b03c65 --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServerHandler.java @@ -0,0 +1,92 @@ +package com.inspect.upstream.tcp; + +import com.inspect.upstream.util.Color; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class UpstreamMockNettyServerHandler extends ChannelInboundHandlerAdapter { + private UpstreamMockNettyServer upstreamMockNettyServer; + + public UpstreamMockNettyServerHandler(UpstreamMockNettyServer upstreamMockNettyServer) { + this.upstreamMockNettyServer = upstreamMockNettyServer; + } + + public void sendMsg(String uuid, String clientKey, ByteBuf byteBuf, String xml, boolean request) { + ChannelHandlerContext ctx = ChannelCache.getInstance().get(clientKey); + if(ctx != null) { + ctx.writeAndFlush(Unpooled.wrappedBuffer(byteBuf)).addListener( + (ChannelFuture future) -> { + if (future.isSuccess()) { + if(request) { + log.info("###### 活动连接:{}, 向客户端[{}]下发消息成功:{} ######", ChannelCache.getInstance().getClients(), clientKey, xml); + } else { + log.info(Color.CYAN + "###### 活动连接:{}, 向客户端[{}]响应成功 ######" + Color.END, ChannelCache.getInstance().getClients(), clientKey); + } + } else { + if(request) { + log.error(Color.RED + "###### 活动连接:{}, 向客户端[{}]下发消息失败:{} ######" + Color.END, ChannelCache.getInstance().getClients(), clientKey, xml); + } else { + log.error(Color.RED + "###### 活动连接:{}, 向客户端[{}]响应失败 ######" + Color.END, ChannelCache.getInstance().getClients(), clientKey); + } + } + }); + } else { + if(request) { + log.error(Color.RED + "###### 活动连接:{},无法向客户端[{}]下发消息,ctx==null######" + Color.END, ChannelCache.getInstance().getClients(), clientKey); + } else { + log.error(Color.RED + "###### 活动连接:{},无法向客户端[{}]响应,ctx==null######" + Color.END, ChannelCache.getInstance().getClients(), clientKey); + } + } + } + + /** + * 客户端连接会触发 + */ + @Override + public void channelActive(ChannelHandlerContext ctx) { + String id = ctx.channel().id().asShortText(); + ChannelCache.getInstance().addIfAbsent(id, ctx); + log.info("###### 设备上线:{} ######", id); + } + + /** + * 客户端断开会触发 + */ + @Override + public void channelInactive(ChannelHandlerContext ctx) { + String id = ctx.channel().id().asShortText(); + log.info("###### 设备断开:{} ######", id); + ChannelCache.getInstance().remove(ctx); + } + + /** + * 客户端发消息会触发 + */ + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + String id = ctx.channel().id().asShortText(); + BinaryModel binaryModel = (BinaryModel) msg; + binaryModel.id = id; + upstreamMockNettyServer.receiveMsg((BinaryModel) msg, ctx); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + super.channelReadComplete(ctx); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + super.userEventTriggered(ctx, evt); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + log.error( "channel ctx: " + ctx.channel() + " exception", cause); + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/UpstreamServerStart.java b/src/main/java/com/inspect/upstream/tcp/UpstreamServerStart.java new file mode 100644 index 0000000..bf8e930 --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/UpstreamServerStart.java @@ -0,0 +1,22 @@ +package com.inspect.upstream.tcp; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.Resource; + +@Slf4j +@ConditionalOnProperty(name = "boot.server", havingValue = "true") +@Configuration +public class UpstreamServerStart implements CommandLineRunner { + + @Resource + UpstreamMockNettyServer upstreamMockNettyServer; + + @Override + public void run(String... args) throws Exception { + upstreamMockNettyServer.startServer(); + } +} diff --git a/src/main/java/com/inspect/upstream/util/Color.java b/src/main/java/com/inspect/upstream/util/Color.java new file mode 100644 index 0000000..ea27310 --- /dev/null +++ b/src/main/java/com/inspect/upstream/util/Color.java @@ -0,0 +1,11 @@ +package com.inspect.upstream.util; + +public class Color { + public static final String END = "\033[0m"; + public static final String RED = "\033[31m"; + public static final String GREEN = "\033[32m"; + public static final String YELLOW = "\033[33m"; + public static final String BLUE = "\033[34m"; + public static final String MAGENTA = "\033[35m"; + public static final String CYAN = "\033[36m"; +} diff --git a/src/main/java/com/inspect/upstream/util/FastJson2JsonRedisSerializer.java b/src/main/java/com/inspect/upstream/util/FastJson2JsonRedisSerializer.java new file mode 100644 index 0000000..665bebe --- /dev/null +++ b/src/main/java/com/inspect/upstream/util/FastJson2JsonRedisSerializer.java @@ -0,0 +1,58 @@ +package com.inspect.upstream.util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.SerializationException; +import org.springframework.util.Assert; + +import java.nio.charset.Charset; + +public class FastJson2JsonRedisSerializer implements RedisSerializer { + @SuppressWarnings("unused") + private ObjectMapper objectMapper = new ObjectMapper(); + + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + private Class clazz; + + static { + ParserConfig.getGlobalInstance().setAutoTypeSupport(true); + } + + public FastJson2JsonRedisSerializer(Class clazz) { + super(); + this.clazz = clazz; + } + + @Override + public byte[] serialize(T t) throws SerializationException { + if (t == null) { + return new byte[0]; + } + return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); + } + + @Override + public T deserialize(byte[] bytes) throws SerializationException { + if (bytes == null || bytes.length <= 0) { + return null; + } + String str = new String(bytes, DEFAULT_CHARSET); + + return JSON.parseObject(str, clazz); + } + + public void setObjectMapper(ObjectMapper objectMapper) { + Assert.notNull(objectMapper, "'objectMapper' must not be null"); + this.objectMapper = objectMapper; + } + + protected JavaType getJavaType(Class clazz) { + return TypeFactory.defaultInstance().constructType(clazz); + } +} diff --git a/src/main/java/com/inspect/upstream/util/HexUtils.java b/src/main/java/com/inspect/upstream/util/HexUtils.java new file mode 100644 index 0000000..c83c056 --- /dev/null +++ b/src/main/java/com/inspect/upstream/util/HexUtils.java @@ -0,0 +1,16 @@ +package com.inspect.upstream.util; + +import org.apache.commons.codec.binary.Hex; + +import java.nio.charset.Charset; + +public class HexUtils { + public static String ascii2hex(String str) { + return convertStringToHex(str, "UTF8"); + } + + public static String convertStringToHex(String str, String charsetName) { + char[] chars = Hex.encodeHex(str.getBytes(Charset.forName(charsetName))); + return String.valueOf(chars); + } +} diff --git a/src/main/java/com/inspect/upstream/util/ProtoDef.java b/src/main/java/com/inspect/upstream/util/ProtoDef.java new file mode 100644 index 0000000..f9f152d --- /dev/null +++ b/src/main/java/com/inspect/upstream/util/ProtoDef.java @@ -0,0 +1,86 @@ +package com.inspect.upstream.util; + +import javolution.io.Struct; +import org.apache.commons.codec.binary.Hex; + +import java.nio.ByteOrder; + +public class ProtoDef extends Struct { + Unsigned16 mark = new Unsigned16(); + Signed64 sendSeq = new Signed64(); + Signed64 recvSeq = new Signed64(); + Signed8 session = new Signed8(); + Signed32 xmlLength = new Signed32(); + + //一定要加上这个,不然会出现对齐的问题 + @Override + public boolean isPacked() { + return true; + } + + //设置为小端格式 + @Override + public ByteOrder byteOrder() { + return ByteOrder.LITTLE_ENDIAN; + } + + //测试 + public static void main(String[] args) { + String xml = +// "\n" + +// " INSPECT-SERVER-001\n" + +// " DRONE-001\n" + +// " 20001\n" + +// " DRONE-001\n" + +// " 3\n" + +// " \n" + +// " \n" + +// ""; + +// "\n" + +// " G100-001\n" + +// " L100-001\n" + +// " 61\n" + +// " \n" + +// " \n" + +// " \n" + +// " \n" + +// " \n" + +// " \n" + +// ""; + + "\n" + + "\n" + + " G100-001\n" + + " L100-001\n" + + " 61\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + String dataHex = HexUtils.ascii2hex(xml); + int length = dataHex.length() / 2; + + ProtoDef proto = new ProtoDef(); + proto.mark.set(0x90EB); + proto.sendSeq.set(0x3c); + proto.recvSeq.set(0x39); + proto.session.set((byte)0); + proto.xmlLength.set(length); + + byte[] bytes = new byte[proto.getByteBuffer().limit()]; + proto.getByteBuffer().get(bytes); + String protoHex = Hex.encodeHexString(bytes, true); + + System.out.println(protoHex + dataHex + "eb90"); + } +} diff --git a/src/main/java/com/inspect/upstream/util/SpringApplicationContext.java b/src/main/java/com/inspect/upstream/util/SpringApplicationContext.java new file mode 100644 index 0000000..33476fd --- /dev/null +++ b/src/main/java/com/inspect/upstream/util/SpringApplicationContext.java @@ -0,0 +1,46 @@ +package com.inspect.upstream.util; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Service; + +@Service +public class SpringApplicationContext implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) { + SpringApplicationContext.applicationContext = applicationContext; + } + + public static ApplicationContext getApplicationContext() { + checkApplicationContext(); + return applicationContext; + } + + @SuppressWarnings("unchecked") + public static T getBean(String name) { + checkApplicationContext(); + return (T) applicationContext.getBean(name); + } + + @SuppressWarnings("unchecked") + public static T getBean(Class clazz) { + checkApplicationContext(); + return (T) applicationContext.getBeansOfType(clazz); + } + + + public static void cleanApplicationContext() { + applicationContext = null; + } + + private static void checkApplicationContext() { + if (applicationContext == null) { + throw new IllegalStateException( + "applicationContext未注入,请在spring的context.xml中定义SpringContextHolder"); + } + } + +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..badf004 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,41 @@ +spring: + application: + name: upstream + redis: + host: 127.0.0.1 + + rabbitmq: + host: 10.10.18.13 + port: 5673 + username: guest + password: guest + +server: + port: 22508 + +deviceServer: + serverIp: 127.0.0.1 + serverPort: 10011 + deviceServerCode: "192.168.1.66" + robotCode: "E100-001" + nestCode: "UAV001" + deviceCode: "192.168.1.15" + +upSystemServer: + serverIp: 127.0.0.1 + serverPort: 10012 + upCode: "192.168.1.99" + iipCode: "192.168.1.66" + +iip_server: + send: + url: http://127.0.0.1:9901/client/send + authDevice: + url: http://127.0.0.1:9902/eqpbook/checkPatrolDeviceIsExist/%s + +up_time_interval_setting: time_interval_up_system_setting + +boot: + client: false + server: true + diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml new file mode 100644 index 0000000..843532a --- /dev/null +++ b/src/main/resources/application-prod.yml @@ -0,0 +1,42 @@ +spring: + application: + name: upstream + redis: + host: 199.199.199.1 + + rabbitmq: + host: 199.199.199.4 + port: 5672 + username: guest + password: guest + + +server: + port: 22508 + +deviceServer: + serverIp: 127.0.0.1 + serverPort: 10011 + deviceServerCode: "192.168.1.66" + robotCode: "192.168.1.15" + nestCode: "192.168.1.16" + deviceCode: "192.168.1.15" + +upSystemServer: + serverIp: 192.168.1.99 + serverPort: 10011 + upCode: "192.168.1.99" + iipCode: "192.168.1.66" + +iip_server: + send: + url: http://199.199.199.104:9901/client/send + authDevice: + url: http://199.199.199.105:9902/eqpbook/checkPatrolDeviceIsExist/%s + +up_time_interval_setting: time_interval_up_system_setting + +boot: + client: false + server: true + diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml new file mode 100644 index 0000000..20a5447 --- /dev/null +++ b/src/main/resources/application-test.yml @@ -0,0 +1,42 @@ +spring: + application: + name: upstream + redis: + host: 199.199.199.1 + + rabbitmq: + host: 199.199.199.4 + port: 5672 + username: guest + password: guest + + +server: + port: 22508 + +deviceServer: + serverIp: 127.0.0.1 + serverPort: 10011 + deviceServerCode: "INSPECT-SERVER-001" + robotCode: "DRONE-001" + nestCode: "NEST-001" + deviceCode: "DRONE-001" + +upSystemServer: + serverIp: 10.10.18.100 + serverPort: 10011 + upCode: "192.168.1.99" + iipCode: "INSPECT-SERVER-001" + +iip_server: + send: + url: http://199.199.199.104:9901/client/send + authDevice: + url: http://199.199.199.105:9902/eqpbook/checkPatrolDeviceIsExist/%s + +up_time_interval_setting: time_interval_up_system_setting + +boot: + client: true + server: true + diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..72de509 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,42 @@ +spring: + application: + name: upstream + redis: + host: 199.199.199.1 + + rabbitmq: + host: 199.199.199.4 + port: 5672 + username: guest + password: guest + + +server: + port: 22508 + +deviceServer: + serverIp: 127.0.0.1 + serverPort: 10011 + deviceServerCode: "192.168.1.116" + robotCode: "192.168.1.15" + nestCode: "192.168.1.16" + deviceCode: "192.168.1.15" + +upSystemServer: + serverIp: 10.10.18.100 + serverPort: 10011 + upCode: "192.168.1.99" + iipCode: "192.168.1.66" + +iip_server: + send: + url: http://199.199.199.104:9901/client/send + authDevice: + url: http://199.199.199.105:9902/eqpbook/checkPatrolDeviceIsExist/%s + +up_time_interval_setting: time_interval_up_system_setting + +boot: + client: true + server: true + diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..a466703 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + ${log.pattern} + + + + + + ${log.path}/info.log + + + + ${log.path}/info/info.%d{yyyy-MM-dd}.%i.log + ${log.maxFileSize} + + ${log.maxHistory} + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + + ${log.path}/error.log + + + + ${log.path}/error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/inspect/upstream/InspectUpstreamApplicationTests.java b/src/test/java/com/inspect/upstream/InspectUpstreamApplicationTests.java new file mode 100644 index 0000000..b426d32 --- /dev/null +++ b/src/test/java/com/inspect/upstream/InspectUpstreamApplicationTests.java @@ -0,0 +1,13 @@ +package com.inspect.upstream; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class InspectUpstreamApplicationTests { + + @Test + void contextLoads() { + } + +}