commit 7a02e26ca0b164c78b863658db97bce6d6f6ade7 Author: htjcAdmin Date: Thu Feb 27 15:45:53 2025 +0800 /*tcpserver*/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..49776a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +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/ +/tcpServer.log +/.mvn/ +/tcpServer.2022-04-21.log +/log/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2f62473 --- /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/tcpserver-0.0.1-SNAPSHOT.jar /work/tcpserver.jar + +ENV DEFAULT_OPTS "" +ENV OTHER_OPTS "" + +# 开放端口 +EXPOSE 22508 + +#设置时区 +RUN echo "Asia/Shanghai" > /etc/timezone; + +# 配置容器启动后执行的命令 +ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -jar /work/tcpserver.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..ef55b7d --- /dev/null +++ b/pom.xml @@ -0,0 +1,129 @@ + + + 4.0.0 + com.dliip + inspect-tcpserver + 1.0.0 + inspect-tcpserver + inspect-tcpserver + + + 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.19 + + + com.alibaba + fastjson + 1.2.73 + + + dom4j + dom4j + 1.6.1 + + + io.netty + netty-all + 4.1.66.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 + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + + 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.tcpserver.TcpserverApplication + + + + repackage + + repackage + + + + + + + + diff --git a/src/main/java/com/inspect/tcpserver/TcpserverApplication.java b/src/main/java/com/inspect/tcpserver/TcpserverApplication.java new file mode 100644 index 0000000..8a6fdb8 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/TcpserverApplication.java @@ -0,0 +1,15 @@ +package com.inspect.tcpserver; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableAsync; + +@SpringBootApplication +@EnableAsync +public class TcpserverApplication { + + public static void main(String[] args) { + SpringApplication.run(TcpserverApplication.class, args); + } + +} diff --git a/src/main/java/com/inspect/tcpserver/cofiguration/ClientStart.java b/src/main/java/com/inspect/tcpserver/cofiguration/ClientStart.java new file mode 100644 index 0000000..a99d148 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/cofiguration/ClientStart.java @@ -0,0 +1,26 @@ +package com.inspect.tcpserver.cofiguration; + +import com.inspect.tcpserver.tcp.NettyClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.Resource; + +@Configuration +@ConditionalOnProperty(name = "boot.client", havingValue = "true") +public class ClientStart implements CommandLineRunner { + + private Logger logger = LoggerFactory.getLogger(ClientStart.class); + + @Resource + NettyClient nettyClient; + + @Override + public void run(String... args) { + + nettyClient.ConnectServer(); + } +} diff --git a/src/main/java/com/inspect/tcpserver/cofiguration/FastJson2JsonRedisSerializer.java b/src/main/java/com/inspect/tcpserver/cofiguration/FastJson2JsonRedisSerializer.java new file mode 100644 index 0000000..c2eb47a --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/cofiguration/FastJson2JsonRedisSerializer.java @@ -0,0 +1,58 @@ +package com.inspect.tcpserver.cofiguration; + +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/tcpserver/cofiguration/ServerStart.java b/src/main/java/com/inspect/tcpserver/cofiguration/ServerStart.java new file mode 100644 index 0000000..bdfda2b --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/cofiguration/ServerStart.java @@ -0,0 +1,25 @@ +package com.inspect.tcpserver.cofiguration; + +import com.inspect.tcpserver.tcp.NettyServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.Resource; + +@ConditionalOnProperty(name = "boot.server", havingValue = "true") +@Configuration +public class ServerStart implements CommandLineRunner { + + private Logger logger = LoggerFactory.getLogger(ServerStart.class); + + @Resource + NettyServer nettyServer; + + @Override + public void run(String... args) throws Exception { + nettyServer.startServer(); + } +} diff --git a/src/main/java/com/inspect/tcpserver/cofiguration/WebConfig.java b/src/main/java/com/inspect/tcpserver/cofiguration/WebConfig.java new file mode 100644 index 0000000..9f858cd --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/cofiguration/WebConfig.java @@ -0,0 +1,94 @@ +package com.inspect.tcpserver.cofiguration; + +import com.inspect.tcpserver.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 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; + +@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) { + RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); + + return rabbitTemplate; + } + + + /** + * 申明交换机 + */ + @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/tcpserver/constant/Constant.java b/src/main/java/com/inspect/tcpserver/constant/Constant.java new file mode 100644 index 0000000..3f2ab1b --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/constant/Constant.java @@ -0,0 +1,24 @@ +package com.inspect.tcpserver.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/tcpserver/controller/ClientController.java b/src/main/java/com/inspect/tcpserver/controller/ClientController.java new file mode 100644 index 0000000..13f6d2e --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/controller/ClientController.java @@ -0,0 +1,68 @@ +package com.inspect.tcpserver.controller; + +import com.alibaba.fastjson.JSONObject; +import com.inspect.tcpserver.domain.AjaxResult; +import com.inspect.tcpserver.tcp.NettyClient; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.UUID; + +@RestController +@RequestMapping("/client") +public class ClientController { + + private Logger logger = LoggerFactory.getLogger(ClientController.class); + + @Resource + NettyClient nettyClient; + + @GetMapping("gray") + public String gray() { + + String uuid = UUID.randomUUID().toString().replaceAll("-", ""); + MDC.put("traceId", uuid); + + logger.info("这是一个来自springboot,logback的info级别的日志"); + logger.warn("这是一条来自springboot,logback的warn级别的日志"); + logger.warn("这是一条来自springboot,logback的warn级别的日志2"); + logger.error("这是一条来自springboot,logback的error级别的日志", new Exception("系统错误")); + return "success"; + } + + /** + * 调用客户端发送消息 + */ + @PostMapping("sendMsg") + public AjaxResult sendMsg(@RequestBody String msg) { + try { + + if (StringUtils.isBlank(msg)) { + return AjaxResult.fail("500", "发送消息msg为空"); + } + + // 此处只是为了判断传入的格式是否正确 + JSONObject jsonObject = JSONObject.parseObject(msg); + + if (null == jsonObject) { + return AjaxResult.fail("500", "发送消息json对象为空"); + } + + logger.info("巡视主机客户端接收到消息,发送到上级。{}", msg); + msg = msg.replaceAll("sendCode", "SendCode"); + msg = msg.replaceAll("receiveCode", "ReceiveCode"); + msg = msg.replaceAll("type", "Type"); + nettyClient.sendJsonMessage(msg); + + return AjaxResult.success(); + } catch (Exception e) { + logger.error("客户端发送消息捕获异常", e); + return AjaxResult.fail(500, "数据格式不正确"); + } + } + +} diff --git a/src/main/java/com/inspect/tcpserver/controller/DeviceServerController.java b/src/main/java/com/inspect/tcpserver/controller/DeviceServerController.java new file mode 100644 index 0000000..a9b1e89 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/controller/DeviceServerController.java @@ -0,0 +1,61 @@ +package com.inspect.tcpserver.controller; + +import com.alibaba.fastjson.JSONObject; +import com.inspect.tcpserver.domain.AjaxResult; +import com.inspect.tcpserver.domain.DeviceServerProperties; +import com.inspect.tcpserver.tcp.NettyServer; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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; + +@RestController +@RequestMapping("/deviceServer") +public class DeviceServerController { + + @Resource + NettyServer server; + + private Logger logger = LoggerFactory.getLogger(DeviceServerController.class); + + @Resource + DeviceServerProperties deviceServerProperties; + + /** + * 下发命令到设备端 + */ + @PostMapping("/sendCommand") + public AjaxResult sendCommand(@RequestBody String json) { + + try { + + logger.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)) { + logger.error("SendCoded或ReceiveCode为空"); + return AjaxResult.fail(500, "SendCoded或ReceiveCode为空"); + } else { + server.SendXmlMessage(jsonObject);// to device + return AjaxResult.success(); + } + + } catch (Exception e) { + logger.error("设备接入服务,处理命令下发捕获异常", e); + return AjaxResult.fail(500); + } + + + } + +} diff --git a/src/main/java/com/inspect/tcpserver/domain/AjaxResult.java b/src/main/java/com/inspect/tcpserver/domain/AjaxResult.java new file mode 100644 index 0000000..3560283 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/domain/AjaxResult.java @@ -0,0 +1,84 @@ +package com.inspect.tcpserver.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/tcpserver/domain/DeviceServerProperties.java b/src/main/java/com/inspect/tcpserver/domain/DeviceServerProperties.java new file mode 100644 index 0000000..753fe88 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/domain/DeviceServerProperties.java @@ -0,0 +1,30 @@ +package com.inspect.tcpserver.domain; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +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/tcpserver/domain/HttpStatus.java b/src/main/java/com/inspect/tcpserver/domain/HttpStatus.java new file mode 100644 index 0000000..ba6a2e7 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/domain/HttpStatus.java @@ -0,0 +1,83 @@ +package com.inspect.tcpserver.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/tcpserver/domain/Result.java b/src/main/java/com/inspect/tcpserver/domain/Result.java new file mode 100644 index 0000000..eb657e3 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/domain/Result.java @@ -0,0 +1,34 @@ +package com.inspect.tcpserver.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/tcpserver/domain/UpSystemServerProperties.java b/src/main/java/com/inspect/tcpserver/domain/UpSystemServerProperties.java new file mode 100644 index 0000000..862fb2c --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/domain/UpSystemServerProperties.java @@ -0,0 +1,23 @@ +package com.inspect.tcpserver.domain; + +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/tcpserver/tcp/BaseControl.java b/src/main/java/com/inspect/tcpserver/tcp/BaseControl.java new file mode 100644 index 0000000..52d5f70 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/tcp/BaseControl.java @@ -0,0 +1,560 @@ +package com.inspect.tcpserver.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 LendonTaskControl extends BaseControl { + public List Items; +} + +//联动任务下发 +@XStreamAlias("Item") +class LendonTaskModel { + @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 PatrolDeviceRuningControl extends BaseControl { + public List Items; +} + +//巡视设备运行数据 +@XStreamAlias("Item") +class PatrolDeviceRuningModel { + @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 NestRuningControl extends BaseControl { + public List Items; +} + +//无人机机巢运行数据 +@XStreamAlias("Item") +class NestRuningModel { + @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/tcpserver/tcp/BinaryModel.java b/src/main/java/com/inspect/tcpserver/tcp/BinaryModel.java new file mode 100644 index 0000000..869d6b6 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/tcp/BinaryModel.java @@ -0,0 +1,12 @@ +package com.inspect.tcpserver.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; +} diff --git a/src/main/java/com/inspect/tcpserver/tcp/ByteUtils.java b/src/main/java/com/inspect/tcpserver/tcp/ByteUtils.java new file mode 100644 index 0000000..3f8a5ad --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/tcp/ByteUtils.java @@ -0,0 +1,258 @@ +package com.inspect.tcpserver.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/tcpserver/tcp/CommonUtils.java b/src/main/java/com/inspect/tcpserver/tcp/CommonUtils.java new file mode 100644 index 0000000..8fe46b6 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/tcp/CommonUtils.java @@ -0,0 +1,13 @@ +package com.inspect.tcpserver.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/tcpserver/tcp/ConnectionListener.java b/src/main/java/com/inspect/tcpserver/tcp/ConnectionListener.java new file mode 100644 index 0000000..a7b6dea --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/tcp/ConnectionListener.java @@ -0,0 +1,29 @@ +package com.inspect.tcpserver.tcp; + +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.EventLoop; + +import java.util.concurrent.TimeUnit; + + +public class ConnectionListener implements ChannelFutureListener { + private NettyClient nettyClient; + + public ConnectionListener(NettyClient nettyClient) { + this.nettyClient = nettyClient; + } + + @Override + public void operationComplete(ChannelFuture channelFuture) throws Exception { + if (!channelFuture.isSuccess()) { + final EventLoop loop = channelFuture.channel().eventLoop(); + loop.schedule(new Runnable() { + @Override + public void run() { + nettyClient.ConnectServer(); + } + }, 3L, TimeUnit.SECONDS); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/inspect/tcpserver/tcp/DownXml2Json.java b/src/main/java/com/inspect/tcpserver/tcp/DownXml2Json.java new file mode 100644 index 0000000..145158a --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/tcp/DownXml2Json.java @@ -0,0 +1,248 @@ +package com.inspect.tcpserver.tcp; + +import com.alibaba.fastjson.JSON; +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; + +public class DownXml2Json { + + /** + * 默认为对上级的客户端的别名 + */ + private String alias; + + public DownXml2Json(String alias) { + this.alias = alias; + } + + + //任务下发 + public String TaskSendControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + 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 LendonTaskControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, LendonTaskControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + LendonTaskControl obj = (LendonTaskControl) 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 PatrolDeviceRuningControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, PatrolDeviceRuningControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + PatrolDeviceRuningControl obj = (PatrolDeviceRuningControl) 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 NestRuningControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, NestRuningControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + NestRuningControl obj = (NestRuningControl) 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); + 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/tcpserver/tcp/MyDecoder.java b/src/main/java/com/inspect/tcpserver/tcp/MyDecoder.java new file mode 100644 index 0000000..2e2fb29 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/tcp/MyDecoder.java @@ -0,0 +1,61 @@ +package com.inspect.tcpserver.tcp; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + +import java.util.List; + +public class MyDecoder extends ByteToMessageDecoder { + + private final String PACKET_FLAG = "EB90"; + + private final int BASE_LENGTH = 2 + 8 + 8 + 1 + 4 + 2; + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + if (in.readableBytes() >= BASE_LENGTH) { + //skip + if (in.readableBytes() > 512 * 1024) { + in.skipBytes(in.readableBytes()); + } + int index; + String flag; + while (true) { + index = in.readerIndex(); + in.markReaderIndex(); + byte[] dst = new byte[2]; + in.readBytes(dst, 0, 2); + flag = ByteUtils.byte2Hex(dst); + if (PACKET_FLAG.equalsIgnoreCase(flag)) { + break; + } + in.resetReaderIndex(); + if (in.readableBytes() < BASE_LENGTH) { + return; + } + } + long sendIndex = in.readLongLE(); + long receiveIndex = in.readLongLE(); + byte sourceFlag = in.readByte(); + int xmlLength = in.readIntLE(); +// int readableBytes = in.readableBytes(); +// if(readableBytes redisTemplate; + + @Value("${iip_server.send.url}") + String iipSendUrl; + + @Value("${up_time_interval_setting}") + String upTimeIntervalSetting; + + /** + * 接收/发送报文xml外层别名 + */ + private String alias = "PatrolHost"; + /** + * 设备层需要的编码,上报或下发的时候转 + */ + private String deviceAlias = "PatrolDevice"; + + public NettyClient() { + up = new UpJson2Xml(alias); + down = new DownXml2Json(alias); + } + + //释放资源 + public void Close() { + if (eventLoopGroup != null) { + eventLoopGroup.shutdownGracefully(); + } + scheduledExecutor.shutdown(); + } + + //连接服务器 + @Async + public void ConnectServer() { + this.serverIP = upSystemServerProperties.ip; + this.serverPort = upSystemServerProperties.port; + this.sendCode = upSystemServerProperties.iipCode; + this.receiveCode = upSystemServerProperties.upCode; + + try { + // 客户端启动对象 + Bootstrap bootstrap = new Bootstrap(); + // 设置相关参数 + bootstrap.group(eventLoopGroup); + bootstrap.channel(NioSocketChannel.class); + bootstrap.option(ChannelOption.TCP_NODELAY, true); + bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000); + bootstrap.option(ChannelOption.SO_KEEPALIVE, true); + bootstrap.handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + client = new NettyClientHandler(NettyClient.this); + ch.pipeline().addLast(new MyDecoder()); + ch.pipeline().addLast(client); + } + }); + + // 开始连接服务器, 并进行同步操作 + // ChannelFuture 类分析 , Netty 异步模型 + // sync 作用是该方法不会再次阻塞 + ChannelFuture channelFuture = bootstrap.connect(serverIP, serverPort).addListener(new ConnectionListener(this)).sync(); + logger.info("nettyClient连接服务器成功"); + // 关闭通道, 开始监听 + channelFuture.channel().closeFuture().sync(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + //发送消息 + public void SendMsg(boolean request, String xml) { + if (client != null && !StringUtil.isNullOrEmpty(xml)) { + ByteBuf byteBuf = Unpooled.copiedBuffer(xml, CharsetUtil.UTF_8); + int length = byteBuf.readableBytes(); + ByteBuf allBuf = Unpooled.buffer(length + ConfigType.dataLegth); + 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(this.sendIndex), allBuf.toString(CharsetUtil.US_ASCII), 60L, TimeUnit.SECONDS); + + client.sendMsg(allBuf); + this.sendIndex++; + } else { + logger.warn("与上级系统连接失败"); + } + } + + //重新发送 + public void resetSendMsg(long sendIndex) { + if (client != null) { + // 获取缓存的中的值 + String msg = redisTemplate.opsForValue().get(String.valueOf(sendIndex)); + + if (!StringUtil.isNullOrEmpty(msg)) { + ByteBuf allBuf = Unpooled.copiedBuffer(msg, CharsetUtil.US_ASCII); + client.sendMsg(allBuf); + } + } + } + + //线程处理接收函数 + public void ReceiveMsg(BinaryModel binaryModel) { + executorService.execute(() -> + { + try { + ThreadDealMsg(binaryModel); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } + + //处理接收消息 + private void ThreadDealMsg(BinaryModel binaryModel) throws DocumentException { + String xml = binaryModel.dataBuf.toString(CharsetUtil.UTF_8); + logger.info("收到上级系统消息:{}", xml); + this.receiveIndex = binaryModel.sendIndex; + SAXReader saxReader = new SAXReader(); + Document document = saxReader.read(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))); + Element root = document.getRootElement(); + 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()); + } + if (type == SystemType.system) { + if (command == SystemType.no_response || command == SystemType.has_response) { + if (null != root.element("Code")) { + if (root.element("Code").getText() == ResponseType.retry) { + resetSendMsg(binaryModel.receiveIndex); + } + } + } + } + // 发送给上级的响应 + String response = ""; + String json = null; + switch (type) { + case SystemType.system: + switch (command) { + case SystemType.has_response: + dealRegister(xml); + break; + case SystemType.no_response: + //心跳处理 + break; + } + break; + case RobotType.robotVl: + case RobotType.robot: + case RobotType.robotCar: + case RobotType.robotFz: + case RobotType.robotIr: + case RobotType.robotPtz: + json = down.RobotControlXml2Json(xml); + break; + case UAVType.uav: + case UAVType.uavXj: + case UAVType.uavKz: + case UAVType.uavYt: + case UAVType.nest: + json = down.UavControlXml2Json(xml); + break; + case TaskType.taskControl: + json = down.BaseControlXml2Json(xml); + break; + case TaskType.taskSend: + json = down.TaskSendControlXml2Json(xml); + break; + case TaskType.lendonTask: + json = down.LendonTaskControlXml2Json(xml); + break; + case TaskType.taskArea: + json = down.AreaControlXml2Json(xml); + break; + case ModelType.modelSync: + json = down.BaseControlXml2Json(xml); + break; + case QueryType.queryResult: + json = down.ResultControlXml2Json(xml); + break; + default: + logger.warn("client-handle-接收到的type:{},不在处理范围内,不予处理", type); + } + + // 将上级下发的指令,转发到业务端处理,接收业务端处理后的结果,上报给上级系统 + if (type != SystemType.system && !StringUtil.isNullOrEmpty(json)) { + + //调用业务端处理 + ResponseEntity ajaxResultResponseEntity = restTemplate.postForEntity(iipSendUrl, json, com.inspect.tcpserver.domain.Result.class); + HttpStatus statusCode = ajaxResultResponseEntity.getStatusCode(); + + if (statusCode.equals(HttpStatus.OK)) { + // 调用业务端处理成功 + Result body = ajaxResultResponseEntity.getBody(); + + if (null == body) { + logger.error("接收上级系统下发的指令,转发到应用业务端处理后,返回的响应体为空"); + return; + } + + String bodyCode = body.getCode(); + String msg = body.getMsg(); + String data = body.getData(); + + logger.info("接收到上级系统下发指令,转发到巡视主机,成功,返回code:{},msg:{},data:{}", bodyCode, msg, data); + + // 响应巡视主机 + JSONObject item = JSONObject.parseObject(data); + response = createDownResponse(item); + + } else { + // 调用业务端处理失败 + logger.warn("下发指令,失败,httpCode:{}", statusCode); + response = createDownFailResponse(); + + } + + // 将xml消息转为json格式字符串 + String msg = up.ModelJson2Xml(response); + + // 上报上级系统,会话类型为响应 + SendMsg(false, msg); + } + } + + //处理注册应答 + public void dealRegister(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, RegisterResponseControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + RegisterResponseControl obj = (RegisterResponseControl) xStream.fromXML(xml); + TimerSendControl(obj); + + logger.info("客户端 接收到服务端注册回馈,服务注册完成"); + } + + //处理心跳 + public void TimerSendControl(RegisterResponseControl response) { + try { + if (response.Code.equals(ResponseType.succeed)) { + int heart = Integer.parseInt(response.Items.get(0).heart_beat_interval); + int patroldevice = Integer.parseInt(response.Items.get(0).patroldevice_run_interval); + int nest = Integer.parseInt(response.Items.get(0).nest_run_interval); + int weather = Integer.parseInt(response.Items.get(0).weather_interval); + SendHeart(); + // 定时心跳报活 + scheduledExecutor.scheduleWithFixedDelay(new TimerTask() { + @Override + public void run() { + SendHeart(); + } + }, 0, heart, TimeUnit.SECONDS); + + + // 上级系统返回的定时信息存入redis + cacheTimeInterval(heart, patroldevice, nest, weather); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 缓存上级系统返回的定时任务间隔 + * + * @param heart + * @param patroldevice + * @param nest + * @param weather + */ + private void cacheTimeInterval(int heart, int patroldevice, int nest, int weather) { + JSONObject json = new JSONObject(); + json.put("heart", heart); + json.put("patroldevice", patroldevice); + json.put("nest", nest); + json.put("weather", weather); + + redisTemplate.opsForValue().set(upTimeIntervalSetting, json.toJSONString()); + } + + private String createRegHeart(boolean isheart) { + ResponseControl obj = new ResponseControl(); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, ResponseControl.class); + obj.SendCode = sendCode; + obj.ReceiveCode = receiveCode; + obj.Type = String.valueOf(SystemType.system); + obj.Code = ""; + obj.Command = String.valueOf(isheart ? SystemType.heart_request : SystemType.register_request); + obj.Time = CommonUtils.GetNowDateString(); + obj.Items = ""; + String resultXML = xStream.toXML(obj); + return resultXML; + } + + /** + * 创建下发失败指令返回 + * + * @param + * @return + */ + private String createDownFailResponse() { + JSONObject object = new JSONObject(); + object.put("SendCode", sendCode); + object.put("ReceiveCode", receiveCode); + object.put("Type", SystemType.system); + object.put("Code", ResponseType.fault); + object.put("Command", SystemType.no_response); + JSONArray jsonArray = new JSONArray(); + object.put("Items", jsonArray); + object.put("Time", CommonUtils.GetNowDateString()); + return object.toString(); + } + + /** + * 创建下发成功指令返回 + * + * @param + * @return + */ + private String createDownResponse(JSONObject item) { + JSONObject object = new JSONObject(); + object.put("SendCode", sendCode); + object.put("ReceiveCode", receiveCode); + object.put("Type", SystemType.system); + object.put("Code", ResponseType.succeed); + + if (null == item) { + object.put("Command", SystemType.no_response); + JSONArray jsonArray = new JSONArray(); + object.put("Items", jsonArray); + } else { + object.put("Command", SystemType.has_response); + JSONArray jsonArray = new JSONArray(); + jsonArray.add(item); + object.put("Items", jsonArray); + } + object.put("Time", CommonUtils.GetNowDateString()); + return object.toString(); + } + + public void SendRegister() { + String xml = createRegHeart(false); + SendMsg(true, xml); + } + + public void SendHeart() { + String xml = createRegHeart(true); + SendMsg(true, xml); + } + + + /** + * 处理身份 + * 处理sendcode 为本机 + * receiveCode 为无人机或机器人处理系统 + * + * @return + */ + public JSONObject handleIdentity(JSONObject obj) { + // 从服务端发出的请求,sendcode 应为服务端 + obj.put("SendCode", sendCode); + obj.put("ReceiveCode", receiveCode); + + return obj; + } + + /** + * 发送消息 + * + * @param json + */ + public void sendJsonMessage(String json) { + JSONObject obj = JSONObject.parseObject(json); + if (obj != null) { + // 处理身份 + obj = handleIdentity(obj); + json = obj.toJSONString(); + int type = Integer.parseInt(obj.get("Type").toString()); + String xml = null; + switch (type) { + case PushType.environment: + xml = up.EnvironmentControlJson2Xml(json); + logger.info("向上级系统发送环境数据。{}", xml); + break; + case PushType.alarm: + xml = up.AlarmControlJson2Xml(json); + logger.info("向上级系统发送巡视设备异常告警数据。{}", xml); + break; + case PushType.analysisAlarm: + xml = up.AnalysisControlJson2Xml(json); + logger.info("向上级系统发送告警数据。{}", xml); + break; + case PushType.location: + xml = up.LocationControlJson2Xml(json); + logger.info("向上级系统发送巡视设备坐标。{}", xml); + break; + case PushType.monitor: + xml = up.MonitorControlJson2Xml(json); + logger.info("向上级系统发送静默监视告警数据。{}", xml); + break; + case PushType.nestRuning: + xml = up.NestRuningJson2Xml(json); + logger.info("向上级系统发送无人机机巢运行数据。{}", xml); + break; + case PushType.nestState: + xml = up.NestStateJson2Xml(json); + logger.info("向上级系统发送无人机机巢状态数据。{}", xml); + break; + case PushType.patrolDeviceState: + xml = up.PatrolDeviceStateControlJson2Xml(json); + logger.info("向上级系统发送巡视设备状态数据。{}", xml); + break; + case PushType.patrolDeviceRuning: + xml = up.PatrolDeviceRuningControlJson2Xml(json); + logger.info("向上级系统发送巡视设备运行数据。{}", xml); + break; + case PushType.result: + xml = up.TaskResultControlJson2Xml(json); + logger.info("向上级系统发送巡视结果。{}", xml); + break; + case PushType.taskState: + xml = up.TaskStateControlJson2Xml(json); + logger.info("向上级系统发送任务状态数据。{}", xml); + break; + case PushType.total: + xml = up.ReportControlJson2Xml(json); + logger.info("向上级系统发送巡视设备统计信息上报。{}", xml); + break; + case PushType.route: + xml = up.RouteControlJson2Xml(json); + logger.info("向上级系统发送巡视路线。{}", xml); + break; + case SystemType.system: + xml = up.ModelJson2Xml(json); + logger.info("向上级系统发送系统数据。{}", xml); + break; + case ModelType.modelUpdate: + xml = up.UpdateModelJson2Xml(json); + //xml = up.ModelJson2Xml(json, UpdateModelControl.class); + logger.info("向上级系统发送模型更新上报指令。{}", xml); + break; + default: + logger.warn("应用向上级系统发送消息,type:{}不在处理范围内,不予处理", type); + } + if (!StringUtils.isEmpty(xml)) { + // 将设备别名转换为上级别名 + xml = xml.replaceAll(deviceAlias, alias); + SendMsg(true, xml); + } + } + } +} diff --git a/src/main/java/com/inspect/tcpserver/tcp/NettyClientHandler.java b/src/main/java/com/inspect/tcpserver/tcp/NettyClientHandler.java new file mode 100644 index 0000000..60b987d --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/tcp/NettyClientHandler.java @@ -0,0 +1,97 @@ +package com.inspect.tcpserver.tcp; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.EventLoop; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.TimeUnit; + +/** + * Handler 处理者, 是 NioEventLoop 线程中处理业务逻辑的类 + *

+ * 继承 : 该业务逻辑处理者 ( Handler ) 必须继承 Netty 中的 ChannelInboundHandlerAdapter 类 + * 才可以设置给 NioEventLoop 线程 + *

+ * 规范 : 该 Handler 类中需要按照业务逻辑处理规范进行开发 + */ +public class NettyClientHandler extends ChannelInboundHandlerAdapter { + + private Logger logger = LoggerFactory.getLogger(NettyClientHandler.class); + + private NettyClient nettyClient; + + public ChannelHandlerContext Context; + + public NettyClientHandler(NettyClient nettyClient) { + this.nettyClient = nettyClient; + } + + public void sendMsg(ByteBuf byteBuf) { + if (Context != null) { + Context.writeAndFlush(byteBuf); + } else { + logger.info("client发送消息时,content为空,未连接服务端,取消发送"); + } + } + + // channel 处于不活动状态时调用 + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + final EventLoop loop = ctx.channel().eventLoop(); + loop.schedule(new Runnable() { + @Override + public void run() { + nettyClient.ConnectServer(); + } + }, 3L, TimeUnit.SECONDS); + super.channelInactive(ctx); + } + + /** + * 当客户端连接服务器完成就会触发该方法 + * + * @param ctx + * @throws Exception + */ + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + Context = ctx; + + try { + nettyClient.SendRegister(); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + /** + * 读取数据 : 在服务器端读取客户端发送的数据 + * + * @param ctx 通道处理者上下文对象 : 封装了 管道 ( Pipeline ) , 通道 ( Channel ), 客户端地址信息 + * 管道 ( Pipeline ) : 注重业务逻辑处理 , 可以关联很多 Handler + * 通道 ( Channel ) : 注重数据读写 + * @param msg 服务器返回的数据 + * @throws Exception + */ + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + nettyClient.ReceiveMsg((BinaryModel) msg); + } + + /** + * 异常处理 , 上面的方法中都抛出了 Exception 异常, 在该方法中进行异常处理 + * + * @param ctx + * @param cause + * @throws Exception + */ + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + //如果出现异常, 就关闭该通道 + ctx.close(); + } +} \ No newline at end of file diff --git a/src/main/java/com/inspect/tcpserver/tcp/NettyServer.java b/src/main/java/com/inspect/tcpserver/tcp/NettyServer.java new file mode 100644 index 0000000..6086125 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/tcp/NettyServer.java @@ -0,0 +1,491 @@ +package com.inspect.tcpserver.tcp; + +import com.alibaba.fastjson.JSONObject; +import com.inspect.tcpserver.constant.Constant; +import com.inspect.tcpserver.controller.ClientController; +import com.inspect.tcpserver.domain.DeviceServerProperties; +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.util.CharsetUtil; +import io.netty.util.internal.StringUtil; +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 org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.*; + +/** + * @author yww + *

+ * 服务启动监听器 + **/ +@Component +public class NettyServer { + private Logger logger = LoggerFactory.getLogger(NettyServer.class); + + /** + * 接收/发送报文xml外层别名 + */ + private String alias = "PatrolDevice"; + + @Resource + ClientController clientController; + + + private EventLoopGroup bossGroup; + private EventLoopGroup workGroup; + private Map clients = new HashMap<>(); //机器人id,通道id + private long sendIndex = 0; //若重启系统后还要延续之前的序列号则需要把序列号存入redis中 + private long receiveIndex = 0; + private DownXml2Json down = new DownXml2Json(alias); + private UpJson2Xml up = new UpJson2Xml(alias); + private NettyServerHandler nettyServerHandler; + private ExecutorService executorService = new ThreadPoolExecutor(1, 10, 5L, TimeUnit.SECONDS, new ArrayBlockingQueue(4), Executors.defaultThreadFactory()); + + @Resource + DeviceServerProperties deviceServerProperties; + + @Resource + private RedisTemplate redisTemplate; + + @Resource + private RestTemplate restTemplate; + + @Resource + private RabbitTemplate rabbitTemplate; + + @Value("${iip_server.authDevice.url}") + String iipAuthDeviceUrl; + + + private String serverIP; + private int serverPort; + + private int num = 410; + + public void init() { + this.serverIP = deviceServerProperties.ip; + this.serverPort = deviceServerProperties.port; + up = new UpJson2Xml(alias); + down = new DownXml2Json(alias); + } + + @Async + public void startServer() { + // 初始化 + init(); + + //new 一个主线程组 + bossGroup = new NioEventLoopGroup(1); + //new 一个工作线程组 + workGroup = new NioEventLoopGroup(10); + ServerBootstrap bootstrap = new ServerBootstrap() + .group(bossGroup, workGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast(new MyDecoder()); + nettyServerHandler = new NettyServerHandler(NettyServer.this); + ch.pipeline().addLast(nettyServerHandler); + } + }) + .localAddress(serverPort) + //设置队列大小 + .option(ChannelOption.SO_BACKLOG, 1024) + // 两小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文 + .childOption(ChannelOption.SO_KEEPALIVE, true); + //绑定端口,开始接收进来的连接 + try { + ChannelFuture future = bootstrap.bind(serverPort).sync(); + logger.info("nettyServer启动"); + future.channel().closeFuture().sync(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + close(); + } + } + + //释放资源 + public void close() { + if (bossGroup != null) { + bossGroup.shutdownGracefully(); + } + if (workGroup != null) { + workGroup.shutdownGracefully(); + } + } + + //发送消息 + public void SendMsg(String client, boolean request, String xml) { + logger.info("==========client===========" + client + "是否在线=" + clients.containsKey(client)); + if (clients.containsKey(client) && !StringUtil.isNullOrEmpty(xml)) { + ByteBuf byteBuf = Unpooled.copiedBuffer(xml, CharsetUtil.UTF_8); + int length = byteBuf.readableBytes(); + ByteBuf allBuf = Unpooled.buffer(length + ConfigType.dataLegth); + 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(this.sendIndex), allBuf.toString(CharsetUtil.US_ASCII), 60L, TimeUnit.SECONDS); + nettyServerHandler.SendMsg(clients.get(client), allBuf); + logger.info("发送到机器人发送会话序列号:{},接收会话序列号:{}", sendIndex, receiveIndex); + this.sendIndex++; + } else { + logger.warn("设备接入层下发消息时,设备不在线"); + } + } + + //开启线程处理消息 + public void ReceiveMsg(BinaryModel binaryModel) { + executorService.execute(() -> + { + try { + ThreadDealMsg(binaryModel); + } catch (Exception e) { + e.printStackTrace(); + } + }); + } + + //重新发送 + 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); + SendMsg(sendCode, true, msg); + } + } + + //处理接收消息 + private void ThreadDealMsg(BinaryModel binaryModel) throws DocumentException { + String xml = binaryModel.dataBuf.toString(CharsetUtil.UTF_8); + logger.info("接收到机器人发送会话序列号:{},接收会话序列号:{}", binaryModel.sendIndex, binaryModel.receiveIndex); + this.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(); + clients.put(sendCode, binaryModel.id);//按照正常得逻辑是注册成功后在添加进关系中 + 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()); + } + //判断是否重发 + if (type == SystemType.system) { + if (command == SystemType.has_response || command == SystemType.no_response) { + if (null != root.element("Code")) { + if (root.element("Code").getText() == ResponseType.retry) { + resetSendMsg(binaryModel.receiveIndex, sendCode); + } + } + } + } + String json = null; + switch (type) { + case SystemType.system: + switch (command) { + case SystemType.register_request: + // 处理注册请求响应 + logger.info("收到接入侧注册信息:{}", xml); + dealRegister(xml); + logger.info("收到接入侧注册信息:{}", xml); + break; + case SystemType.heart_request: + // 处理心跳请求响应 + logger.info("收到接入侧心跳信息:{}", xml); + SendHeart(xml); + 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")) { + logger.info("收到接入侧模型同步数据:{}", xml); + json = down.ModelControlXml2Json(xml); + JSONObject jsonObject = JSONObject.parseObject(json); + 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")) { + logger.info("收到接入侧任务下发或控制回复数据:{}", xml); + json = down.ModelControlXml2Json(xml); + JSONObject jsonObject = JSONObject.parseObject(json); + jsonObject.put("SendCode", ""); + jsonObject.put("SendCode", ""); + clientController.sendMsg(jsonObject.toJSONString()); + } + } else { + logger.warn("接收到的系统类信息报文中,root:{},中不包含items或items中没有item,不予处理", root); + } + break; + default: + logger.warn("不予处理的消息体,{}", xml); + logger.warn("接收到的系统类信息报文中,command:{},不在处理范围内,不予处理", command); + } + break; + case PushType.patrolDeviceState: + json = down.PatrolDeviceStateControlXml2Json(xml); + logger.info("收到接入侧设备状态数据:{}", xml); + break; + case PushType.patrolDeviceRuning: + json = down.PatrolDeviceRuningControlXml2Json(xml); + logger.info("收到接入侧设备运行数据:{}", xml); + break; + case PushType.nestState: + json = down.NestStateControlXml2Json(xml); + logger.info("收到接入侧机巢状态数据{}", xml); + break; + case PushType.nestRuning: + json = down.NestRuningControlXml2Json(xml); + logger.info("收到接入侧机巢运行数据{}", xml); + break; + case PushType.location: + json = down.LocationControlXml2Json(xml); + logger.info("收到接入侧设备坐标{}", xml); + break; + case PushType.route: + json = down.RouteControlXml2Json(xml); + logger.info("收到接入侧设备路线{}", xml); + break; + case PushType.alarm: + json = down.AlarmControlXml2Json(xml); + logger.info("收到接入侧设备异常告警{}", xml); + break; + case PushType.environment: + json = down.EnvironmentControlXml2Json(xml); + logger.info("收到接入侧设备上报环境数据{}", xml); + break; + case PushType.taskState: + json = down.TaskStateControlXml2Json(xml); + logger.info("收到接入侧设备任务状态{}", xml); + break; + case PushType.result: + json = down.TaskResultControlXml2Json(xml); + logger.info("收到接入侧巡视结果{}", xml); + break; + default: + logger.warn("不予处理的消息体,{}", xml); + logger.warn("server-handle-接收到的type:{},不在处理范围内,不予处理", type); + } + if (type != SystemType.system && !StringUtil.isNullOrEmpty(json)) { + //rabbitmq推送到消息队列中基于springboot_xggd + rabbitTemplate.convertAndSend(Constant.EX_CHANGE_NAME, Constant.ROUTING_KEY_NAME, json); + String receiveCode = root.element("ReceiveCode").getText(); + ResponseMsg(receiveCode, sendCode); + } + } + + public void ResponseMsg(String sendCode, String receiveCode) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, 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); + SendMsg(receiveCode, false, xml); + } + + //处理注册应答 + public void dealRegister(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + //xStream.alias(alias,BaseControl.class); + xStream.alias("PatrolHost", BaseControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + BaseControl obj = (BaseControl) xStream.fromXML(xml); + 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)) { + //鉴权通过_xggd + 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("patroldevice_code", obj.SendCode); + jsonObject.put("Type", "heartbeat"); + jsonObject.put("eventType", "connect"); + jsonObject.put("heart_beat_interval", ConfigType.heart_beat_interval); + + rabbitTemplate.convertAndSend(Constant.EX_CHANGE_NAME, Constant.ROUTING_KEY_NAME, jsonObject.toJSONString()); + } else { + // 鉴权不通过 + responseControl.Code = ResponseType.fault; + } + SendRegisterResponse(responseControl, obj.SendCode); + } + + /** + * 鉴权巡视设备 + * + * @param sendCode 巡视设备(机器人、无人机)唯一标识 + * @return + */ + public boolean authDevice(String sendCode) { +// // 调用基础服务的鉴权巡视设备接口 +// String url = String.format(iipAuthDeviceUrl,sendCode); +// +// String resultString = restTemplate.getForObject(url,String.class); +// +// Result result = JSONObject.parseObject(resultString, Result.class); +// +// // 判断鉴权结果 +// if(StringUtils.equals(result.getCode(),"200")){ +// logger.info("设备鉴权成功,result:{}",result); +// return true; +// } +// +// logger.warn("设备鉴权失败 sendCode:{},resutl:{}",sendCode,result); +// return false; + + return true; + } + + + public void SendRegisterResponse(RegisterResponseControl responseControl, String sendCode) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, RegisterResponseControl.class); + xStream.autodetectAnnotations(true); + String xml = xStream.toXML(responseControl); + SendMsg(sendCode, false, xml); + } + + public void SendHeart(String xml) { + logger.info("接收到机器人巡视系统心跳消息:{}", 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); + ResponseMsg(obj.ReceiveCode, obj.SendCode); + + // 推送消息到mq + JSONObject jsonObject = new JSONObject(); + jsonObject.put("SendCode", obj.SendCode); + jsonObject.put("Type", "heartbeat"); + jsonObject.put("eventType", "heart"); + jsonObject.put("heart_beat_interval", ConfigType.heart_beat_interval); + + rabbitTemplate.convertAndSend(Constant.EX_CHANGE_NAME, Constant.ROUTING_KEY_NAME, jsonObject.toJSONString()); + } + + /** + * 判断机器人是否在线 + */ + public boolean isOnline(String code) { + return clients.containsKey(code); + } + + 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 = up.RobotJson2Xml(json); + break; + case UAVType.uav: + case UAVType.uavXj: + case UAVType.uavKz: + case UAVType.uavYt: + case UAVType.nest: + xml = up.UavControlJson2Xml(json); + break; + case TaskType.taskControl: + xml = up.ResponseJson2Xml(json); + break; + case TaskType.taskSend: + xml = up.TaskSendJson2Xml(json); + break; + case TaskType.taskArea: + xml = up.AreaJson2Xml(json); + break; + case ModelType.modelSync: + xml = up.ResponseJson2Xml(json); + break; + case TaskType.lendonTask: + xml = up.LendonTaskJson2Xml(json); + break; + default: + logger.warn("应用向设备接入发送消息,type:{}不在处理范围内,不予处理", type); + + } + if (!StringUtils.isEmpty(xml)) { + logger.info("向设备接入侧下发命令:{}", xml); + SendMsg(receiveCode, true, xml); + } + } +} diff --git a/src/main/java/com/inspect/tcpserver/tcp/NettyServerHandler.java b/src/main/java/com/inspect/tcpserver/tcp/NettyServerHandler.java new file mode 100644 index 0000000..7c85884 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/tcp/NettyServerHandler.java @@ -0,0 +1,83 @@ +package com.inspect.tcpserver.tcp; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author yww + *

+ * netty服务端处理器 + **/ + +public class NettyServerHandler extends ChannelInboundHandlerAdapter { + public Logger logger = LoggerFactory.getLogger(NettyServerHandler.class); + + private NettyServer nettyServer; + private Map ids = new HashMap<>(); + + public NettyServerHandler(NettyServer nettyServer) { + this.nettyServer = nettyServer; + } + + public void SendMsg(String id, ByteBuf byteBuf) { + if (ids.containsKey(id)) { + ids.get(id).writeAndFlush(byteBuf); + } + } + + /** + * 客户端连接会触发 + */ + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + String id = ctx.channel().id().asShortText(); + ids.put(id, ctx); + logger.warn("设备连接,id:{}", id); + } + + /** + * 客户端断开会触发 + */ + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + ctx.close(); + String id = ctx.channel().id().asShortText(); + + logger.warn("设备断开,id:{}", id); + + if (ids.containsKey(id)) { + ids.remove(id); + } + super.channelInactive(ctx); + } + + /** + * 客户端发消息会触发 + */ + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + logger.warn("channelRead!!!"); + String id = ctx.channel().id().asShortText(); + BinaryModel binaryModel = (BinaryModel) msg; + binaryModel.id = id; + nettyServer.ReceiveMsg((BinaryModel) msg); + } + + /** + * 发生异常触发 + */ + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + ctx.close(); + String id = ctx.channel().id().asShortText(); + if (ids.containsKey(id)) { + ids.remove(id); + } + } +} diff --git a/src/main/java/com/inspect/tcpserver/tcp/SystemType.java b/src/main/java/com/inspect/tcpserver/tcp/SystemType.java new file mode 100644 index 0000000..2f48e2b --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/tcp/SystemType.java @@ -0,0 +1,74 @@ +package com.inspect.tcpserver.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 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 patrolDeviceRuning = 2; + public static final int nestState = 20001; + public static final int nestRuning = 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 dataLegth = 25; + public static final String heart_beat_interval = "300"; + 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/tcpserver/tcp/UpJson2Xml.java b/src/main/java/com/inspect/tcpserver/tcp/UpJson2Xml.java new file mode 100644 index 0000000..ccdae6e --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/tcp/UpJson2Xml.java @@ -0,0 +1,268 @@ +package com.inspect.tcpserver.tcp; + +import com.alibaba.fastjson.JSON; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.naming.NoNameCoder; +import com.thoughtworks.xstream.io.xml.Xpp3Driver; + +public class UpJson2Xml +{ + + 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 ModelJson2Xml(String json, Class clazz) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, clazz.getClass()); + + T obj = JSON.parseObject(json,clazz); + return xStream.toXML(obj); + } + + //模型更新上报指令 + 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 LendonTaskJson2Xml(String json) + { + LendonTaskControl obj=JSON.parseObject(json,LendonTaskControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, LendonTaskControl.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 PatrolDeviceRuningControlJson2Xml(String json) + { + PatrolDeviceRuningControl obj=JSON.parseObject(json,PatrolDeviceRuningControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, PatrolDeviceRuningControl.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 NestRuningJson2Xml(String json) + { + NestRuningControl obj=JSON.parseObject(json,NestRuningControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, NestRuningControl.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/tcpserver/util/SpringApplicationContext.java b/src/main/java/com/inspect/tcpserver/util/SpringApplicationContext.java new file mode 100644 index 0000000..8660714 --- /dev/null +++ b/src/main/java/com/inspect/tcpserver/util/SpringApplicationContext.java @@ -0,0 +1,46 @@ +package com.inspect.tcpserver.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..e905c55 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,41 @@ +spring: + application: + name: tcpServer + 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..1ae0f5c --- /dev/null +++ b/src/main/resources/application-prod.yml @@ -0,0 +1,42 @@ +spring: + application: + name: tcpServer + 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.199: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..fcbf90b --- /dev/null +++ b/src/main/resources/application-test.yml @@ -0,0 +1,42 @@ +spring: + application: + name: tcpServer + 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: 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/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..9f96606 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,3 @@ +spring: + profiles: + active: prod diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..63fd431 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,62 @@ + + + + + + + + + ${log.pattern} + + + + + + log/tcpServer.log + + + + log/tcpServer.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + + + + + udp:10.10.18.185 + 12201 + 1.1 + + dliip-device + + version=1.1,module=patrol + true + true + true + yyyy-MM-dd HH:mm:ss,SSS + 8192 + + mdcField1,mdcField2 + mdc.*,(mdc|MDC)fields + true + + + INFO + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/inspect/tcpserver/TcpserverApplicationTests.java b/src/test/java/com/inspect/tcpserver/TcpserverApplicationTests.java new file mode 100644 index 0000000..ebb7c89 --- /dev/null +++ b/src/test/java/com/inspect/tcpserver/TcpserverApplicationTests.java @@ -0,0 +1,13 @@ +package com.inspect.tcpserver; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class TcpserverApplicationTests { + + @Test + void contextLoads() { + } + +}