Browse Source

添加消息系统

master
zhangye 6 years ago
parent
commit
ff6c119a06
  1. 25
      ccmq/.gitignore
  2. BIN
      ccmq/.mvn/wrapper/maven-wrapper.jar
  3. 1
      ccmq/.mvn/wrapper/maven-wrapper.properties
  4. 36
      ccmq/README.en.md
  5. 37
      ccmq/README.md
  6. 286
      ccmq/mvnw
  7. 161
      ccmq/mvnw.cmd
  8. 275
      ccmq/pom.xml
  9. 234
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/ClientManager.java
  10. 366
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/ChannelManager.java
  11. 200
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/WrapperedChannel.java
  12. 115
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcphexserver/ModbusConverter.java
  13. 45
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcphexserver/ModbusDecoder.java
  14. 33
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcphexserver/ModbusEncoder.java
  15. 109
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcphexserver/ModbusHandler.java
  16. 59
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcphexserver/NettyMBServer.java
  17. 61
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcptextserver/NettyTextServer.java
  18. 32
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcptextserver/TextDecoder.java
  19. 49
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcptextserver/TextEncoder.java
  20. 110
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcptextserver/TextHandler.java
  21. 72
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/wsserver/NettyWsServer.java
  22. 33
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/wsserver/WebSocketDecoder.java
  23. 25
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/wsserver/WebSocketEncoder.java
  24. 107
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/wsserver/WebSocketHandler.java
  25. 36
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/rabbitmq/QueueManager.java
  26. 48
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/rabbitmq/RabbitMqListener.java
  27. 28
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/restful/MessageApi.java
  28. 16
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/restful/RestManager.java
  29. 478
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/MessageHandler.java
  30. 31
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/AckMessage.java
  31. 36
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/AuthMessage.java
  32. 16
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/ClientAuthTimeOutMessage.java
  33. 16
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/ClientIdleClosedMessage.java
  34. 16
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/GetStatusMessage.java
  35. 36
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/HasReadMessage.java
  36. 32
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/PingMessage.java
  37. 31
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/SetDeletedStatusMessage.java
  38. 31
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/SetRevertedStatusMessage.java
  39. 31
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/SetSuccessStatusMessage.java
  40. 95
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/InMessage.java
  41. 134
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/Message.java
  42. 217
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/MessageConstant.java
  43. 80
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/MessageRule.java
  44. 71
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/OutMessage.java
  45. 43
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/OutMessageSet.java
  46. 11
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/ServerMessage.java
  47. 37
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/server/ChannelStatusMessage.java
  48. 28
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/server/InvertedMessage.java
  49. 15
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/server/PongMessage.java
  50. 30
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/server/QueueStatusMessage.java
  51. 49
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/server/ServerAckMessage.java
  52. 31
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/server/UnExceptedErrorMessage.java
  53. 118
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/persist/IMessageDao.java
  54. 180
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/persist/MessageDao.java
  55. 9
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/service/IUserService.java
  56. 32
      ccmq/src/main/java/com/ccsens/ccmq/lowlevel/service/UserService.java
  57. 2
      ccmq/src/main/java/lombok.config
  58. 64
      ccmq/src/main/java/wiki/tall/ccmq/common/TallMessageApplication.java
  59. 168
      ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/CCModBusEntity.java
  60. 39
      ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/ChangeBeginTimeProtocol.java
  61. 31
      ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/ChangeDurationProtocol.java
  62. 114
      ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/CommonProtocol.java
  63. 23
      ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/CountdownProtocol.java
  64. 12
      ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/HeartProtocol.java
  65. 16
      ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/JoinProtocol.java
  66. 16
      ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/LoadProtocol.java
  67. 31
      ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/MoveProtocol.java
  68. 29
      ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/PlayProtocol.java
  69. 29
      ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/RemoveProtocol.java
  70. 30
      ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/TimeHeartProtocol.java
  71. 16
      ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/TimingProtocol.java
  72. 108
      ccmq/src/main/java/wiki/tall/ccmq/common/config/DruidProps.java
  73. 44
      ccmq/src/main/java/wiki/tall/ccmq/common/config/EnjoyConfig.java
  74. 71
      ccmq/src/main/java/wiki/tall/ccmq/common/config/ExcepHandler.java
  75. 25
      ccmq/src/main/java/wiki/tall/ccmq/common/config/RabbitMqConfig.java
  76. 39
      ccmq/src/main/java/wiki/tall/ccmq/common/config/RedisConfig.java
  77. 74
      ccmq/src/main/java/wiki/tall/ccmq/common/config/RestClientConfig.java
  78. 123
      ccmq/src/main/java/wiki/tall/ccmq/common/config/ServletConfig.java
  79. 60
      ccmq/src/main/java/wiki/tall/ccmq/common/config/SettingProps.java
  80. 136
      ccmq/src/main/java/wiki/tall/ccmq/common/config/SpringConfig.java
  81. 64
      ccmq/src/main/java/wiki/tall/ccmq/common/config/SwaggerConfigure.java
  82. 29
      ccmq/src/main/java/wiki/tall/ccmq/common/config/TaskExecutorConfig.java
  83. 75
      ccmq/src/main/java/wiki/tall/ccmq/common/controller/interceptor/TokenInterceptor.java
  84. 106
      ccmq/src/main/java/wiki/tall/ccmq/common/controller/web/LearnController.java
  85. 26
      ccmq/src/main/java/wiki/tall/ccmq/common/controller/web/MessageController.java
  86. 17
      ccmq/src/main/java/wiki/tall/ccmq/common/exception/BaseException.java
  87. 50
      ccmq/src/main/java/wiki/tall/ccmq/common/util/BeanWrapperUtil.java
  88. 30
      ccmq/src/main/java/wiki/tall/ccmq/common/util/CRCUtil.java
  89. 41
      ccmq/src/main/java/wiki/tall/ccmq/common/util/CcMessageUtil.java
  90. 15
      ccmq/src/main/java/wiki/tall/ccmq/common/util/DateUtil.java
  91. 285
      ccmq/src/main/java/wiki/tall/ccmq/common/util/GenericsUtils.java
  92. 59
      ccmq/src/main/java/wiki/tall/ccmq/common/util/HttpServletUtil.java
  93. 133
      ccmq/src/main/java/wiki/tall/ccmq/common/util/HttpsClientRequestFactory.java
  94. 256
      ccmq/src/main/java/wiki/tall/ccmq/common/util/HttpsUtil.java
  95. 15
      ccmq/src/main/java/wiki/tall/ccmq/common/util/IDGenerator.java
  96. 13
      ccmq/src/main/java/wiki/tall/ccmq/common/util/ImgUtil.java
  97. 311
      ccmq/src/main/java/wiki/tall/ccmq/common/util/JacksonUtil.java
  98. 42
      ccmq/src/main/java/wiki/tall/ccmq/common/util/JsonPathUtil.java
  99. 158
      ccmq/src/main/java/wiki/tall/ccmq/common/util/JsonResponse.java
  100. 298
      ccmq/src/main/java/wiki/tall/ccmq/common/util/JsonResponse1.java

25
ccmq/.gitignore

@ -0,0 +1,25 @@
/target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

BIN
ccmq/.mvn/wrapper/maven-wrapper.jar

Binary file not shown.

1
ccmq/.mvn/wrapper/maven-wrapper.properties

@ -0,0 +1 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip

36
ccmq/README.en.md

@ -0,0 +1,36 @@
# ccmq
#### Description
MQ(Rest) 2 User(ws,tcp text,tcp hex)
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

37
ccmq/README.md

@ -0,0 +1,37 @@
# ccmq
#### 介绍
MQ(Rest) 2 User(ws,tcp text,tcp hex)
#### 软件架构
软件架构说明
#### 安装教程
1. xxxx
2. xxxx
3. xxxx
#### 使用说明
1. xxxx
2. xxxx
3. xxxx
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
#### 码云特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目
5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

286
ccmq/mvnw

@ -0,0 +1,286 @@
#!/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
#
# http://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.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 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)`"
# TODO classpath?
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
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
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 command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
wget "$jarUrl" -O "$wrapperJarPath"
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
curl -o "$wrapperJarPath" "$jarUrl"
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
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
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 "$@"

161
ccmq/mvnw.cmd

@ -0,0 +1,161 @@
@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 http://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 Maven2 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 key stroke 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 my 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.4.2/maven-wrapper-0.4.2.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% (
echo Found %WRAPPER_JAR%
) else (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
echo Finished downloading %WRAPPER_JAR%
)
@REM End of extension
%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%

275
ccmq/pom.xml

@ -0,0 +1,275 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ccsens</groupId>
<artifactId>tall-message</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>tall-message</name>
<description>Tall Message MicroService</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
<docker.image.prefix>springboot</docker.image.prefix>
</properties>
<dependencies>
<!--<dependency>-->
<!--<groupId>org.springframework.cloud</groupId>-->
<!--<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.springframework.cloud</groupId>-->
<!--<artifactId>spring-cloud-starter-openfeign</artifactId>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.springframework.cloud</groupId>-->
<!--<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- spring Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring RabbitMQ-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- spring MongoDB-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- spring MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!--jfinal enjoy 模板引擎-->
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>enjoy</artifactId>
<version>4.7</version>
</dependency>
<!-- mybatis pagehelper包-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.4</version>
</dependency>
<!--mybatis generator包-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
<!-- MySQL数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--Durid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.1.21</version>
</dependency>
<!--jjwt-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
<!--Jackson Xml-->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.4.0</version>
</dependency>
<!--Shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!--Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.beanshell/bsh -->
<dependency>
<groupId>org.beanshell</groupId>
<artifactId>bsh</artifactId>
<version>2.0b5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.32.Final</version>
</dependency>
<!--Poi Excel -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<configurationFile>${basedir}/src/main/resources/mbg.xml</configurationFile>
<overwrite>true</overwrite>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
</dependencies>
</plugin>
<!-- Docker maven plugin -->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<imageName>${docker.image.prefix}/${project.artifactId}</imageName>
<dockerDirectory>src/main/docker</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
<!-- Docker maven plugin -->
</plugins>
</build>
</project>

234
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/ClientManager.java

@ -0,0 +1,234 @@
package com.ccsens.ccmq.lowlevel.client;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.ccsens.ccmq.lowlevel.client.netty.WrapperedChannel;
import com.ccsens.ccmq.lowlevel.message.MessageHandler;
import com.ccsens.ccmq.lowlevel.message.client.ClientAuthTimeOutMessage;
import com.ccsens.ccmq.lowlevel.message.common.*;
import com.ccsens.ccmq.lowlevel.message.server.ServerAckMessage;
import com.ccsens.ccmq.lowlevel.client.netty.ChannelManager;
import com.ccsens.ccmq.lowlevel.client.rabbitmq.QueueManager;
import com.ccsens.ccmq.lowlevel.client.restful.RestManager;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import wiki.tall.ccmq.common.util.JacksonUtil;
import java.util.Iterator;
import java.util.Map;
import static com.ccsens.ccmq.lowlevel.message.MessageHandler.handleMessage;
/**
* @author __zHangSan
*/
@Component
public class ClientManager {
private static Logger logger = LoggerFactory.getLogger(ClientManager.class);
/**
* 未认证连接存活时间s
*/
private static final Long UnAuthedChannelMaxAliveTimeInSeconds = 30L;
@Scheduled(cron = "0/30 * * * * *")
public void closeUnAuthedChannels() throws Exception{
logger.debug("Invoke closeUnAuthedChannels({})",UnAuthedChannelMaxAliveTimeInSeconds);
Map<Channel, WrapperedChannel> allChannels = ChannelManager.getCopyOfAllChannels();
Iterator<Map.Entry<Channel,WrapperedChannel>> it = allChannels.entrySet().iterator();
while(it.hasNext()){
Map.Entry<Channel,WrapperedChannel> entry = it.next();
WrapperedChannel wrapperedChannel = entry.getValue();
if((!wrapperedChannel.isAuthed()) && (wrapperedChannel.getConnectedSeconds() > UnAuthedChannelMaxAliveTimeInSeconds)) {
//构造AuthTimeOut消息并处理
try {
ChannelManager.setCurrentChannel(wrapperedChannel.getChannel());
MessageHandler.handleMessage(InMessage.newToServerMessage(MessageConstant.DomainType.User,
new ClientAuthTimeOutMessage()));
//close会触发remove
wrapperedChannel.getChannel().close();
logger.debug("Remove a unAuthed Channel {}, which has connected {}s,maxOutTime is {}s",
wrapperedChannel.getId(), wrapperedChannel.getConnectedSeconds(), UnAuthedChannelMaxAliveTimeInSeconds
);
}catch(Exception e){
e.printStackTrace();
logger.error("handle ClientAuthTimeOutMessage error: {}",e.getMessage());
}finally {
ChannelManager.removeCurrentChannel();
}
}
}
}
@Scheduled(cron="*/30 * * * * ?")
public void showChannels(){
logger.debug("----------------- AuthedChannels(" + System.currentTimeMillis()/1000 + ")--------------");
ChannelManager.showAuthedChannels();
logger.debug("----------------- AllChannels -----------------");
ChannelManager.showAllChannels();
logger.debug("------------------End -------------------------");
}
public static InMessage fillMessageInfo(InMessage inMessage, MessageConstant.DomainType fromDomain){
//1. 填充from、toDomain、Rule
switch (fromDomain){
case User: {
//1.填充Message from信息
inMessage.setFromDomain(MessageConstant.DomainType.User);
inMessage.setFrom(ChannelManager.getUserIdByChannel(ChannelManager.getCurrentChannel()));
//2.填充Message to信息
if (null == inMessage.getToDomain()) {
inMessage.setToDomain(MessageConstant.DomainType.Queue);
}
//3.填充规则缺省值
if (null == inMessage.getRule()) {
inMessage.setRule(MessageRule.defaultRule(inMessage.getFromDomain()));
}
break;
}
case Queue: {
//1.填充Message from信息
inMessage.setFromDomain(MessageConstant.DomainType.Queue);
inMessage.setFrom(QueueManager.getInQueueName());
//2.填充Message to信息
if(null == inMessage.getToDomain()){
inMessage.setToDomain( MessageConstant.DomainType.User);
}
//3.填充规则缺省值
if (null == inMessage.getRule()) {
inMessage.setRule(MessageRule.defaultRule(inMessage.getFromDomain()));
}
break;
}
case Rest: {
//1.填充Message from信息
inMessage.setFromDomain(MessageConstant.DomainType.Rest);
inMessage.setFrom("");
//2.填充Message to信息
if (null == inMessage.getToDomain()) {
inMessage.setToDomain(MessageConstant.DomainType.User);
}
//3.填充规则缺省值
if (null == inMessage.getRule()) {
inMessage.setRule(MessageRule.defaultRule(inMessage.getFromDomain()));
}
break;
}
default:
break;
}
//2.填充tos值
if (null == inMessage.getTos()) {
inMessage.setTos(CollectionUtil.newHashSet());
} else {
inMessage.getTos().removeIf(to -> to == null || StrUtil.isEmpty(to));
}
switch (inMessage.getToDomain()) {
case Queue: {
if (CollectionUtil.isEmpty(inMessage.getTos())) {
inMessage.getTos().add(QueueManager.getOutQueueName());
}
break;
}
case Rest:{
if (CollectionUtil.isEmpty(inMessage.getTos())) {
inMessage.getTos().add(RestManager.getOutRestName());
}
break;
}
default: {
break;
}
}
return inMessage;
}
public static void sendMessageToAuthedClient(MessageConstant.DomainType toDomain, String to, OutMessageSet outMessageSet) throws JsonProcessingException {
switch (toDomain){
case User:
if(StrUtil.isNotEmpty(to)) {
ChannelManager.sendTo(to, outMessageSet);
}
break;
case Queue:
QueueManager.sendTo(outMessageSet);
break;
case Rest:
RestManager.sendTo(outMessageSet);
break;
default:
break;
}
}
public static void sendServerMessage(MessageConstant.DomainType toDomain, OutMessageSet outMessageSet) throws JsonProcessingException {
switch (toDomain){
case User:
ChannelManager.sendTo(ChannelManager.getCurrentChannel(), outMessageSet);
break;
case Queue:
QueueManager.sendTo(outMessageSet);
break;
case Rest:
RestManager.sendTo(outMessageSet);
break;
default:
break;
}
}
public static void sendServerAck(InMessage inMessage, MessageConstant.Error error) throws Exception {
switch (error) {
case Ok:
if (inMessage.getRule().getAckRule() != MessageRule.AckRule.ALWAYS) {
return;
}
break;
default:
if (inMessage.getRule().getAckRule() == MessageRule.AckRule.NONE) {
return;
}
break;
}
OutMessageSet outMessageSet = OutMessageSet.newInstance().ackId(null).add(
new OutMessage(MessageConstant.DomainType.Server,
JacksonUtil.beanToJson(
new ServerAckMessage(inMessage.getId(),inMessage.getUnikey(),error)
)
)
);
sendServerMessage(inMessage.getFromDomain(),outMessageSet);
}
public static boolean isSenderAuthed(InMessage inMessage) {
if (inMessage.getFromDomain() == MessageConstant.DomainType.User) {
return ChannelManager.channelAuthed(ChannelManager.getCurrentChannel());
}
return true;
}
public static void closeCurrentSender(InMessage message) {
if(message.getFromDomain() == MessageConstant.DomainType.User){
ChannelManager.getCurrentChannel().close();
}
}
public static boolean isUserOnline(MessageConstant.DomainType domain, String to) {
if (domain == MessageConstant.DomainType.User) {
return ChannelManager.isUserOnline(to);
}
return true;
}
}

366
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/ChannelManager.java

@ -0,0 +1,366 @@
package com.ccsens.ccmq.lowlevel.client.netty;
import cn.hutool.core.collection.CollectionUtil;
import com.ccsens.ccmq.lowlevel.message.client.ClientAuthTimeOutMessage;
import com.ccsens.ccmq.lowlevel.message.common.InMessage;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static com.ccsens.ccmq.lowlevel.message.MessageHandler.handleMessage;
/**
* @author wei
*/
public class ChannelManager {
private static Logger logger = LoggerFactory.getLogger(ChannelManager.class);
private static ThreadLocal<Channel> threadLocal = new ThreadLocal<>();
/**
* UserId,WrappedChannel authed channels;
*/
private static Map<String,Set<WrapperedChannel>> authedChannels;
/**
* Channel,WrapperedChannel
*/
private static Map<Channel,WrapperedChannel> rawChannels;
static {
authedChannels = new ConcurrentHashMap<>();
rawChannels = new ConcurrentHashMap<>();
}
/**
* 私有构造,不允许生成该类对象
*/
private ChannelManager(){}
/**
* 设置当前正在错误的channel
* @param channel netty ws/tcp连接
*/
public static void setCurrentChannel(Channel channel){
threadLocal.set(channel);
}
/**
* 获取当前线程的channel对象
* @return channel
*/
public static Channel getCurrentChannel(){
return threadLocal.get();
}
/**
* 删除当前线程的channel对象
*/
public static void removeCurrentChannel(){
threadLocal.remove();
}
/**
* 添加一个新的连接(Channel)
* @param channel 新的连接
* @param serverType 服务器类型
*/
public static synchronized void addChannel(Channel channel,String serverType){
logger.debug("Invoke addChannel({},{})",channel,serverType);
if(null != channel) {
rawChannels.put(channel, new WrapperedChannel(channel, serverType));
logger.debug("Add a new channel: {},{}",channel.id().asLongText(),serverType);
}else{
logger.error("channel is null");
}
}
/**
* 用户认证
* @param channel 连接
* @param userId 用户ID
* @param major 客户端主版本号
* @param minor 客户端次版本号
*/
public static synchronized void authChannel(Channel channel,String userId,Integer major,Integer minor){
logger.debug("Invoke authedChannels({},{},{},{})",channel.id().asLongText(),userId,major,minor);
major = major != null ? major : 0;
minor = minor != null ? minor : 0;
WrapperedChannel wrapperedChannel = rawChannels.get(channel);
if(wrapperedChannel != null){
wrapperedChannel.whenAuthed(userId,major,minor);
Set<WrapperedChannel> authedWchannelSet = authedChannels.computeIfAbsent(userId, k -> new HashSet<>());
authedWchannelSet.add(wrapperedChannel);
logger.debug("Authed channel {} with user {}", channel.id().asLongText(), userId);
}else{
logger.error("Authed channel,but wrappedChannel is null.");
}
}
/**
* 移除一个连接(Channel)
* @param channel 要移除的连接
*/
public static synchronized void removeChannel(Channel channel){
logger.debug("Invoke removeChannel({})",channel.id().asLongText());
WrapperedChannel wrapperedChannel = rawChannels.get(channel);
if(wrapperedChannel != null){
//从rawChannels集合中删除
rawChannels.remove(channel);
logger.debug("Remove a channel from rawChannels: {}",channel.id().asLongText());
if(wrapperedChannel.isAuthed()){
Set<WrapperedChannel> authedChannelSet = authedChannels.get(wrapperedChannel.getUserId());
//从authedChannel集合的value(set)中删除
if(CollectionUtil.isNotEmpty(authedChannelSet)){
authedChannelSet.remove(wrapperedChannel);
logger.debug("Remove a channel from authedChannelSet: {}, {}",wrapperedChannel.getUserId(),channel.id().asLongText());
}
//从authedChannel中删除,此处不用else,因为if中语句执行完毕之后,authedChannelSet也可能变成空集合
if(CollectionUtil.isEmpty(authedChannelSet)){
authedChannels.remove(wrapperedChannel.getUserId());
logger.debug("Remove a user from authedChannels: {}",wrapperedChannel.getUserId());
}
}
}else{
logger.error("Remove channel,but wrappedChannel is null.");
}
if(channel.isOpen() || channel.isActive()){
channel.close();
}
}
/**
* 移除一个用户
* @param userId 要移除的用户
*/
public static synchronized void removeUser(String userId){
logger.debug("Invoke remove user : {}",userId);
Set<WrapperedChannel> wChannelSet = authedChannels.get(userId);
if(CollectionUtil.isNotEmpty(wChannelSet)){
for(WrapperedChannel wChannel : wChannelSet){
//从rawChannel中依次删除
rawChannels.remove(wChannel.getChannel());
logger.debug("Remove a channel from rawChannels: {}",wChannel.getChannel().id().asLongText());
}
}
//从authedChannel中删除
authedChannels.remove(userId);
logger.debug("Remove a user from authedChannels: {}",userId);
}
/**
* 添加版本号
* 只能给已认证的请求添加版本号
* @param channel 连接
* @param major 主版本号
* @param minor 次版本号
*/
public static synchronized void versionChannel(Channel channel,int major,int minor){
logger.debug("Invoke Version channel({},{},{}))",channel.id().asLongText(),major,minor);
WrapperedChannel wChannel = rawChannels.get(channel);
if(wChannel != null){
wChannel.setVersion(major,minor);
logger.debug("Version Channel: {},{},{}",channel.id().asLongText(),major,minor);
}else{
logger.error("Remove channel,but wrappedChannel is null.");
}
}
/**
* 发送广播消息给所有已认证Channel
* @param message 消息
*/
public static synchronized void broadCastAuthed(Object message) {
logger.debug("Invoke broadCastAuthed({})",message);
for (Map.Entry<Channel,WrapperedChannel> entry : rawChannels.entrySet()) {
WrapperedChannel wChannel = entry.getValue();
if(wChannel.isAuthed()) {
wChannel.writeAndFlush(message);
logger.debug("Send Message {} to {},{}",message,wChannel.getUserId(),wChannel.getId());
}
}
}
/**
* 发送广播消息
* @param message 消息
*/
public static synchronized void broadCast(Object message) {
logger.debug("Invoke broadCast({})",message);
for (Map.Entry<Channel,WrapperedChannel> entry : rawChannels.entrySet()) {
entry.getValue().writeAndFlush(message);
logger.debug("Send Message {} to {}",message,entry.getValue().getId());
}
}
/**
* 发送消息给某个连接
* @param channel 连接
* @param message 消息
*/
public static synchronized void sendTo(Channel channel,Object message){
logger.debug("Invoke sendTo({},{})",channel.id().asLongText(),message);
WrapperedChannel wrapperedChannel = rawChannels.get(channel);
if(wrapperedChannel != null) {
wrapperedChannel.writeAndFlush(message);
logger.debug("Write message {} to Channel {}",message,channel);
}else{
logger.error("can't find channel from rawChannels");
}
}
/**
* 发送消息给某个用户
* @param userId 用户ID
* @param message 消息
*/
public static synchronized boolean sendTo(String userId,Object message){
logger.debug("Invoke sendTo({},{})",userId,message);
Set<WrapperedChannel> wChannelSet = authedChannels.get(userId);
if(CollectionUtil.isNotEmpty(wChannelSet)){
for(WrapperedChannel wChannel:wChannelSet){
wChannel.writeAndFlush(message);
logger.debug("Send message {} to channel {}",message,userId);
}
return true;
}else{
return false;
}
}
/**
* 刷新最后一次接收数据时间 每次接收数据需要调用该函数
* @param channel 接收数据的连接
*/
public static synchronized void flushReceiveTimestamp(Channel channel){
logger.debug("Invoke flushReceiveTimestamp({})",channel.id().asLongText());
WrapperedChannel wrapperedChannel = rawChannels.get(channel);
if(wrapperedChannel != null){
wrapperedChannel.whenReceivedData();
}else{
logger.error("can find channel from rawChannels");
}
}
/**
* 关闭所有未认证的连接
* @param unAuthedChannelsMaxAliveTimeInSeconds 未认证的最大时长(s)
* @throws Exception
* @deprecated 已过期该方法在多线程并发下可能出现问题建议使用messageService中的同名方法
*/
@Deprecated
public static synchronized void closeUnAuthedChannels(Long unAuthedChannelsMaxAliveTimeInSeconds) throws Exception {
logger.debug("Inovke closeUnAuthedChannels({})",unAuthedChannelsMaxAliveTimeInSeconds);
Iterator<Map.Entry<Channel,WrapperedChannel>> it = rawChannels.entrySet().iterator();
while(it.hasNext()){
Map.Entry<Channel,WrapperedChannel> entry = it.next();
WrapperedChannel wrapperedChannel = entry.getValue();
if((!wrapperedChannel.isAuthed()) && (wrapperedChannel.getConnectedSeconds() > unAuthedChannelsMaxAliveTimeInSeconds)) {
it.remove();
//关闭连接
wrapperedChannel.getChannel().close();
logger.debug("Remove a unAuthed Channel {}, which has connected {}s,maxOutTime is {}s", wrapperedChannel.getId(),wrapperedChannel.getConnectedSeconds() ,
unAuthedChannelsMaxAliveTimeInSeconds );
}
}
}
/**
* 判断Channel是否存在
* @param channel 连接
* @return 是否存在
*/
public static synchronized boolean channelExist(Channel channel){
return rawChannels.containsKey(channel);
}
/**
* 判断Channel是否已经认证
* @param channel 连接
* @return 是否认证
*/
public static synchronized boolean channelAuthed(Channel channel){
return rawChannels.containsKey(channel) && rawChannels.get(channel).isAuthed();
}
/**
* 判断用户是否在线
* @param userId 用户ID
* @return 是否认证
*/
public static synchronized boolean isUserOnline(String userId){
return authedChannels.containsKey(userId);
}
/**
* 根据Channel获取对应的用户ID
* @param channel 连接
* @return 用户ID
*/
public static synchronized String getUserIdByChannel(Channel channel) {
return rawChannels.containsKey(channel) ? rawChannels.get(channel).getUserId() : null;
}
/**
* 获取所有在线用户
* @return 所有用户的集合列表
*/
public static synchronized Set<String> getOnlineUsers(){
return authedChannels.keySet();
}
/**
* 获取某种类型的所有在线用户的连接
* @param type 客户端类型(ws/tcp modebus/tcp text)
* @return 所有在西安channel的集合列表
*/
public static synchronized Set<Channel> getOnlineChannels(String type){
Set<Channel> onLineChannels = CollectionUtil.newHashSet();
for(Map.Entry<Channel,WrapperedChannel> entry: rawChannels.entrySet()){
WrapperedChannel wrapperedChannel = entry.getValue();
if(wrapperedChannel.isAuthed() && wrapperedChannel.getType().equals(type)){
onLineChannels.add(entry.getKey());
}
}
return onLineChannels;
}
/**
* 获取一个rawChannel的副本
* @return 副本
*/
public static Map<Channel, WrapperedChannel> getCopyOfAllChannels() {
Map<Channel,WrapperedChannel> copyMap = new HashMap<>(rawChannels.size());
copyMap.putAll(rawChannels);
return copyMap;
}
/**
* 根据Channel获取WrapperedChannel
* @param channel channel
* @return 对应的wrapperedChannel
*/
public static WrapperedChannel getWrapperedChannelByChannel(Channel channel) {
return rawChannels.get(channel);
}
public static synchronized void showAuthedChannels(){
for(Map.Entry<String,Set<WrapperedChannel>> entry : authedChannels.entrySet()){
for (WrapperedChannel channel:entry.getValue()){
logger.debug("{}-->{}",entry.getKey(),channel.toString());
}
}
}
public static synchronized void showAllChannels(){
for(Map.Entry<Channel,WrapperedChannel> entry : rawChannels.entrySet()){
logger.debug(entry.getValue().toString());
}
}
public static Set<String> getAllOnlineUsers() {
return authedChannels.keySet();
}
}

200
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/WrapperedChannel.java

@ -0,0 +1,200 @@
package com.ccsens.ccmq.lowlevel.client.netty;
import cn.hutool.core.util.ObjectUtil;
import wiki.tall.ccmq.common.util.DateUtil;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.Setter;
import java.net.InetSocketAddress;
/**
* @author wei
*/
@Getter
@Setter
public class WrapperedChannel {
@Getter
@Setter
private static class ClientVersion{
int major;
int minor;
public ClientVersion(int major,int minor){
this.major = major;
this.minor = minor;
}
}
/**
* Netty's Channel
*/
private Channel channel;
/**
* userId
*/
private String userId;
/**
* 客户端版本号
*/
private ClientVersion version;
/**
* 客户端类型(哪种服务器)
*/
private String type;
/**
* 是否认证
*/
private boolean authed;
/**
* 连接建立时间
*/
private Long createdAtInSeconds;
/**
* 认证时间(s)
*/
private Long authedAtInSeconds;
/**
* 最后一次接收有效数据时间(包括心跳包)
*/
private Long lastDataReceivedInSeconds;
/**
* 最后一次发送有效数据时间(包括心跳包)
*/
private Long lastDataSendInSeconds;
/**
* 接收到数据条数(每接收到一条协议加1包括心跳)
*/
private long dataReceivedCount;
/**
* 发送数据条数(每发送到一条协议加1包括心跳)
*/
private long dataSendCount;
public WrapperedChannel(Channel channel){
this.channel = channel;
this.createdAtInSeconds = DateUtil.currentSeconds();
}
public WrapperedChannel(Channel channel,String type){
this(channel);
this.type = type;
}
public WrapperedChannel(Channel channel,String type,int major,int minor){
this(channel,type);
this.version = new ClientVersion(major,minor);
}
public String getVersion(){
if(ObjectUtil.isNotNull(version)){
return "v" + version.getMajor() + "." + version.getMinor();
}
return null;
}
public void setVersion(int major,int minor){
if (ObjectUtil.isNull(version)) {
version = new ClientVersion(major, minor);
} else {
version.setMajor(major);
version.setMinor(minor);
}
}
public String getRemoteAddr(){
if(ObjectUtil.isNotNull(channel)){
InetSocketAddress insocket = (InetSocketAddress) channel.remoteAddress();
if(ObjectUtil.isNotNull(insocket)) {
return insocket.getAddress().getHostAddress();
}
}
return null;
}
public Integer getRemotePort(){
if(ObjectUtil.isNotNull(channel)){
InetSocketAddress insocket = (InetSocketAddress) channel.remoteAddress();
if(ObjectUtil.isNotNull(insocket)) {
return insocket.getPort();
}
}
return null;
}
public String getId(){
if(ObjectUtil.isNotNull(channel)){
return channel.id().asLongText();
}
return null;
}
public void whenReceivedData(){
lastDataReceivedInSeconds = DateUtil.currentSeconds();
dataReceivedCount++;
}
public void whenSendData(){
lastDataSendInSeconds = DateUtil.currentSeconds();
dataSendCount++;
}
public void whenAuthed(){
authed = true;
authedAtInSeconds = DateUtil.currentSeconds();
}
public void whenAuthed(String userId,int major,int minor){
whenAuthed();
setVersion(major,minor);
this.userId = userId;
}
public void writeAndFlush(Object message){
if(channel != null && channel.isActive()){
channel.writeAndFlush(message);
whenSendData();
}
}
public Long getConnectedSeconds(){
return createdAtInSeconds == null ? null : DateUtil.currentSeconds() - createdAtInSeconds;
}
public Long getOnlineSeconds(){
return authedAtInSeconds == null ? null : DateUtil.currentSeconds() - authedAtInSeconds ;
}
@Override
public boolean equals(Object obj) {
if(ObjectUtil.isNull(obj)) {
return false;
}
if(this == obj) {
return true;
}
if(ObjectUtil.isNull(channel)) {
return false;
}
if(obj.getClass() == this.getClass()){
WrapperedChannel other = (WrapperedChannel)obj;
return channel.equals(other.channel);
}else if(obj.getClass() == channel.getClass()){
Channel other = (Channel)obj;
return channel.equals(other);
}
return false;
}
@Override
public int hashCode() {
if(ObjectUtil.isNotNull(channel)){
return channel.hashCode();
}
return 0;
}
@Override
public String toString() {
return String.format("id: %s, type: %s, authed: %b, userId: %s, version: %s",getId(),type,authed,userId,getVersion());
}
}

115
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcphexserver/ModbusConverter.java

@ -0,0 +1,115 @@
package com.ccsens.ccmq.lowlevel.client.netty.tcphexserver;
public class ModbusConverter {
// public static BaseMessageDto convertCCModbusToMessage(CCModBusEntity ccModBusEntity) {
// BaseMessageDto message = null;
// int addr = ccModBusEntity.getAddr() & 0xFF;
// int oper = ccModBusEntity.getOper() & 0xFF;
// WebConstant.Message_Type type = WebConstant.Message_Type.valueOf(addr);
// if(type != null) {
// switch (type) {
// case Heart: {
// message = toHeartMessage(addr,oper,ccModBusEntity.getOriginData());
// break;
// }
// case Auth:{
// message = toAuthMessage(addr,oper,ccModBusEntity.getOriginData());
// }
// }
// }
// return message;
// }
//
// /**
// * OriginaData ==> 0x00
// * @param oper
// * @return
// */
// private static BaseMessageDto toHeartMessage(int addr, int oper, byte[] originData){
// HeartMessageDto message = new HeartMessageDto();
// return message;
// }
//
// /**
// * OriginaData ==> 0x00 0x00 0x00 0x64
// * @param oper
// * @return
// */
// private static BaseMessageDto toAuthMessage(int addr, int oper, byte[] originData){
// Long userId = 0L;
// for(int i=0;i<originData.length;i++){
// userId <<= 8;
// userId |= originData[i] & 0xFF;
// }
// AuthMessageDto message = new AuthMessageDto(userId,null);
// return message;
// }
//
// public static CCModBusEntity convertCommonProtocolToCCModbus(BaseMessageDto message) {
// CCModBusEntity ccModBusEntity = null;
// WebConstant.Message_Type type = WebConstant.Message_Type.phaseOf(message.getType());
// switch (type){
// case Heart:{
// ccModBusEntity = fromHeartMessage((HeartMessageDto)message);
// break;
// }
// case Timer:{
// WebConstant.Message_Timer_Event event = WebConstant.Message_Timer_Event.phaseOf(message.getEvent());
// switch (event){
// case CountDown:
// ccModBusEntity = fromTimerMessageWithCountDown((TimerMessageWithCountDownDto)message);
// break;
// case Clock:
// ccModBusEntity = fromTimerMessageWithClock((TimerMessageWithClockDto)message);
// break;
// }
// break;
// }
// }
// return ccModBusEntity;
// }
//
// /**
// * OriginalData: 0x00
// * @param message
// * @return
// */
// private static CCModBusEntity fromHeartMessage(HeartMessageDto message){
// byte []originData = new byte[1];
// originData[0] = 0x00;
// byte addr = (byte)(WebConstant.Message_Type.phaseOf(message.getType()).value & 0xFF);
// byte oper = (byte)(WebConstant.Message_Type.phaseOf(message.getEvent()).value & 0xFF);
// CCModBusEntity ccModBusEntity = new CCModBusEntity(addr,oper,originData);
// return ccModBusEntity;
// }
//
// /**
// * originaData: a1 xx xx xx crc
// * @param message
// * @return
// */
// private static CCModBusEntity fromTimerMessageWithCountDown(TimerMessageWithCountDownDto message){
// Long second = message.getData().getSecond();
// byte []originData = new byte[5];
// originData[0] = (byte)(0xa1 & 0xFF);
// originData[1] = (0x48 & 0xFF);
// originData[2] = (byte)((second >> 8) & 0xFF);
// originData[3] = (byte)(second & 0xFF);
// originData[4] = (byte)((originData[0] + originData[1] + originData[2] + originData[3]) & 0xFF);
//
// byte addr = (byte)(WebConstant.Message_Type.phaseOf(message.getType()).value & 0xFF);
// byte oper = (byte)(WebConstant.Message_Timer_Event.phaseOf(message.getEvent()).value & 0xFF);
// CCModBusEntity ccModBusEntity = new CCModBusEntity(addr,oper,originData);
// return ccModBusEntity;
// }
//
// /**
// * originaData: xxx
// * @param message
// * @return
// */
// private static CCModBusEntity fromTimerMessageWithClock(TimerMessageWithClockDto message){
// return null;
// }
}

45
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcphexserver/ModbusDecoder.java

@ -0,0 +1,45 @@
package com.ccsens.ccmq.lowlevel.client.netty.tcphexserver;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
public class ModbusDecoder extends ByteToMessageDecoder {
private void discardNBytes(ByteBuf in, int length) {
for (int i = 0; i < length; i++) {
in.readByte();
}
}
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Object> out) throws Exception {
// if (in.readableBytes() < CCModBusEntity.SIZE_MIN) {
// //长度小于协议的最小长度,继续读下一次
// return;
// }
//
// CCModBusEntity ccModBusEntity = new CCModBusEntity(in);
// CCModBusEntity.Error error = ccModBusEntity.valid();
// switch (error) {
// case ERROR_FILTER_NOT_MATCH:
// case ERROR_LEN_EXCLUEE_MAX:
// case ERROR_CRC_INVALID: //丢弃一个字节,继续读取
// discardNBytes(in, 1);
// return;
// case ERROR_NEED_MORE_DATA: //继续读取
// return;
// case ERROR_NONE:
// break;
// }
//
// //交给下个handler处理
// discardNBytes(in, ccModBusEntity.getModbusLength());
// BaseMessageDto message = ModbusConverter.convertCCModbusToMessage(ccModBusEntity);
// if(ObjectUtil.isNotNull(message)) {
// out.add(message);
// }
}
}

33
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcphexserver/ModbusEncoder.java

@ -0,0 +1,33 @@
package com.ccsens.ccmq.lowlevel.client.netty.tcphexserver;
import com.ccsens.ccmq.lowlevel.message.common.OutMessageSet;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
public class ModbusEncoder extends MessageToByteEncoder<OutMessageSet> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, OutMessageSet message, ByteBuf out) throws Exception {
//
// //1.处理Start->Timer[Countdown]
// if(message != null && message instanceof SyncMessageWithStartDto){
// SyncMessageWithStartDto startMessage = (SyncMessageWithStartDto)message;
// if(ObjectUtil.isNotNull(startMessage.getData().getBeginTaskId())){
// Long duration = startMessage.getData().getDuration();
// message = new TimerMessageWithCountDownDto(duration/1000,null,null);
// }
// }
//
// if(message != null){
// CCModBusEntity ccModBusEntity = ModbusConverter.convertCommonProtocolToCCModbus(message);
// if(ccModBusEntity != null){
// byte[] modbusData = ccModBusEntity.getModbusData();
// for(int i=0;i<modbusData.length;i++){
// System.out.printf("%02x ",modbusData[i]);
// }
// System.out.println();
// out.writeBytes(modbusData);
// }
// }
}
}

109
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcphexserver/ModbusHandler.java

@ -0,0 +1,109 @@
package com.ccsens.ccmq.lowlevel.client.netty.tcphexserver;
import com.ccsens.ccmq.lowlevel.message.common.InMessage;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.client.ClientIdleClosedMessage;
import com.ccsens.ccmq.lowlevel.message.server.UnExceptedErrorMessage;
import com.ccsens.ccmq.lowlevel.client.ClientManager;
import com.ccsens.ccmq.lowlevel.message.MessageHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import wiki.tall.ccmq.common.util.WebConstant;
import com.ccsens.ccmq.lowlevel.client.netty.ChannelManager;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.springframework.stereotype.Component;
/**
* @author __zHangSan
*/
@ChannelHandler.Sharable
@Component
public class ModbusHandler extends SimpleChannelInboundHandler<InMessage> {
private Logger logger = LoggerFactory.getLogger(ModbusHandler.class);
private static final String TYPE = WebConstant.NETTY_SERVER_TYPE.TCP_MB.phase;
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ChannelManager.addChannel(ctx.channel(),TYPE);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ChannelManager.removeChannel(ctx.channel());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
try {
ChannelManager.setCurrentChannel(ctx.channel());
MessageHandler.handleMessage(
InMessage.newToServerMessage(MessageConstant.DomainType.User,new UnExceptedErrorMessage(cause.getMessage())));
}catch(Exception e){
e.printStackTrace();
logger.error("TcpHex exceptionCaught handler error: {}",e.getMessage());
}finally {
ChannelManager.removeCurrentChannel();
}
cause.printStackTrace();
ctx.close();
logger.error("Channel closed. TcpHex get a exception: {}", cause.getMessage());
}
@SuppressWarnings("all")
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
if (idleStateEvent.state() == IdleState.READER_IDLE) {
try {
ChannelManager.setCurrentChannel(ctx.channel());
MessageHandler.handleMessage(
InMessage.newToServerMessage(MessageConstant.DomainType.User,new ClientIdleClosedMessage()));
}catch(Exception e){
e.printStackTrace();
logger.error("TcpHex exceptionCaught handler error: {}",e.getMessage());
}finally {
ChannelManager.removeCurrentChannel();
}
ctx.channel().close();
logger.error("TcpHex channel idle,closed.");
}
} else {
super.userEventTriggered(ctx, evt);
}
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, InMessage inMessage) throws Exception {
try {
//0.设置最后一次收数据的时间 和 当前线程channel
ChannelManager.flushReceiveTimestamp(ctx.channel());
ChannelManager.setCurrentChannel(ctx.channel());
//1.填充缺省信息
ClientManager.fillMessageInfo(inMessage, MessageConstant.DomainType.User);
//2.处理消息
MessageHandler.handleMessage(inMessage);
} catch (Exception e) {
e.printStackTrace();
logger.error("TcpHex Process Message Failed: {},{}", e.getMessage(), inMessage);
throw e;
} finally {
ChannelManager.removeCurrentChannel();
}
}
}

59
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcphexserver/NettyMBServer.java

@ -0,0 +1,59 @@
package com.ccsens.ccmq.lowlevel.client.netty.tcphexserver;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @author __zHangSan
*/
@Component
public class NettyMBServer {
@Autowired
private ModbusHandler modbusHandler;
private static final short SERVER_PORT = 8195;
@Async
public void start() {
// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new IdleStateHandler(40, 0, 0, TimeUnit.SECONDS));
p.addLast(new ModbusDecoder());
p.addLast(new ModbusEncoder());
p.addLast(modbusHandler);
}
});
// Start the server.
ChannelFuture f = b.bind(SERVER_PORT).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} catch(Exception e){
e.printStackTrace();
}finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}

61
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcptextserver/NettyTextServer.java

@ -0,0 +1,61 @@
package com.ccsens.ccmq.lowlevel.client.netty.tcptextserver;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class NettyTextServer {
@Autowired
private TextHandler textHandler;
@Autowired
private static final String DELIMITER = "_$$_";
private static final short SERVER_PORT = 8199;
@Async
public void start() {
// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new IdleStateHandler(40, 0, 0, TimeUnit.SECONDS));
p.addLast(new DelimiterBasedFrameDecoder(2048, Unpooled.copiedBuffer(DELIMITER.getBytes())));
p.addLast(new TextDecoder());
p.addLast(new TextEncoder(2048,Unpooled.copiedBuffer(DELIMITER.getBytes())));
p.addLast(textHandler);
}
});
// Start the server.
ChannelFuture f = b.bind(SERVER_PORT).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} catch(Exception e){
e.printStackTrace();
}finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}

32
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcptextserver/TextDecoder.java

@ -0,0 +1,32 @@
package com.ccsens.ccmq.lowlevel.client.netty.tcptextserver;
import com.ccsens.ccmq.lowlevel.message.common.InMessage;
import wiki.tall.ccmq.common.util.JacksonUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
/**
* @author __zHangSan
*/
public class TextDecoder extends MessageToMessageDecoder<ByteBuf> {
private static Logger logger = LoggerFactory.getLogger(TextDecoder.class);
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf msg, List<Object> out) throws Exception {
String msgString = msg.toString(Charset.defaultCharset());
logger.info("TcpText received: {}" + msgString);
try {
out.add(JacksonUtil.jsonToBean(msgString, InMessage.class));
}catch (IOException e){
e.printStackTrace();
logger.error("TcpText read error: {}",msgString);
}
}
}

49
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcptextserver/TextEncoder.java

@ -0,0 +1,49 @@
package com.ccsens.ccmq.lowlevel.client.netty.tcptextserver;
import com.ccsens.ccmq.lowlevel.message.common.OutMessageSet;
import wiki.tall.ccmq.common.util.JacksonUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.List;
/**
* @author __zHangSan
*/
public class TextEncoder extends MessageToMessageEncoder<OutMessageSet> {
private final Charset charset;
private int maxLength;
private ByteBuf delimiter;
public TextEncoder() {
this(Charset.defaultCharset());
}
public TextEncoder(Charset charset) {
if (charset == null) {
throw new NullPointerException("charset");
} else {
this.charset = charset;
}
}
public TextEncoder(int maxLength, ByteBuf delimiter) {
this();
this.maxLength = maxLength;
this.delimiter = delimiter;
}
@Override
protected void encode(ChannelHandlerContext ctx, OutMessageSet outMessageSet, List<Object> out) throws Exception {
String delimiterString = delimiter.toString(Charset.defaultCharset());
String msgString = JacksonUtil.beanToJson(outMessageSet) + delimiterString;
if (msgString.length() != 0) {
out.add(ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(msgString), this.charset));
}
}
}

110
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/tcptextserver/TextHandler.java

@ -0,0 +1,110 @@
package com.ccsens.ccmq.lowlevel.client.netty.tcptextserver;
import com.ccsens.ccmq.lowlevel.message.common.InMessage;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.client.ClientIdleClosedMessage;
import com.ccsens.ccmq.lowlevel.message.server.UnExceptedErrorMessage;
import com.ccsens.ccmq.lowlevel.client.ClientManager;
import com.ccsens.ccmq.lowlevel.message.MessageHandler;
import wiki.tall.ccmq.common.config.SettingProps;
import com.ccsens.ccmq.lowlevel.client.netty.ChannelManager;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author __zHangSan
*/
@ChannelHandler.Sharable
@Component
public class TextHandler extends SimpleChannelInboundHandler<InMessage> {
private static Logger logger = LoggerFactory.getLogger(TextHandler.class);
@Autowired
private SettingProps settingProps;
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ChannelManager.addChannel(ctx.channel(),settingProps.getNettyTcpTextType());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ChannelManager.removeChannel(ctx.channel());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
try {
ChannelManager.setCurrentChannel(ctx.channel());
MessageHandler.handleMessage(
InMessage.newToServerMessage(MessageConstant.DomainType.User,new UnExceptedErrorMessage(cause.getMessage())));
}catch(Exception e){
e.printStackTrace();
logger.error("TcpText exceptionCaught handler error: {}",e.getMessage());
}finally {
ChannelManager.removeCurrentChannel();
}
cause.printStackTrace();
ctx.close();
logger.error("Channel closed. TcpText get a exception: {}",cause.getMessage());
}
@SuppressWarnings("all")
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
if (idleStateEvent.state() == IdleState.READER_IDLE) {
try {
ChannelManager.setCurrentChannel(ctx.channel());
MessageHandler.handleMessage(
InMessage.newToServerMessage(MessageConstant.DomainType.User,new ClientIdleClosedMessage()));
}catch(Exception e){
e.printStackTrace();
logger.error("TcpText exceptionCaught handler error: {}",e.getMessage());
}finally {
ChannelManager.removeCurrentChannel();
}
ctx.channel().close();
logger.error("TcpText channel idle,closed.");
}
} else {
super.userEventTriggered(ctx, evt);
}
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, InMessage inMessage) throws Exception {
try {
//0.设置最后一次收数据的时间 和 当前线程channel
ChannelManager.flushReceiveTimestamp(ctx.channel());
ChannelManager.setCurrentChannel(ctx.channel());
//1.填充缺省信息
ClientManager.fillMessageInfo(inMessage, MessageConstant.DomainType.User);
//2.处理消息
MessageHandler.handleMessage(inMessage);
} catch (Exception e) {
e.printStackTrace();
logger.error("TcpText Process Message Failed: {},{}", e.getMessage(), inMessage);
throw e;
} finally {
ChannelManager.removeCurrentChannel();
}
}
}

72
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/wsserver/NettyWsServer.java

@ -0,0 +1,72 @@
package com.ccsens.ccmq.lowlevel.client.netty.wsserver;
import wiki.tall.ccmq.common.config.SettingProps;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @author wei
*/
@Component
public class NettyWsServer {
@Autowired
private SettingProps settingProps;
@Autowired
private WebSocketHandler webSocketHandler;
@Async
public void start() {
// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
if(settingProps.getKeepAlive().isEnable()) {
p.addLast(new IdleStateHandler(settingProps.getKeepAlive().getMaxIdleSeconds(),
0, 0, TimeUnit.SECONDS));
}
p.addLast(new HttpServerCodec());
p.addLast(new HttpObjectAggregator(64 * 1024));
p.addLast(new ChunkedWriteHandler());
p.addLast(new WebSocketServerProtocolHandler(settingProps.getNettyWsUri()));
p.addLast(new WebSocketDecoder());
p.addLast(new WebSocketEncoder());
p.addLast(webSocketHandler);
}
});
// Start the server.
ChannelFuture f = b.bind(settingProps.getNettyWsPort()).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} catch(Exception e){
e.printStackTrace();
}finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}

33
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/wsserver/WebSocketDecoder.java

@ -0,0 +1,33 @@
package com.ccsens.ccmq.lowlevel.client.netty.wsserver;
import com.ccsens.ccmq.lowlevel.message.common.InMessage;
import wiki.tall.ccmq.common.util.JacksonUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
/**
* @author wei
*/
public class WebSocketDecoder extends MessageToMessageDecoder<TextWebSocketFrame> {
private static Logger logger = LoggerFactory.getLogger(WebSocketDecoder.class);
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame msg, List<Object> out) throws Exception {
String text = msg.text();
logger.info("Websocket received: {}",text);
try {
out.add(JacksonUtil.jsonToBean(text, InMessage.class));
}catch(IOException e){
e.printStackTrace();
logger.error("Websocket Read Error: {}",text);
throw e;
}
}
}

25
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/wsserver/WebSocketEncoder.java

@ -0,0 +1,25 @@
package com.ccsens.ccmq.lowlevel.client.netty.wsserver;
import com.ccsens.ccmq.lowlevel.message.common.OutMessageSet;
import wiki.tall.ccmq.common.util.JacksonUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author wei
*/
public class WebSocketEncoder extends MessageToByteEncoder<OutMessageSet> {
private static Logger logger = LoggerFactory.getLogger(WebSocketEncoder.class);
@Override
protected void encode(ChannelHandlerContext ctx, OutMessageSet outMessageSet, ByteBuf out) throws Exception {
String msg = JacksonUtil.beanToJson(outMessageSet);
ctx.writeAndFlush(new TextWebSocketFrame(msg));
logger.info("Websocket send: {}",msg);
}
}

107
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/netty/wsserver/WebSocketHandler.java

@ -0,0 +1,107 @@
package com.ccsens.ccmq.lowlevel.client.netty.wsserver;
import com.ccsens.ccmq.lowlevel.message.common.InMessage;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.client.ClientIdleClosedMessage;
import com.ccsens.ccmq.lowlevel.message.server.UnExceptedErrorMessage;
import com.ccsens.ccmq.lowlevel.client.ClientManager;
import com.ccsens.ccmq.lowlevel.message.MessageHandler;
import wiki.tall.ccmq.common.config.SettingProps;
import com.ccsens.ccmq.lowlevel.client.netty.ChannelManager;
import io.netty.channel.*;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author wei
*/
@ChannelHandler.Sharable
@Component
public class WebSocketHandler extends SimpleChannelInboundHandler<InMessage> {
private static Logger logger = LoggerFactory.getLogger(WebSocketHandler.class);
@Autowired
private SettingProps settingProps;
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ChannelManager.addChannel(ctx.channel(),settingProps.getNettyWsType());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ChannelManager.removeChannel(ctx.channel());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
try {
ChannelManager.setCurrentChannel(ctx.channel());
MessageHandler.handleMessage(
InMessage.newToServerMessage(MessageConstant.DomainType.User,new UnExceptedErrorMessage(cause.getMessage())));
}catch(Exception e){
e.printStackTrace();
logger.error("Ws exceptionCaught handler error: {}",e.getMessage());
}finally {
ChannelManager.removeCurrentChannel();
}
cause.printStackTrace();
ctx.close();
logger.error("Channel closed. Ws get a exception: {}", cause.getMessage());
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
if (idleStateEvent.state() == IdleState.READER_IDLE) {
try {
ChannelManager.setCurrentChannel(ctx.channel());
MessageHandler.handleMessage(
InMessage.newToServerMessage(MessageConstant.DomainType.User,new ClientIdleClosedMessage()));
}catch(Exception e){
e.printStackTrace();
logger.error("Ws exceptionCaught handler error: {}",e.getMessage());
}finally {
ChannelManager.removeCurrentChannel();
}
ctx.channel().close();
logger.error("Ws channel idle,closed.");
}
} else {
super.userEventTriggered(ctx, evt);
}
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, InMessage inMessage) throws Exception {
try {
//0.设置最后一次收数据的时间 和 当前线程channel
ChannelManager.flushReceiveTimestamp(ctx.channel());
ChannelManager.setCurrentChannel(ctx.channel());
//1.填充缺省信息
ClientManager.fillMessageInfo(inMessage,MessageConstant.DomainType.User);
//2.处理消息
MessageHandler.handleMessage(inMessage);
} catch (Exception e) {
e.printStackTrace();
logger.error("Websocket Process Message Failed: {},{}", e.getMessage(), inMessage);
throw e;
} finally {
ChannelManager.removeCurrentChannel();
}
}
}

36
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/rabbitmq/QueueManager.java

@ -0,0 +1,36 @@
package com.ccsens.ccmq.lowlevel.client.rabbitmq;
import wiki.tall.ccmq.common.config.SettingProps;
import wiki.tall.ccmq.common.util.JacksonUtil;
import wiki.tall.ccmq.common.util.SpringContextUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
/**
* @author __zHangSan
*/
public class QueueManager {
private static Logger logger = LoggerFactory.getLogger(QueueManager.class);
public static String getInQueueName(){
return SpringContextUtils.getBean(SettingProps.class).getMq().getInName();
}
public static String getOutQueueName(){
return SpringContextUtils.getBean(SettingProps.class).getMq().getOutName();
}
public static void sendTo(String queueName,Object obj) throws JsonProcessingException {
String text = JacksonUtil.beanToJson(obj);
logger.info("QueueManager SendTo: {}",text);
SpringContextUtils.getBean(RabbitTemplate.class).convertAndSend(queueName,text);
}
public static void sendTo(Object obj) throws JsonProcessingException {
String text = JacksonUtil.beanToJson(obj);
logger.info("QueueManager SendTo: {}",text);
SpringContextUtils.getBean(RabbitTemplate.class).convertAndSend(getOutQueueName(),text);
}
}

48
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/rabbitmq/RabbitMqListener.java

@ -0,0 +1,48 @@
package com.ccsens.ccmq.lowlevel.client.rabbitmq;
import com.ccsens.ccmq.lowlevel.message.common.InMessage;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.server.UnExceptedErrorMessage;
import com.ccsens.ccmq.lowlevel.client.ClientManager;
import com.ccsens.ccmq.lowlevel.message.MessageHandler;
import wiki.tall.ccmq.common.util.JacksonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* @author wei
*/
@Component
@PropertySource(value = {"classpath:setting-${spring.profiles.active}.properties"})
@RabbitListener(queues = "${setting.mq.inName}")
public class RabbitMqListener {
private Logger logger = LoggerFactory.getLogger(RabbitMqListener.class);
@RabbitHandler
public void process(String messageJson) {
logger.info("Rabbit Received: {}",messageJson);
try {
InMessage inMessage = JacksonUtil.jsonToBean(messageJson, InMessage.class);
//1.填充缺省字段
ClientManager.fillMessageInfo(inMessage,MessageConstant.DomainType.Queue);
//2.处理消息
MessageHandler.handleMessage(inMessage);
}catch (Exception e){
e.printStackTrace();
try {
MessageHandler.handleMessage(
InMessage.newToServerMessage(MessageConstant.DomainType.Queue,new UnExceptedErrorMessage(e.getMessage())));
} catch (Exception ex) {
ex.printStackTrace();
}
logger.error("Rabbit Process Message Failed: {},{}",e.getMessage(),messageJson);
}
}
}

28
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/restful/MessageApi.java

@ -0,0 +1,28 @@
package com.ccsens.ccmq.lowlevel.client.restful;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import wiki.tall.ccmq.common.util.JsonResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller
public class MessageApi {
/**
* Restful Json 请求
* @param request
* @param response
* @param model
* @return
* @throws Exception
*/
@RequestMapping(value = "/json",method = RequestMethod.GET,produces = {"application/json;charset=UTF-8"})
@ResponseBody
public JsonResponse api(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
return JsonResponse.newInstance().ok();
}
}

16
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/client/restful/RestManager.java

@ -0,0 +1,16 @@
package com.ccsens.ccmq.lowlevel.client.restful;
import com.ccsens.ccmq.lowlevel.message.common.OutMessageSet;
/**
* @author __zHangSan
*/
public class RestManager {
public static void sendTo(OutMessageSet outMessageSet){
}
public static String getOutRestName(){
return "";
}
}

478
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/MessageHandler.java

@ -0,0 +1,478 @@
package com.ccsens.ccmq.lowlevel.message;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
import com.ccsens.ccmq.lowlevel.client.ClientManager;
import com.ccsens.ccmq.lowlevel.client.rabbitmq.QueueManager;
import com.ccsens.ccmq.lowlevel.message.server.*;
import com.ccsens.ccmq.lowlevel.persist.IMessageDao;
import com.ccsens.ccmq.lowlevel.message.client.*;
import com.ccsens.ccmq.lowlevel.message.common.*;
import com.ccsens.ccmq.lowlevel.client.netty.ChannelManager;
import com.ccsens.ccmq.lowlevel.client.netty.WrapperedChannel;
import com.ccsens.ccmq.lowlevel.service.IUserService;
import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import wiki.tall.ccmq.common.config.SettingProps;
import wiki.tall.ccmq.common.util.*;
import java.nio.channels.Channel;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author __zHangSan
*/
@Component
public class MessageHandler {
private Logger logger = LoggerFactory.getLogger(MessageHandler.class);
/**
* 发送消息最大等待ack时间
*/
private static final Integer REDIS_ACK_EXPIRED_SECONDS = 10;
/**
* 每次最多查询消息条数
*/
private static final Integer MAX_MESSAGE_NUM = 50;
private static IMessageDao getMessageDao(){
return SpringContextUtils.getBean(IMessageDao.class);
}
private static SettingProps getSettingProps(){
return SpringContextUtils.getBean(SettingProps.class);
}
private static IUserService getUserService(){
return SpringContextUtils.getBean(IUserService.class);
}
/**
* 每个20s同步一次有未决消息的用户到pendingClientSet中
* @throws Exception
*/
@Scheduled(cron = "0/20 * * * * *")
public void detectPendingClients() throws Exception{
logger.info("schedule detectPendingClients: {}", DateUtil.currentSeconds());
//1.获取所有的在线客户端
Set<String> onLineUsers = ChannelManager.getAllOnlineUsers();
Set<String> onLineClients = new HashSet<>(onLineUsers.size()+1);
if(CollectionUtil.isNotEmpty(onLineUsers)) {
for (String onlineUser : onLineUsers) {
onLineClients.add(CcMessageUtil.getDomainTypeAndUserIdString(MessageConstant.DomainType.User, onlineUser));
}
}
onLineClients.add(CcMessageUtil.getDomainTypeAndUserIdString(MessageConstant.DomainType.Queue,
QueueManager.getOutQueueName()));
//2.如果有未ack消息并且不在当前待处理列表中,则添加
for(String domainTypeAndUserId: onLineClients){
addClientToRedisUnPendingSet(domainTypeAndUserId);
}
}
/**
* 每隔5分钟将所有的tempSucceed的消息状态修改为pending
* @throws Exception
*/
@Scheduled(cron = "0 */5 * * * *")
public void updateMessageTempStatusToPending() throws Exception{
logger.info("schedule updateMessageTempStatusToPending: {}", DateUtil.currentSeconds());
getMessageDao().updateMessageStatusToPending();
}
/**
* 每隔5分钟扫描消息过期或发送次数达到上限消息
* @throws Exception
*/
@Scheduled(cron = "0 */5 * * * *")
public void updateMessageExpiredStatus() throws Exception{
logger.info("schedule updateMessageExpiredStatus: {}", DateUtil.currentSeconds());
getMessageDao().updateMessageToExpired();
}
/**
* 每隔5分钟扫描消息过期或发送次数达到上限消息
* @throws Exception
*/
@Scheduled(cron = "0 */5 * * * *")
public void updateMessageSendTimesUpLimitStatus() throws Exception{
logger.info("schedule updateMessageSendTimesUpLimitStatus: {}", DateUtil.currentSeconds());
getMessageDao().updateMessageToSendTimesUpLimit();
}
@Async("cc-msg-executor")
public void loopSendMessage() throws Exception {
String typeAndUserId = null,ackId = null;
List<Message> messageList = null;
List<String> sendTimesUpLimitMessageList = null,expiredMessageList = null;
while(true){
//从redis中或取第一个待处理用户
Object o = RedisUtil.sPop(RedisKeyManager.getPendingClientSetKey());
if(o != null && StrUtil.isNotEmpty(typeAndUserId = ackId = (String)o)){
Console.log("RedisUtil.sPop: {}",o);
String []stringArray = CcMessageUtil.splitTypeAndUserId(typeAndUserId);
MessageConstant.DomainType toDomain = MessageConstant.DomainType.valueOf(stringArray[0]);
String to = stringArray[1];
//针对同一用户,在上一次ack还未收到/超时之前,不进行处理
Object lockObj = ResourceLock.getLockObj(ackId);
synchronized (lockObj) {
//查找该用户是否有正在处理的消息
if (RedisUtil.hasKey(RedisKeyManager.getAckSetKey(ackId))) {
//将当前用户重新放回到待处理列表的最后
RedisUtil.sSet(RedisKeyManager.getPendingClientSetKey(), o);
continue;
}
//查找所有没有ack的消息
messageList = getMessageDao().getClientPendingMessage(toDomain, to, MAX_MESSAGE_NUM);
if (CollectionUtil.isEmpty(messageList)) {
continue;
}
//判断用户是否在线
boolean clientOnLine = ClientManager.isUserOnline(toDomain,to);
//发送和处理消息
if(clientOnLine){
//发送
//1.手机所有待发送的messageId,以ackId为key放入redis
Set<String> messageIdSet = new HashSet<>(messageList.size());
OutMessageSet outMessageSet = OutMessageSet.newInstance();
for(Message message : messageList) {
messageIdSet.add(message.getId());
outMessageSet.add(new OutMessage(message));
getMessageDao().incrementSendTimes(message.getId(), DateUtil.currentSeconds());
}
RedisUtil.sSetAndTime(RedisKeyManager.getAckSetKey(ackId),REDIS_ACK_EXPIRED_SECONDS,messageIdSet.toArray());
//2.构造outMessage并且发送
outMessageSet.ackId(ackId);
//发送给对应的接收者
ClientManager.sendMessageToAuthedClient(toDomain,to,outMessageSet);
}else{
//不发送,根据规则检查所有“offLineDiscard”的消息设置为failed状态
for(Message message : messageList){
if(message.getRule().getOfflineDiscard() == 1){
getMessageDao().updateMessageStatus(message.getId(),MessageConstant.Status.Failed);
}
}
}
}
ResourceLock.freeLockObj(ackId);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void handleMessage(InMessage inMessage) throws Exception{
//1. 处理发送给Server的消息
if(inMessage.getToDomain() == MessageConstant.DomainType.Server){
String type = null;
JsonNode typeNode = JacksonUtil.getJsonProperty(inMessage.getData(), "type");
//校验错误
if (typeNode == null || StrUtil.isEmpty(type = typeNode.textValue())) {
ClientManager.sendServerAck(inMessage, MessageConstant.Error.MessageNoTypeError);
}
//处理消息
handlerServerMessage(type,inMessage);
return;
}
//2. 处理发送给Client的消息
//校验错误
if (CollectionUtil.isEmpty(inMessage.getTos())) {
ClientManager.sendServerAck(inMessage, MessageConstant.Error.MessageNoReceiversError);
return;
}
if(!ClientManager.isSenderAuthed(inMessage)){
ClientManager.sendServerAck(inMessage,MessageConstant.Error.UnAuthed);
ClientManager.closeCurrentSender(inMessage);
return;
}
//存储消息(原始消息+按照tos拆分之后的每条消息)
saveMessage(inMessage);
//3.发送ack
ClientManager.sendServerAck(inMessage, MessageConstant.Error.Ok);
//4.将用户添加到Redis待处理用户集合中
RedisUtil.sSet(RedisKeyManager.getPendingClientSetKey(),
CcMessageUtil.getNameManglingToList(inMessage).toArray()
);
}
private static void saveMessage(InMessage inMessage) throws Exception{
//1.存储原始消息
getMessageDao().saveOrUpdateMessage(inMessage);
//2.按照tos拆分成不同消息
for(String to : inMessage.getTos()){
Message message = new Message(inMessage,to);
getMessageDao().saveOrUpdateMessage(message);
}
}
private static void handlerServerMessage(String type, InMessage inMessage) throws Exception {
MessageConstant.ClientMessageType clientMessageType = MessageConstant.ClientMessageType.valueOf(type);
String data = inMessage.getData();
OutMessage outMessage = null;
//1. 处理消息
switch(clientMessageType){
case Ping: {
PingMessage inSysData = JacksonUtil.jsonToBean(data, PingMessage.class);
if (null != inSysData.getData()) {
ChannelManager.versionChannel(ChannelManager.getCurrentChannel(), inSysData.getData().getMajor(), inSysData.getData().getMinor());
}
outMessage = new OutMessage(JacksonUtil.beanToJson(new PongMessage()));
break;
}
case Auth: {
boolean authSuccess = false;
AuthMessage inSysData = JacksonUtil.jsonToBean(data, AuthMessage.class);
if(null != inSysData.getData()){
if(StrUtil.isNotEmpty(inSysData.getData().getToken())) {
String userId = getUserService().getUserIdByToken(inSysData.getData().getToken());
if(StrUtil.isNotEmpty(userId)){
ChannelManager.authChannel(ChannelManager.getCurrentChannel(),userId,inSysData.getData().getMajor(),inSysData.getData().getMinor());
onClientOnLine(MessageConstant.DomainType.User,userId);
authSuccess = true;
}
}
}
if(!authSuccess){
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ChannelStatusMessage(false,0L,MessageConstant.Error.AuthFailed))
);
}else{
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ChannelStatusMessage(true,0L,MessageConstant.Error.Ok))
);
}
break;
}
case GetChannelStatus: {
WrapperedChannel wrapperedChannel = ChannelManager.getWrapperedChannelByChannel(ChannelManager.getCurrentChannel());
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ChannelStatusMessage(wrapperedChannel.isAuthed(),
wrapperedChannel.getOnlineSeconds(),
MessageConstant.Error.Ok))
);
break;
}
case Ack: {
//根据id找到
boolean ackSuccess = false;
AckMessage inSysData = JacksonUtil.jsonToBean(data, AckMessage.class);
if(null != inSysData.getData()){
updateMessageAckStatus(inSysData.getData().getAckId());
ackSuccess = true;
}
if(!ackSuccess){
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ServerAckMessage(MessageConstant.Error.AckParameterError))
);
}
//没有错误不回复消息
break;
}
case HasRead: {
boolean hasReadSuccess = false;
HasReadMessage inSysData = JacksonUtil.jsonToBean(data, HasReadMessage.class);
if(null != inSysData.getData()){
updateMessageHasReadStatus(
inSysData.getData().getFromDomain(),inSysData.getData().getFromUserId(),
inMessage.getFromDomain().name(),inMessage.getFrom(), inSysData.getData().getTime(),(byte)1
);
hasReadSuccess = true;
}
if(!hasReadSuccess){
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ServerAckMessage(MessageConstant.Error.AckParameterError))
);
}
//没有错误不回复消息
break;
}
case SetMsgSuccess: {
boolean setStatusSuccess = false;
SetSuccessStatusMessage inSysData = JacksonUtil.jsonToBean(data, SetSuccessStatusMessage.class);
if(null != inSysData.getData() && StrUtil.isNotEmpty(inSysData.getData().getMsgId())){
updateMessageStatus(inSysData.getData().getMsgId(), MessageConstant.Status.Succeed);
setStatusSuccess = true;
}
if(!setStatusSuccess){
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ServerAckMessage(MessageConstant.Error.SetStatusParameterError))
);
}else{
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ServerAckMessage(MessageConstant.Error.Ok))
);
}
break;
}
case SetMsgReverted: {
boolean setStatusSuccess = false;
SetRevertedStatusMessage inSysData = JacksonUtil.jsonToBean(data, SetRevertedStatusMessage.class);
if(null != inSysData.getData() && StrUtil.isNotEmpty(inSysData.getData().getMsgId())){
updateMessageStatus(inSysData.getData().getMsgId(), MessageConstant.Status.Reverted);
setStatusSuccess = true;
}
if(!setStatusSuccess){
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ServerAckMessage(MessageConstant.Error.SetStatusParameterError))
);
}else{
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ServerAckMessage(MessageConstant.Error.Ok))
);
}
break;
}
case SetMsgDeleted: {
boolean setStatusSuccess = false;
SetDeletedStatusMessage inSysData = JacksonUtil.jsonToBean(data, SetDeletedStatusMessage.class);
if(null != inSysData.getData() && StrUtil.isNotEmpty(inSysData.getData().getMsgId())){
updateMessageStatus(inSysData.getData().getMsgId(), MessageConstant.Status.Deleted);
setStatusSuccess = true;
}
if(!setStatusSuccess){
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ServerAckMessage(MessageConstant.Error.SetStatusParameterError))
);
}else{
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ServerAckMessage(MessageConstant.Error.Ok))
);
}
break;
}
case ClientIdleClosed: {
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ServerAckMessage(
MessageConstant.Error.ChannelIdle.joinExtra(String.valueOf(getSettingProps().getKeepAlive().getMaxIdleSeconds()))
)
)
);
break;
}
case UnExceptedError: {
UnExceptedErrorMessage inSysData = JacksonUtil.jsonToBean(data, UnExceptedErrorMessage.class);
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ServerAckMessage(
MessageConstant.Error.UnExpectedError.joinExtra(inSysData.getData().getErrorString())
)
)
);
break;
}
case ClientAuthTimeOut:{
outMessage = new OutMessage(JacksonUtil.beanToJson(
new ServerAckMessage(MessageConstant.Error.ChannelAuthTimeOut)
)
);
break;
}
default: break;
}
//2.结果应答
if(null != outMessage) {
ClientManager.sendServerMessage(inMessage.getFromDomain(),
OutMessageSet.newInstance().ackId(null).add(outMessage)
);
}
}
private static void onClientOnLine(MessageConstant.DomainType domain,String userId){
getMessageDao().updateMessageStatusToPending(domain,userId);
addClientToRedisUnPendingSet(CcMessageUtil.getDomainTypeAndUserIdString(domain,userId));
}
private static void updateMessageAckStatus(String ackId) throws Exception {
String ackKey = RedisKeyManager.getAckSetKey(ackId);
//1.从redis中获取ackId对应的set列表
if(!RedisUtil.hasKey(ackKey)) {
return;
}
//2.从redis中获取set集合,并删除ackId对应的set列表
Set<Object> ackMessageSet = RedisUtil.sGet(ackKey);
RedisUtil.del(ackKey);
//2.更新msg的ack标志
if (CollectionUtil.isNotEmpty(ackMessageSet)) {
for (Object msgId : ackMessageSet) {
Message message = getMessageDao().getMessageById((String) msgId);
if(message.getRule().getAckIsSuccess() == 0) {
getMessageDao().updateMessageAckAndStatus((String) msgId, (byte)1,MessageConstant.Status.TempSucceed);
}else{
getMessageDao().updateMessageAckAndStatus((String) msgId, (byte)1,MessageConstant.Status.Succeed);
}
}
}
//3.查找该用户是否仍然有未ack消息,
addClientToRedisUnPendingSet(ackId);
}
private static void updateMessageHasReadStatus(String fromDomain, String fromUserId,String toDomain, String toUserId,
Long time, byte hasRead) throws Exception{
getMessageDao().updateMessageReadStatus(fromDomain,fromUserId,toDomain,toUserId,time,hasRead);
}
private static void updateMessageStatus(String rawId, MessageConstant.Status status) throws Exception {
getMessageDao().updateMessageStatusByRawId(rawId,status);
if(status == MessageConstant.Status.Reverted){
List<Message> messageList = getMessageDao().getMessageByRawId(rawId);
if(CollectionUtil.isNotEmpty(messageList)){
//ClientManager.sendServerMessage();
//为了保证投递到目标客户端,将该消息添加到消息队列中,进行投递。
for(Message message : messageList) {
Message invertedMessage = new Message(
MessageConstant.DomainType.Server, "", message.getToDomain(),message.getTo(),
JacksonUtil.beanToJson(new InvertedMessage(message.getId())),MessageRule.defaultRule(MessageConstant.DomainType.Server)
);
getMessageDao().saveOrUpdateMessage(invertedMessage);
}
}
}
}
private static void addClientToRedisUnPendingSet(String domainTypeAndUserId){
//如果有未ack消息并且不在当前待处理列表中,则添加
String redisUnPendingClientSetKey = RedisKeyManager.getPendingClientSetKey();
String redisWaitAckSetKey = RedisKeyManager.getAckSetKey(domainTypeAndUserId);
String []stringArray = CcMessageUtil.splitTypeAndUserId(domainTypeAndUserId);
MessageConstant.DomainType toDomain = MessageConstant.DomainType.valueOf(stringArray[0]);
String to = stringArray[1];
//1.1 当前用户是否在pendingClients列表中
if (!RedisUtil.sHas(redisUnPendingClientSetKey,domainTypeAndUserId)) {
//1.2 当前用户是否在redis的等待ack列表中
if(!RedisUtil.hasKey(redisWaitAckSetKey)){
//1.3 当前用户是否有pending消息
if(getMessageDao().countClientPendingMessage(toDomain,to) > 0){
//1.4 将当前用户添加到redisUnPendingClientSet列表中排队处理
RedisUtil.sSet(redisUnPendingClientSetKey,domainTypeAndUserId);
}
}
}
}
}

31
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/AckMessage.java

@ -0,0 +1,31 @@
package com.ccsens.ccmq.lowlevel.message.client;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
/**
* @author wei
*/
@Data
public class AckMessage extends ServerMessage {
@Setter
@Getter
public static class Data {
String ackId;
}
private Data data;
public AckMessage(){
setType(MessageConstant.ClientMessageType.Ack.name());
}
public AckMessage(String ackId){
this();
data = new Data();
data.setAckId(ackId);
}
}

36
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/AuthMessage.java

@ -0,0 +1,36 @@
package com.ccsens.ccmq.lowlevel.message.client;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
/**
* @author wei
* 客户端认证 (user)
*/
@Data
public class AuthMessage extends ServerMessage {
@Setter
@Getter
public static class Data{
private String token;
private int major;
private int minor;
}
private Data data;
public AuthMessage(){
setType(MessageConstant.ClientMessageType.Auth.name());
}
public AuthMessage(String token,int major,int minor){
this();
data = new Data();
data.setToken(token);
data.setMajor(major);
data.setMinor(minor);
}
}

16
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/ClientAuthTimeOutMessage.java

@ -0,0 +1,16 @@
package com.ccsens.ccmq.lowlevel.message.client;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
/**
* @author wei
* 客户端向服务器请求当前连接状态
*/
@Data
public class ClientAuthTimeOutMessage extends ServerMessage {
public ClientAuthTimeOutMessage(){
setType(MessageConstant.ClientMessageType.ClientAuthTimeOut.name());
}
}

16
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/ClientIdleClosedMessage.java

@ -0,0 +1,16 @@
package com.ccsens.ccmq.lowlevel.message.client;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
/**
* @author wei
* 客户端向服务器请求当前连接状态
*/
@Data
public class ClientIdleClosedMessage extends ServerMessage {
public ClientIdleClosedMessage(){
setType(MessageConstant.ClientMessageType.ClientIdleClosed.name());
}
}

16
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/GetStatusMessage.java

@ -0,0 +1,16 @@
package com.ccsens.ccmq.lowlevel.message.client;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
/**
* @author wei
* 客户端向服务器请求当前连接状态
*/
@Data
public class GetStatusMessage extends ServerMessage {
public GetStatusMessage(){
setType(MessageConstant.ClientMessageType.GetChannelStatus.name());
}
}

36
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/HasReadMessage.java

@ -0,0 +1,36 @@
package com.ccsens.ccmq.lowlevel.message.client;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
/**
* @author wei
*/
@Data
public class HasReadMessage extends ServerMessage {
/**
* fromDomain域的fromUserId用户 给我发送的所有 时间<lastMsgId时间的消息 都已读
*/
@Setter
@Getter
public static class Data {
private Long time;
private String fromUserId;
private String fromDomain;
}
private Data data;
public HasReadMessage(){
setType(MessageConstant.ClientMessageType.HasRead.name());
}
public HasReadMessage(Long time){
this();
data = new Data();
data.setTime(time);
}
}

32
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/PingMessage.java

@ -0,0 +1,32 @@
package com.ccsens.ccmq.lowlevel.message.client;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
/**
* @author wei
*/
@Data
public class PingMessage extends ServerMessage {
@Setter
@Getter
public static class Data{
private Integer major;
private Integer minor;
}
private Data data;
public PingMessage(){
setType(MessageConstant.ClientMessageType.Ping.name());
}
public PingMessage(Integer major,Integer minor){
this();
data = new Data();
data.setMajor(major);
data.setMinor(minor);
}
}

31
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/SetDeletedStatusMessage.java

@ -0,0 +1,31 @@
package com.ccsens.ccmq.lowlevel.message.client;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
/**
* @author wei
*/
@Data
public class SetDeletedStatusMessage extends ServerMessage {
@Setter
@Getter
public static class Data {
String msgId;
}
private Data data;
public SetDeletedStatusMessage(){
setType(MessageConstant.ClientMessageType.SetMsgDeleted.name());
}
public SetDeletedStatusMessage(String msgId){
this();
data = new Data();
data.setMsgId(msgId);
}
}

31
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/SetRevertedStatusMessage.java

@ -0,0 +1,31 @@
package com.ccsens.ccmq.lowlevel.message.client;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
/**
* @author wei
*/
@Data
public class SetRevertedStatusMessage extends ServerMessage {
@Setter
@Getter
public static class Data {
String msgId;
}
private Data data;
public SetRevertedStatusMessage(){
setType(MessageConstant.ClientMessageType.SetMsgReverted.name());
}
public SetRevertedStatusMessage(String msgId){
this();
data = new Data();
data.setMsgId(msgId);
}
}

31
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/client/SetSuccessStatusMessage.java

@ -0,0 +1,31 @@
package com.ccsens.ccmq.lowlevel.message.client;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
/**
* @author wei
*/
@Data
public class SetSuccessStatusMessage extends ServerMessage {
@Setter
@Getter
public static class Data {
String msgId;
}
private Data data;
public SetSuccessStatusMessage(){
setType(MessageConstant.ClientMessageType.SetMsgSuccess.name());
}
public SetSuccessStatusMessage(String msgId){
this();
data = new Data();
data.setMsgId(msgId);
}
}

95
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/InMessage.java

@ -0,0 +1,95 @@
package com.ccsens.ccmq.lowlevel.message.common;
import cn.hutool.core.date.DateUtil;
import wiki.tall.ccmq.common.util.JacksonUtil;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.Data;
import java.util.*;
/**
* @author wei
*/
@Data
public class InMessage {
/**
* 消息ID
*/
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private String id;
/**
* 发送时间(s)
* Notice: 指的是服务器收到发送请求的时间不是服务器发出消息的时间
*/
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Long time;
/**
* 消息来自于那个域
*/
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private MessageConstant.DomainType fromDomain;
/**
* 发送者信息
*/
private String from;
/**
* 消息要发送到哪个域
*/
private MessageConstant.DomainType toDomain;
/**
* 接受者信息列表
*/
private Set<String> tos;
/**
* 消息的标示符通常是由用户传过来的消息ID该消息在用户系统中的ID
*/
private String unikey;
/**
* 发送规则
* DeSerialize but not serialize @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
*/
private MessageRule rule;
/**
* 发送内容
* 如果toDomain是Server 代表消息是发给当前服务器的必须是MessageSysData的子类型
* 其他格式不限由用户指定
*/
private String data;
public InMessage(){
this.time = DateUtil.currentSeconds();
}
public static InMessage newToServerMessage(MessageConstant.DomainType fromDomain,ServerMessage serverMessage) throws JsonProcessingException {
InMessage inMessage = new InMessage();
inMessage.setFromDomain(fromDomain);
inMessage.setToDomain(MessageConstant.DomainType.Server);
inMessage.setData(JacksonUtil.beanToJson(serverMessage));
return inMessage;
}
public static InMessage newToQueueMessage(String from, Set<String> tos, String unikey, MessageRule rule, String data) throws JsonProcessingException {
InMessage inMessage = new InMessage();
inMessage.setToDomain(MessageConstant.DomainType.Queue);
inMessage.setFrom(from);
inMessage.setTos(tos);
inMessage.setUnikey(unikey);
inMessage.setRule(rule);
inMessage.setData(data);
return inMessage;
}
public static InMessage newToUserMessage(String from, Set<String> tos, String unikey, MessageRule rule, String data) throws JsonProcessingException {
InMessage inMessage = new InMessage();
inMessage.setToDomain(MessageConstant.DomainType.User);
inMessage.setFrom(from);
inMessage.setTos(tos);
inMessage.setUnikey(unikey);
inMessage.setRule(rule);
inMessage.setData(data);
return inMessage;
}
//TODO
//添加方便链式调用的构造方法,类似builder
}

134
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/Message.java

@ -0,0 +1,134 @@
package com.ccsens.ccmq.lowlevel.message.common;
import wiki.tall.ccmq.common.util.DateUtil;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* @author wei
*/
@Data
public class Message {
/**
* 消息ID (Message's ID)
*/
private String id;
/**
* 原始消息ID (InMessage's ID)
*/
private String rawId;
/**
* 发送时间(s)
* Notice: 指的是服务器收到发送请求的时间不是服务器发出消息的时间
*/
private Long time;
/**
* 消息来自于那个域
*/
private MessageConstant.DomainType fromDomain;
/**
* 发送者信息
*/
private String from;
/**
* 消息要发送到哪个域
*/
private MessageConstant.DomainType toDomain;
/**
* 接受者信息列表
*/
private String to;
/**
* 发送规则
* DeSerialize but not serialize @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
*/
private MessageRule rule;
/**
* 发送内容
* 如果toDomain是Server 代表消息是发给当前服务器的必须是MessageSysData的子类型
* 其他格式不限由用户指定
*/
private String data;
/**
* 是否收到用户的ack消息
*/
private byte acked;
/**
* 是否收到用户的已读消息
*/
private byte hasRead;
/**
* 消息状态
* 发送成功标志根据配置由三种情况
* 1. 配置不需要客户端ack
* 发送完毕自动设置 ack = true;
* rule -> ackIsSuccess = true 发送即代表成功
* rule -> ackIsSuccess = false 等待用户手动设置成功标志
* 2. 配置需要ack则发送并受到ack代表成功
* rule -> ackIsSuccess = true 发送并收到ack即代表成功
* rule -> ackIsSuccess = false 等待用户手动设置成功标志
*/
private MessageConstant.Status status;
/**
* 发送次数
*/
private int sendTimes;
/**
* 发送时间
*/
private List<Long> sendTimeInSecondList;
public Message(){
}
public Message(MessageConstant.DomainType fromDomain,String from,MessageConstant.DomainType toDomain,String to,String data,MessageRule rule){
this.time = DateUtil.currentSeconds();
this.fromDomain = fromDomain;
this.from = from;
this.toDomain = toDomain;
this.to = to;
this.data = data;
this.rule = rule;
}
public Message(InMessage inEntity, String to){
this.rawId = inEntity.getId();
this.time = inEntity.getTime();
this.fromDomain = inEntity.getFromDomain();
this.from = inEntity.getFrom();
this.toDomain = inEntity.getToDomain();
this.to = to;
this.rule = inEntity.getRule();
this.data = inEntity.getData();
this.acked = 0;
this.hasRead = 0;
this.status = MessageConstant.Status.Pending;
this.sendTimes = 0;
}
public void incrementSendTimes() {
this.sendTimes++;
if(this.sendTimeInSecondList == null){
this.sendTimeInSecondList = new ArrayList<>();
}
this.sendTimeInSecondList.add(DateUtil.currentSeconds());
}
public boolean isSendTimesUpLimit() {
if((rule.getNoAckRetryTimes() > 0) && (sendTimes >= rule.getNoAckRetryTimes())){
return true;
}
return false;
}
public boolean isExpired() {
return DateUtil.currentSeconds() >= rule.getExpireAt();
}
}

217
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/MessageConstant.java

@ -0,0 +1,217 @@
package com.ccsens.ccmq.lowlevel.message.common;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* @author wei
* 消息相关常量
*/
public class MessageConstant {
public enum ClientMessageType{
//客户端心跳
Ping(0x00),
//客户端认证
Auth(0x01),
//客户端收到消息ACK
Ack(0x02),
//客户端收到消息ACK
HasRead(0x03),
//客户端请求连接状态
GetChannelStatus(0x04),
//不可预期的错误
UnExceptedError(0x21),
ClientIdleClosed(0x22),
ClientAuthTimeOut(0x23),
//设置消息状态消息(disable撤销消息,适用于,消息撤回),针对消息本身(eg:消息撤回)
SetMsgSuccess(0x52),
SetMsgReverted(0x53),
SetMsgDeleted(0x54);
public int value;
ClientMessageType(int value){
this.value = value;
}
/**
* 从int到enum的转换函数
* @param value 枚举int值
* @return 对应的枚举找不到则返回null
*/
public static ClientMessageType valueOf(int value) {
for(ClientMessageType type : values()){
if(type.value == value){
return type;
}
}
return null;
}
}
public enum ServerMessageType{
//客户端心跳
Pong(0x00),
//客户端收到消息ACK
Ack(0x02),
//客户端请求连接状态
ChannelStatus(0x03);
//撤销某个消息
//DelMessage(0x04),
//客户端请求连接状态
//QueueStatus(0x05);
public int value;
ServerMessageType(int value){
this.value = value;
}
/**
* 从int到enum的转换函数
* @param value 枚举int值
* @return 对应的枚举找不到则返回null
*/
public static ServerMessageType valueOf(int value) {
for(ServerMessageType type : values()){
if(type.value == value){
return type;
}
}
return null;
}
}
/**
* JsonFormat是Json Serialize相关配置
*/
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Error{
//Ok
Ok(200,"Ok"),
/**
* 通用消息错误
*/
//消息无接收者错误
MessageNoReceiversError(1001,"[用户]消息至少应该有一个接收者"),
//消息无数据错误
MessageNoDataError(1002,"不允许消息内容为空"),
/**
* server消息错误
*/
//server消息无type错误
MessageNoTypeError(1003,"发送至Server域的消息必须有type字段"),
//Ack参数错误,没有找到对应的msgId
AckParameterError(1103,"Ack参数错误,没有找到对应的msgId"),
//SetSuccess参数错误,没有找到对应的msgId
SetSuccessParameterError(1104,"SetSuccess参数错误,没有找到对应的msgId"),
//SetStatusParameterError
SetStatusParameterError(1105,"SetStatus参数错误,没有找到对应的msgId"),
//HasRead参数错误,没有找到对应的msgId
HasReadParameterError(1106,"HasRead参数错误,没有找到对应的msgId"),
/**
* 身份认证错误
*/
//无权限
UnAuthed(1021, "未认证的用户"),
/**
* 业务错误
*/
//认证失败
AuthFailed(1301,"认证失败"),
//空闲断开连接(连续Ns没有收到数据)
ChannelIdle(1302,"连接断开:连续N秒没有从收到客户端收到任何数据"),
//认证超时断开连接
ChannelAuthTimeOut(1303,"连接断开:认证超时"),
//不可预期错误
UnExpectedError(1304,"不可预期异常");
public int code;
public String text;
public String extra;
Error(int code,String text) {
this.code = code;
this.text = text;
}
Error(int code,String text,String extra) {
this.code = code;
this.text = text;
this.extra = extra;
}
public Error joinExtra(String extra){
this.extra = extra;
return this;
}
}
/**
* (UserQueueRestServer)
*/
public enum DomainType{
//Netty Client
User(1),
//Queue Client
Queue(2),
//Rest Client
Rest(3),
//系统
Server(4);
public int value;
DomainType(int value){
this.value = value;
}
public static DomainType valueOf(int value) {
for(DomainType domainType : values()){
if(domainType.value == value){
return domainType;
}
}
return null;
}
}
public enum Status{
//未决状态(未完成)
Pending(0),
//发送成功(投递成功)
Succeed(1),
//发送失败(投递失败)
Failed(2),
//消息过期
Expired(3),
//消息被撤回
Reverted(4),
//消息被删除
Deleted(5),
//消息达到重试次数上限
SendTimesUpLimit(6),
//临时完成状态,当ackIsSuccess==0时,一旦ack设置消息为此状态
TempSucceed(10);
public int value;
Status(int value){
this.value = value;
}
public static Status valueOf(int value){
for(Status status : values()){
if(status.value == value){
return status;
}
}
return null;
}
}
}

80
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/MessageRule.java

@ -0,0 +1,80 @@
package com.ccsens.ccmq.lowlevel.message.common;
import lombok.Data;
/**
* 发送规则实体类
* @author wei
*/
@Data
public class MessageRule {
public enum AckRule{
//不需要ack
NONE,
//产生错误时回复ack
ERROR,
//总是回复ack
ALWAYS
}
/**
* 离线丢弃标志
*/
private byte offlineDiscard;
/**
* 消息是否需要ack如果不需要ack则发送完毕即代表成功
*/
private AckRule ackRule;
/**
* 没有收到ack重试次数
*/
private Integer noAckRetryTimes;
/**
* 收到ack代表发送成功不再发送
* 如果该标志为0则代表每次上线都发送直到用户手动设置成功
*/
private byte ackIsSuccess;
/**
* 消息过期时间(s)
*/
private Long expireAt;
public MessageRule(){
}
public MessageRule(byte offlineDiscard,AckRule ackRule,Integer noAckRetryTimes,byte ackIsSuccess){
this.offlineDiscard = offlineDiscard;
this.ackRule = ackRule;
this.noAckRetryTimes = noAckRetryTimes;
this.ackIsSuccess = ackIsSuccess;
}
public MessageRule(byte offlineDiscard,AckRule ackRule,Integer noAckRetryTimes,byte ackIsSuccess,Long expireAt){
this.offlineDiscard = offlineDiscard;
this.ackRule = ackRule;
this.noAckRetryTimes = noAckRetryTimes;
this.ackIsSuccess = ackIsSuccess;
this.expireAt = expireAt;
}
public static MessageRule defaultRule(MessageConstant.DomainType fromDomain) {
MessageRule messageRule = null;
switch(fromDomain) {
case User:
messageRule = new MessageRule((byte) 0, AckRule.ALWAYS, 10, (byte) 1,0L);
break;
case Queue:
messageRule = new MessageRule((byte) 1, AckRule.ALWAYS, 10, (byte) 1,0L);
break;
case Rest:
messageRule = new MessageRule((byte) 1, AckRule.ALWAYS, 10, (byte) 1,0L);
break;
case Server:
messageRule = new MessageRule((byte) 1, AckRule.ALWAYS, 10, (byte) 1,0L);
break;
default:
break;
}
return messageRule;
}
}

71
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/OutMessage.java

@ -0,0 +1,71 @@
package com.ccsens.ccmq.lowlevel.message.common;
import cn.hutool.core.date.DateUtil;
import lombok.Data;
/**
* @author wei
*/
@Data
public class OutMessage {
/**
* 消息ID
*/
private String id;
/**
* sender发送消息时间(s)
* Notice: 指的是服务器收到发送请求的时间不是服务器发出消息的时间服务器发出消息的时间客户端很好确定就是当前时间
*/
private Long time;
/**
* 消息来自于那个域通常不需要知道toDomain
*/
private MessageConstant.DomainType fromDomain;
/**
* 发送者信息
*/
private String from;
/**
* 如果toDomain是Server 代表消息是发给当前服务器的必须是MessageSysData的子类型
* 其他格式不限由用户指定消息系统会将data字段原封不动投递到接收方由接收方进行解析
*/
private String data;
public OutMessage(){
}
public OutMessage(String id, Long time, String from, String data){
this.id = id;
this.time = time;
this.from = from;
this.data = data;
}
public OutMessage(InMessage messageEntity){
this.id = messageEntity.getId();
this.time = messageEntity.getTime();
this.fromDomain = messageEntity.getFromDomain();
this.from = messageEntity.getFrom();
this.data = messageEntity.getData();
}
public OutMessage(String data){
this.time = DateUtil.currentSeconds();
this.fromDomain = MessageConstant.DomainType.Server;
this.data = data;
}
public OutMessage(MessageConstant.DomainType fromDomain, String data) {
this.time = DateUtil.currentSeconds();
this.fromDomain = fromDomain;
this.data = data;
}
public OutMessage(Message message){
this.id = message.getId();
this.time = message.getTime();
this.fromDomain = message.getFromDomain();
this.from = message.getFrom();
this.data = message.getData();
}
}

43
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/OutMessageSet.java

@ -0,0 +1,43 @@
package com.ccsens.ccmq.lowlevel.message.common;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* @author __zHangSan
*/
@Getter @Setter @ToString
public class OutMessageSet {
private String ackId;
private Set<OutMessage> messageSet;
public OutMessageSet ackId(String ackId){
this.ackId = ackId;
return this;
}
public static OutMessageSet newInstance(){
return new OutMessageSet();
}
public OutMessageSet add(OutMessage messageOutEntity){
if(messageSet == null){
messageSet = new HashSet<>();
}
messageSet.add(messageOutEntity);
return this;
}
public OutMessageSet addAll(Collection<OutMessage> theMessageSet){
if(messageSet == null){
messageSet = new HashSet<>();
}
messageSet.addAll(theMessageSet);
return this;
}
}

11
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/common/ServerMessage.java

@ -0,0 +1,11 @@
package com.ccsens.ccmq.lowlevel.message.common;
import lombok.Data;
/**
* @author wei
*/
@Data
public class ServerMessage {
private String type;
}

37
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/server/ChannelStatusMessage.java

@ -0,0 +1,37 @@
package com.ccsens.ccmq.lowlevel.message.server;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
/**
* @author zhangsan
*/
@Data
public class ChannelStatusMessage extends ServerMessage {
@Setter
@Getter
public static class Data{
//认证状态
private Boolean authed;
//已认证时长(s)
private Long onlineSeconds;
//错误信息
private MessageConstant.Error error;
}
private Data data;
public ChannelStatusMessage(){
setType(MessageConstant.ServerMessageType.ChannelStatus.name());
}
public ChannelStatusMessage(Boolean authed,Long onlineSeconds,MessageConstant.Error error){
this();
data = new Data();
data.authed = authed;
data.onlineSeconds = onlineSeconds;
data.error = error;
}
}

28
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/server/InvertedMessage.java

@ -0,0 +1,28 @@
package com.ccsens.ccmq.lowlevel.message.server;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Getter;
import lombok.Setter;
/**
* @author __zHangSan
*/
public class InvertedMessage extends ServerMessage {
@Setter
@Getter
public static class Data{
private String msgId;
}
private Data data;
public InvertedMessage(){
setType(MessageConstant.ServerMessageType.Pong.name());
}
public InvertedMessage(String msgId){
this();
data = new Data();
data.setMsgId(msgId);
}
}

15
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/server/PongMessage.java

@ -0,0 +1,15 @@
package com.ccsens.ccmq.lowlevel.message.server;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
/**
* @author zhangsan
*/
@Data
public class PongMessage extends ServerMessage {
public PongMessage(){
setType(MessageConstant.ServerMessageType.Pong.name());
}
}

30
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/server/QueueStatusMessage.java

@ -0,0 +1,30 @@
package com.ccsens.ccmq.lowlevel.message.server;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
/**
* @author zhangsan
*/
@Data
public class QueueStatusMessage extends ServerMessage {
@Setter
@Getter
public static class Data{
private MessageConstant.Error error;
}
private Data data;
public QueueStatusMessage(){
setType(MessageConstant.ServerMessageType.ChannelStatus.name());
}
public QueueStatusMessage(MessageConstant.Error error){
this();
data = new Data();
data.error = error;
}
}

49
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/server/ServerAckMessage.java

@ -0,0 +1,49 @@
package com.ccsens.ccmq.lowlevel.message.server;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
/**
* @author zhangsan
*/
@Data
public class ServerAckMessage extends ServerMessage {
@lombok.Data
public static class Data{
/**
* 消息ID
*/
private String msgId;
/**
* 发送者指定的unikey如果发送者未指定则为null
*/
private String unikey;
/**
* 消息状态
*/
private MessageConstant.Error error;
public Data(String msgId,String unikey,MessageConstant.Error error){
this.msgId = msgId;
this.unikey = unikey;
this.error = error;
}
}
private Data data;
public ServerAckMessage(){
setType(MessageConstant.ServerMessageType.Ack.name());
}
public ServerAckMessage(MessageConstant.Error status){
this();
this.data = new Data(null,null,status);
}
public ServerAckMessage(String msgId,String unikey,MessageConstant.Error status){
this();
this.data = new Data(msgId,unikey,status);
}
}

31
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/message/server/UnExceptedErrorMessage.java

@ -0,0 +1,31 @@
package com.ccsens.ccmq.lowlevel.message.server;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.ccsens.ccmq.lowlevel.message.common.ServerMessage;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
/**
* @author wei
* 客户端向服务器请求当前连接状态
*/
@Data
public class UnExceptedErrorMessage extends ServerMessage {
@Getter@Setter
public static class Data{
private String errorString;
}
private Data data;
public UnExceptedErrorMessage(){
setType(MessageConstant.ClientMessageType.UnExceptedError.name());
}
public UnExceptedErrorMessage(String errorString){
this();
data = new Data();
data.setErrorString(errorString);
}
}

118
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/persist/IMessageDao.java

@ -0,0 +1,118 @@
package com.ccsens.ccmq.lowlevel.persist;
import com.ccsens.ccmq.lowlevel.message.common.InMessage;
import com.ccsens.ccmq.lowlevel.message.common.Message;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import java.util.List;
/**
* @author wei
*/
public interface IMessageDao {
/**
* 保存原始消息
* @param inMessage message to be saved
* @throws Exception 可能产生的异常
*/
void saveOrUpdateMessage(InMessage inMessage) throws Exception;
/**
* 保存message
* @param message message to be saved
* @throws Exception 可能产生的异常
*/
void saveOrUpdateMessage(Message message) throws Exception;
/**
* 更新消息的某个接受者的hasRead状态
* @param fromDomain 消息fromDomain
* @param fromUserId 消息from
* @param toDomain 消息toDomain
* @param toUserId 接受者ID
* @param time 该time之前包括自己的消息
* @param hasRead 是否已读
* @throws Exception
*/
void updateMessageReadStatus(String fromDomain, String fromUserId, String toDomain, String toUserId, Long time, byte hasRead)throws Exception;
/**
* 更新消息的某个接受者的 ack和success状态
* @param msgId 消息ID
* @param acked 是否ack
* @param status status
*/
void updateMessageAckAndStatus(String msgId, byte acked, MessageConstant.Status status);
/**
* 根据rawId修改message status
* @param rawId 原始消息ID
* @param status 要修改的状态
*/
void updateMessageStatusByRawId(String rawId, MessageConstant.Status status);
/**
* 更新消息状态
* @param msgId
* @param status NormalDeleted
*/
void updateMessageStatus(String msgId, MessageConstant.Status status);
/**
* 更新所有的status==TempSucceed的消息为pending
*/
void updateMessageStatusToPending();
/**
* 更新所有的status==TempSucceed的消息为pending
* @param domainType
* @param userId 用户
*/
void updateMessageStatusToPending(MessageConstant.DomainType domainType, String userId);
/**
* 检查pending消息是否过期如果是设置为expired状态
*/
void updateMessageToExpired();
/**
* 检查pending消息是否达到发送上限如果是设置为SendTimesUpLimit状态
*/
void updateMessageToSendTimesUpLimit();
/**
* 增加某个消息的发送次数并添加一条发送记录
* @param id 消息ID
* @param time 发送时间
*/
void incrementSendTimes(String id, Long time);
/**
* 根据ID获取MessageEntity
* @param msgId 消息ID
* @return 消息实体类
*/
Message getMessageById(String msgId);
/**
* 根据ID获取MessageEntity
* @param rawId 消息ID
* @return 消息实体类集合
*/
List<Message> getMessageByRawId(String rawId);
/**
* 获取某个客户端pending的消息集合最多获取maxMessageNum个
* @param toDomain 消息的接收域
* @param to 消息的接收者Id
* @param maxMessageNum 最多查询数量
* @return 消息集合
*/
List<Message> getClientPendingMessage(MessageConstant.DomainType toDomain, String to, Integer maxMessageNum);
/**
* 获取toDomain域to用户的未ack消息数量
* @param toDomain
* @param to 用户
* @return 未ack消息数量
*/
Long countClientPendingMessage(MessageConstant.DomainType toDomain, String to);
}

180
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/persist/MessageDao.java

@ -0,0 +1,180 @@
package com.ccsens.ccmq.lowlevel.persist;
import com.ccsens.ccmq.lowlevel.message.common.InMessage;
import com.ccsens.ccmq.lowlevel.message.common.Message;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;
import wiki.tall.ccmq.common.util.DateUtil;
import java.util.List;
/**
* @author wei
*/
@Repository
public class MessageDao implements IMessageDao {
private static final String COLLECTION_RAW_MESSAGE = "col_message_raw";
private static final String COLLECTION_MESSAGE = "col_message";
@Autowired
private MongoTemplate mongoTemplate;
@Override
public void saveOrUpdateMessage(InMessage inMessage) throws Exception {
mongoTemplate.save(inMessage,COLLECTION_RAW_MESSAGE);
}
@Override
public void saveOrUpdateMessage(Message message) throws Exception {
mongoTemplate.save(message,COLLECTION_MESSAGE);
}
@Override
public void updateMessageReadStatus(String fromDomain,String fromUserId,String toDomain,String toUserId,Long time,byte hasRead) throws Exception {
Query query = new Query(
Criteria.where("fromDomain").is(fromDomain).andOperator(
Criteria.where("from").is(fromUserId).andOperator(
Criteria.where("toDomain").is(toDomain).andOperator(
Criteria.where("to").is(toUserId).andOperator(
Criteria.where("time").lte(time)
)
)
))
);
Update update = new Update().set("hasRead",hasRead);
mongoTemplate.updateMulti(query,update, Message.class,COLLECTION_MESSAGE);
}
@Override
public void updateMessageAckAndStatus(String msgId, byte acked, MessageConstant.Status status) {
Query query = new Query(Criteria.where("id").is(msgId));
Update update = new Update().set("acked",acked).set("status",status);
mongoTemplate.updateFirst(query,update, Message.class,COLLECTION_MESSAGE);
}
@Override
public void updateMessageStatusByRawId(String rawId, MessageConstant.Status status) {
Query query = new Query(Criteria.where("rawId").is(rawId));
Update update = new Update().set("status",status);
mongoTemplate.updateFirst(query,update, Message.class,COLLECTION_MESSAGE);
}
@Override
public void updateMessageStatus(String msgId, MessageConstant.Status status) {
Query query = new Query(Criteria.where("id").is(msgId));
Update update = new Update().set("status",status);
mongoTemplate.updateFirst(query,update, Message.class,COLLECTION_MESSAGE);
}
@Override
public void updateMessageStatusToPending() {
Query query = new Query(Criteria.where("status").is(MessageConstant.Status.TempSucceed));
Update update = new Update().set("status",MessageConstant.Status.Pending);
mongoTemplate.updateMulti(query,update, Message.class,COLLECTION_MESSAGE);
}
@Override
public void updateMessageStatusToPending(MessageConstant.DomainType domainType, String userId) {
Query query = new Query()
.addCriteria(Criteria.where("toDomain").is(domainType))
.addCriteria(Criteria.where("to").is(userId))
.addCriteria(Criteria.where("status").is(MessageConstant.Status.TempSucceed));
Update update = new Update().set("status",MessageConstant.Status.Pending);
mongoTemplate.updateMulti(query,update, Message.class,COLLECTION_MESSAGE);
}
@Override
public void updateMessageToExpired() {
Query query = new Query()
.addCriteria(Criteria.where("status").is(MessageConstant.Status.Pending))
.addCriteria(Criteria.where("rule.expireAt").gt(0).lt(DateUtil.currentSeconds()));
Update update = new Update().set("status",MessageConstant.Status.Expired);
mongoTemplate.updateMulti(query,update, Message.class,COLLECTION_MESSAGE);
}
@Override
public void updateMessageToSendTimesUpLimit() {
Query query = new Query()
.addCriteria(Criteria.where("status").is(MessageConstant.Status.Pending))
.addCriteria(Criteria.where("rule.noAckRetryTimes").gt(0))
.addCriteria(new Criteria(){
@Override
public Document getCriteriaObject() {
Document obj = new Document();
obj.put("$where", "this.sendTimes >= this.rule.noAckRetryTimes");
return obj;
}
});
Update update = new Update().set("status",MessageConstant.Status.SendTimesUpLimit);
mongoTemplate.updateMulti(query,update, Message.class,COLLECTION_MESSAGE);
}
@Override
public void incrementSendTimes(String msgId,Long time) {
Query query = new Query(Criteria.where("id").is(msgId));
Update update = new Update();
update.inc("sendTimes");
update.addToSet("sendTimeInSecondList", time);
mongoTemplate.updateFirst(query,update, Message.class,COLLECTION_MESSAGE);
}
@Override
public Message getMessageById(String msgId) {
return mongoTemplate.findById(msgId, Message.class,COLLECTION_MESSAGE);
}
@Override
public List<Message> getMessageByRawId(String rawId) {
Query query = new Query().addCriteria(Criteria.where("rawId").is(rawId));
return mongoTemplate.find(query,Message.class);
}
@Override
public List<Message> getClientPendingMessage(MessageConstant.DomainType toDomain, String to, Integer maxMessageNum) {
Query query = clientPendingMessageQuery(toDomain,to)
.with(Sort.by(Sort.Order.asc("time")));
if(maxMessageNum == null || maxMessageNum.intValue() == 0) {
query.limit(maxMessageNum);
}
return mongoTemplate.find(query,Message.class,COLLECTION_MESSAGE);
}
@Override
public Long countClientPendingMessage(MessageConstant.DomainType toDomain, String to) {
Query query = clientPendingMessageQuery(toDomain,to);
return mongoTemplate.count(query,Message.class,COLLECTION_MESSAGE);
}
private Query clientPendingMessageQuery(MessageConstant.DomainType toDomain, String to){
return new Query().addCriteria(Criteria.where("toDomain").is(toDomain))
.addCriteria(Criteria.where("to").is(to))
//状态为pending
.addCriteria(Criteria.where("status").is(MessageConstant.Status.Pending))
.addCriteria(new Criteria().andOperator(
//未过期消息
new Criteria().orOperator(
Criteria.where("rule.expireAt").is(0),
Criteria.where("rule.expireAt").gt(DateUtil.currentSeconds()
)),
//未达到发送次数上限
new Criteria().orOperator(
Criteria.where("rule.noAckRetryTimes").is(0),
new Criteria() {
@Override
public Document getCriteriaObject() {
Document obj = new Document();
obj.put("$where", "this.sendTimes < this.rule.noAckRetryTimes");
return obj;
}
})
));
}
}

9
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/service/IUserService.java

@ -0,0 +1,9 @@
package com.ccsens.ccmq.lowlevel.service;
import org.springframework.web.bind.annotation.RequestParam;
//@FeignClient(value = "eureka-client-btpro",fallback = TokenSer.class)
public interface IUserService {
//@GetMapping(value="/btpro/v1.0/token")
String getUserIdByToken(@RequestParam(value = "token") String token);
}

32
ccmq/src/main/java/com/ccsens/ccmq/lowlevel/service/UserService.java

@ -0,0 +1,32 @@
package com.ccsens.ccmq.lowlevel.service;
import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
* @author wei
*/
@Service
public class UserService implements IUserService{
@Autowired
private RestTemplate restTemplate;
@Override
public String getUserIdByToken(String token){
String userId = null;
// String url = "https://test.tall.wiki/gateway/tall/v1.0/users/claims?token="+token;
String url = "http://localhost:7030/v1.0/users/claims?token="+token;
ResponseEntity<String> response = restTemplate.getForEntity(url,String.class);
String strBody = null;
if(response.getStatusCodeValue() == 200){
strBody = response.getBody();
}
if(StrUtil.isNotEmpty(strBody)) {
userId = strBody;
}
return userId;
}
}

2
ccmq/src/main/java/lombok.config

@ -0,0 +1,2 @@
config.stopBubbling=true
lombok.equalsAndHashCode.callSuper=call

64
ccmq/src/main/java/wiki/tall/ccmq/common/TallMessageApplication.java

@ -0,0 +1,64 @@
package wiki.tall.ccmq.common;
import com.ccsens.ccmq.lowlevel.client.netty.tcphexserver.NettyMBServer;
import com.ccsens.ccmq.lowlevel.client.netty.tcptextserver.NettyTextServer;
import com.ccsens.ccmq.lowlevel.client.netty.wsserver.NettyWsServer;
import com.ccsens.ccmq.lowlevel.message.MessageHandler;
import wiki.tall.ccmq.common.util.WebConstant;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import java.io.File;
/**
* @author wei
*/
@ComponentScan(basePackages = {"com.ccsens.ccmq.lowlevel.*","wiki.tall.ccmq.common.*"})
@MapperScan(basePackages = {"wiki.tall.ccmq.common.persist.*"})
@ServletComponentScan
@EnableScheduling
@EnableAsync
@SpringBootApplication
//@EnableDiscoveryClient
//@EnableFeignClients(basePackages = "com.ccsens.feignclient")
//@EnableCircuitBreaker
public class TallMessageApplication implements CommandLineRunner {
@Autowired
private NettyMBServer nettyMBServer;
@Autowired
private NettyWsServer nettyWsServer;
@Autowired
private NettyTextServer nettyTextServer;
@Autowired
private MessageHandler messageHandler;
public static void main(String[] args) {
createNecessaryDir();
SpringApplication.run(TallMessageApplication.class, args);
}
private static void createNecessaryDir(){
File dir = new File(WebConstant.IMG_PATH_PREFIX_SHARE_QR);
if(!dir.exists()){
dir.mkdirs();
}
}
@Override
public void run(String... args) throws Exception {
nettyWsServer.start();
nettyMBServer.start();
nettyTextServer.start();
for(int i=0;i<1;i++) {
messageHandler.loopSendMessage();
}
}
}

168
ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/CCModBusEntity.java

@ -0,0 +1,168 @@
package wiki.tall.ccmq.common.bean.dto.ccmodbus;
import wiki.tall.ccmq.common.util.CRCUtil;
import io.netty.buffer.ByteBuf;
/**
* format: Filter(2) len(1) addr(1) oper(1) data(x) crc(2)
* eg: FF FE 0A 10 93 00 00 00 00 00 00 94 2A
* Notice: crc is example ,not the real data
*/
public class CCModBusEntity {
public enum Error{
ERROR_NONE,
ERROR_FILTER_NOT_MATCH,
ERROR_LEN_EXCLUEE_MAX,
ERROR_CRC_INVALID,
ERROR_NEED_MORE_DATA
}
public static final int SIZE_FILTER = 2;
public static final int SIZE_LEN = 1;
public static final int SIZE_ADDR = 1;
public static final int SIZE_OPER = 1;
public static final int SIZE_CRC = 2;
public static final int SIZE_DATA_MIN = 1;
public static final int SIZE_DATA_MAX = 255 - SIZE_ADDR - SIZE_OPER - SIZE_CRC;
public static final int SIZE_MIN = SIZE_FILTER + SIZE_LEN + SIZE_ADDR + SIZE_OPER + SIZE_DATA_MIN + SIZE_CRC;
public static final int SIZE_MAX = SIZE_FILTER + SIZE_LEN + SIZE_ADDR + SIZE_OPER + SIZE_DATA_MAX + SIZE_CRC;
public static final byte[] FILTER = {(byte)0xFF,(byte)0xFE};
// public static final byte[] TAILER = {0x0d,0x0a};
public static final byte[] TAILER = {};
private byte modbusData[];
private byte filter[];
private int len;
private byte addr;
private byte oper;
private byte originData[];
private byte crc[];
public CCModBusEntity(byte addr,byte oper,byte[] originData){
modbusData = new byte[SIZE_FILTER + SIZE_LEN + SIZE_ADDR + SIZE_OPER + originData.length + SIZE_CRC + TAILER.length];
int index = 0;
System.arraycopy(FILTER,0,modbusData,index,SIZE_FILTER);
index += SIZE_FILTER;
modbusData[index++] = (byte)((SIZE_ADDR + SIZE_OPER + originData.length + SIZE_CRC) & 0xFF);
modbusData[index++] = addr;
modbusData[index++] = oper;
System.arraycopy(originData,0,modbusData,index,originData.length);
index += originData.length;
byte crc[] = new byte[SIZE_CRC];
CRCUtil.crc16(crc,modbusData,SIZE_FILTER+SIZE_LEN,originData.length + SIZE_ADDR + SIZE_OPER);
modbusData[index++] = crc[1];
modbusData[index++] = crc[0];
for(int i=0;i<TAILER.length;i++){
modbusData[index++] = TAILER[i];
}
}
public CCModBusEntity(ByteBuf in){
this.modbusData = new byte[in.readableBytes()];
in.getBytes(in.readerIndex(),this.modbusData);
}
public byte[] getModbusData(){
return modbusData;
}
public byte[] getFilter(){
if(filter == null){
filter = new byte[SIZE_FILTER];
}
int index = 0;
for(int i=0;i<SIZE_FILTER;i++){
filter[i] = modbusData[index + i];
}
return filter;
}
public int getLen(){
int index = SIZE_FILTER;
return modbusData[index] & 0xFF;
}
public byte getAddr(){
int index = SIZE_FILTER + SIZE_LEN;
return modbusData[index];
}
public byte getOper(){
int index = SIZE_FILTER + SIZE_LEN + SIZE_ADDR;
return modbusData[index];
}
public byte[] getOriginData(){
int dataLen = getLen() - SIZE_ADDR - SIZE_OPER - SIZE_CRC;
if(originData == null || originData.length != dataLen) {
originData = new byte[dataLen];
}
int index = SIZE_FILTER + SIZE_LEN + SIZE_ADDR + SIZE_OPER;
System.arraycopy(modbusData,index,originData,0,dataLen);
return originData;
}
public byte[] getCrc(){
if(crc == null || crc.length != SIZE_CRC)
crc = new byte[SIZE_CRC];
int index = SIZE_FILTER + SIZE_LEN + getLen() - SIZE_CRC;
System.arraycopy(modbusData,index,crc,0,SIZE_CRC);
return crc;
}
public int getModbusLength(){
return SIZE_FILTER + SIZE_LEN + getLen();
}
public boolean crcValid() {
// byte[] thisCRC = getCrc();
// byte crc[] = {0,0};
// int index = SIZE_FILTER + SIZE_LEN;
// int length = getLen() - SIZE_CRC;
// ProtocolUtil.crc16(crc, this.modbusData,index,length);
// if(crc[1] == thisCRC[0] && crc[0]== thisCRC[1])
// return true;
// return false;
return true;
}
public void print(){
filter = getFilter();
System.out.printf("%02x %02x ",filter[0],filter[1]);
System.out.printf("%02x %02x %02x ",getLen(),getAddr(),getOper());
originData = getOriginData();
for(int i=0;i<originData.length;i++){
System.out.printf("%02x ",originData[i]);
}
crc = getCrc();
System.out.printf("%02x %02x ",crc[0],crc[1]);
System.out.println();
}
public Error valid(){
//1.filter
filter = getFilter();
for(int i=0;i<SIZE_FILTER;i++){
if(filter[i] != FILTER[i])
return Error.ERROR_FILTER_NOT_MATCH;
}
//2.len
len = getLen();
if(len > SIZE_DATA_MAX)
return Error.ERROR_LEN_EXCLUEE_MAX;
//3.data 完整性
if(this.modbusData.length < (SIZE_FILTER + SIZE_LEN + len)) {
return Error.ERROR_NEED_MORE_DATA;
}
//4.crc
if(!crcValid()){
return Error.ERROR_CRC_INVALID;
}
return Error.ERROR_NONE;
}
}

39
ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/ChangeBeginTimeProtocol.java

@ -0,0 +1,39 @@
package wiki.tall.ccmq.common.bean.dto.ccmodbus;
public class ChangeBeginTimeProtocol extends CommonProtocol {
public static class Data{
public Long nodeId;
public Long beginTime;
public Long offset;
}
private Data data;
public Data getData() {
return data;
}
public void setData(Data data){
this.data = data;
}
public void setData(Long nodeId,Long beginTime,Long offset){
if(data == null)
data = new Data();
data.nodeId = nodeId;
data.beginTime = beginTime;
data.offset = offset;
}
public void setData(Long nodeId,Long offset){
if(data == null)
data = new Data();
data.nodeId = nodeId;
data.offset = offset;
data.beginTime = System.currentTimeMillis();
}
@Override
public String toString(){
return getEvent() + "," + data.nodeId + "," + data.beginTime;
}
}

31
ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/ChangeDurationProtocol.java

@ -0,0 +1,31 @@
package wiki.tall.ccmq.common.bean.dto.ccmodbus;
public class ChangeDurationProtocol extends CommonProtocol {
public static class Data{
public Long taskId;
public Long nodeId;
public Long duration;
}
private Data data;
public Data getData() {
return data;
}
public void setData(Data data){
this.data = data;
}
public void setData(Long taskId,Long nodeId,Long duration){
if(data == null)
data = new Data();
data.taskId = taskId;
data.nodeId = nodeId;
data.duration = duration;
}
@Override
public String toString(){
return getEvent() + "," + data.taskId + "," + data.nodeId + "," + data.duration;
}
}

114
ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/CommonProtocol.java

@ -0,0 +1,114 @@
package wiki.tall.ccmq.common.bean.dto.ccmodbus;
public class CommonProtocol {
public enum Event {
HEART(0x00, "heart"),
COUNTDOWN(0x01, "countdown"),
JOIN(0x02, "join"),
TIMING(0x03, "timing"),
PLAY(0x04, "play"),
LOAD(0x05, "load"),
CHANGEDURATION(0x06,"changeduration"),
CHANGEBEGINTIME(0x07,"changebegintime"),
ADD(0x08,"add"),
REMOVE(0x09,"remove"),
MOVE(0x0A,"MOVE"),
CHANGEAUTOMODE(0x0B,"changeautomode"),
TIMEHEART(0x10,"timeheart");
public int value;
public String phase;
Event(int value, String thePhase) {
this.value = value;
this.phase = thePhase;
}
public static Event valueOf(int value) { // 手写的从int到enum的转换函数
switch (value) {
case 0x00:
return HEART;
case 0x01:
return COUNTDOWN;
case 0x02:
return JOIN;
case 0x03:
return TIMING;
case 0x04:
return PLAY;
case 0x05:
return LOAD;
case 0x06:
return CHANGEDURATION;
case 0x07:
return CHANGEBEGINTIME;
case 0x08:
return ADD;
case 0x09:
return REMOVE;
case 0x0A:
return MOVE;
case 0x0B:
return CHANGEAUTOMODE;
case 0x10:
return TIMEHEART;
default:
return null;
}
}
public static Event textOf(String event) {
if (event.equalsIgnoreCase("heart")) {
return HEART;
} else if (event.equalsIgnoreCase("countdown")) {
return COUNTDOWN;
} else if (event.equalsIgnoreCase("join")) {
return JOIN;
} else if (event.equalsIgnoreCase("timing")) {
return TIMING;
} else if (event.equalsIgnoreCase("play")) {
return PLAY;
} else if (event.equalsIgnoreCase("load")) {
return LOAD;
} else if(event.equalsIgnoreCase("changeduration")){
return CHANGEDURATION;
}else if(event.equalsIgnoreCase("changebegintime")){
return CHANGEBEGINTIME;
}else if(event.equalsIgnoreCase("add")){
return ADD;
}else if(event.equalsIgnoreCase("remove")){
return REMOVE;
}else if(event.equalsIgnoreCase("move")){
return MOVE;
}else if(event.equalsIgnoreCase("changeautomode")){
return CHANGEAUTOMODE;
}else if(event.equalsIgnoreCase("timeheart")){
return TIMEHEART;
}
return null;
}
}
private Event event;
public void setModbusEvent(int value) {
this.event = Event.valueOf(value);
}
public byte getModbusEvent() {
return (byte) (event.value & 0xFF);
}
public void setEvent(String text) {
this.event = Event.textOf(text);
}
public String getEvent() {
return event.phase;
}
@Override
public String toString() {
return getEvent();
}
}

23
ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/CountdownProtocol.java

@ -0,0 +1,23 @@
package wiki.tall.ccmq.common.bean.dto.ccmodbus;
import lombok.Data;
@Data
public class CountdownProtocol extends CommonProtocol {
public static class Data{
public Long second;
public Long beepSecond;
public Long beepType;
}
private Data data;
public CountdownProtocol(){
setEvent("countdown");
}
@Override
public String toString(){
return getEvent() + "," + data.second + "," + data.beepSecond + "," + data.beepType;
}
}

12
ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/HeartProtocol.java

@ -0,0 +1,12 @@
package wiki.tall.ccmq.common.bean.dto.ccmodbus;
import lombok.Data;
@Data
public class HeartProtocol extends CommonProtocol {
@Override
public String toString(){
return getEvent();
}
}

16
ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/JoinProtocol.java

@ -0,0 +1,16 @@
package wiki.tall.ccmq.common.bean.dto.ccmodbus;
import lombok.Data;
@Data
public class JoinProtocol extends CommonProtocol {
public static class Data{
public Long taskId;
}
private Data data;
@Override
public String toString(){
return getEvent() + "," + data.taskId;
}
}

16
ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/LoadProtocol.java

@ -0,0 +1,16 @@
package wiki.tall.ccmq.common.bean.dto.ccmodbus;
import lombok.Data;
@Data
public class LoadProtocol extends CommonProtocol {
public static class Data{
public Long taskId;
}
private Data data;
@Override
public String toString(){
return getEvent() + "," + data.taskId;
}
}

31
ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/MoveProtocol.java

@ -0,0 +1,31 @@
package wiki.tall.ccmq.common.bean.dto.ccmodbus;
import java.util.List;
public class MoveProtocol extends CommonProtocol {
public static class Data{
public Long taskId;
public List<String> nodeIds;
}
private Data data;
public Data getData() {
return data;
}
public void setData(Data data){
this.data = data;
}
public void setData(Long taskId,List<String> nodeIds){
if(data == null)
data = new Data();
data.taskId = taskId;
data.nodeIds = nodeIds;
}
@Override
public String toString(){
return getEvent() + "," + data.taskId + "," + data.nodeIds;
}
}

29
ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/PlayProtocol.java

@ -0,0 +1,29 @@
package wiki.tall.ccmq.common.bean.dto.ccmodbus;
public class PlayProtocol extends CommonProtocol {
public static class Data{
public Long nodeId;
public Long beginTime;
}
private Data data;
public Data getData() {
return data;
}
public void setData(Data data){
this.data = data;
}
public void setData(Long nodeId,Long beginTime){
if(data == null)
data = new Data();
data.nodeId = nodeId;
data.beginTime = beginTime;
}
@Override
public String toString(){
return getEvent() + "," + data.nodeId + "," + data.beginTime;
}
}

29
ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/RemoveProtocol.java

@ -0,0 +1,29 @@
package wiki.tall.ccmq.common.bean.dto.ccmodbus;
public class RemoveProtocol extends CommonProtocol {
public static class Data{
public Long taskId;
public Long nodeId;
}
private Data data;
public Data getData() {
return data;
}
public void setData(Data data){
this.data = data;
}
public void setData(Long taskId,Long nodeId){
if(data == null)
data = new Data();
data.taskId = taskId;
data.nodeId = nodeId;
}
@Override
public String toString(){
return getEvent() + "," + data.taskId + "," + data.nodeId;
}
}

30
ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/TimeHeartProtocol.java

@ -0,0 +1,30 @@
package wiki.tall.ccmq.common.bean.dto.ccmodbus;
public class TimeHeartProtocol extends CommonProtocol {
public static class Data{
public Long ctime;
public Long stime;
}
private Data data;
public Data getData() {
return data;
}
public void setData(Data data){
this.data = data;
}
public void setData(Long ctime,Long stime){
if(data == null) {
data = new Data();
}
data.ctime = ctime;
data.stime = stime;
}
@Override
public String toString(){
return getEvent() + "," + data.ctime + "," + data.stime;
}
}

16
ccmq/src/main/java/wiki/tall/ccmq/common/bean/dto/ccmodbus/TimingProtocol.java

@ -0,0 +1,16 @@
package wiki.tall.ccmq.common.bean.dto.ccmodbus;
import lombok.Data;
@Data
public class TimingProtocol extends CommonProtocol {
public static class Data{
public Long timestamp;
}
private Data data;
@Override
public String toString(){
return getEvent() + "," + data.timestamp;
}
}

108
ccmq/src/main/java/wiki/tall/ccmq/common/config/DruidProps.java

@ -0,0 +1,108 @@
package wiki.tall.ccmq.common.config;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.alibaba.druid.pool.DruidDataSource;
import wiki.tall.ccmq.common.util.WebConstant;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.SQLException;
/**
* @author wei
*/
@Component
@PropertySource(value = { "classpath:druid-${spring.profiles.active}.properties" })
@ConfigurationProperties(prefix="spring.datasource.druid")
@Getter @Setter
public class DruidProps {
private Logger logger = LoggerFactory.getLogger(DruidProps.class);
private String dynamicUrl;
private String url;
private String username;
private String password;
private String driverClassName;
private int initialSize;
private int minIdle;
private int maxActive;
private int maxWait;
private int timeBetweenEvictionRunsMillis;
private int minEvictableIdleTimeMillis;
private String validationQuery;
private boolean testWhileIdle;
private boolean testOnBorrow;
private boolean testOnReturn;
private boolean poolPreparedStatements;
private int maxPoolPreparedStatementPerConnectionSize;
private String filters;
private String connectionProperties;
private String logSlowSql;
private String servletName;
private String servletUrlMapping;
private String servletLoginUsername;
private String servletLoginPassword;
private String servletLogSlowSql;
private String servletResetEnable;
private String filterName;
private String filterUrlPattern;
private String filterExclusions;
private String filterProfileEnable;
public DataSource createDruidDataSource() {
String url = this.url;
return createDruidDataSource(url);
}
public DataSource createDynamicDruidDataSource(String schema) {
String url = dynamicUrl.replace(WebConstant.DYNAMIC_DATASOURCE_SCHEMA_KEY,schema);
return createDruidDataSource(url);
}
public String getPassword(){
String key = System.getenv("CCSENS_TALL_TEST");
SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, Base64.decode(key));
return key;
// return aes.decryptStr(password, CharsetUtil.CHARSET_UTF_8);
}
private DataSource createDruidDataSource(String url){
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(url);
datasource.setUsername(username);
datasource.setPassword(getPassword());
datasource.setDriverClassName(driverClassName);
//configuration
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
logger.error("druid configuration initialization filter : {0}", e);
e.printStackTrace();
}
datasource.setConnectionProperties(connectionProperties);
return datasource;
}
}

44
ccmq/src/main/java/wiki/tall/ccmq/common/config/EnjoyConfig.java

@ -0,0 +1,44 @@
package wiki.tall.ccmq.common.config;
import com.jfinal.template.Engine;
import com.jfinal.template.ext.spring.JFinalViewResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class EnjoyConfig {
@Bean(name = "jfinalViewResolver")
public JFinalViewResolver getJFinalViewResolver() {
// 创建用于整合 spring boot 的 ViewResolver 扩展对象
JFinalViewResolver jfr = new JFinalViewResolver();
// 对 spring boot 进行配置
jfr.setSuffix(".html");
jfr.setContentType("text/html;charset=UTF-8");
jfr.setOrder(0);
// 获取 engine 对象,对 enjoy 模板引擎进行配置,配置方式与前面章节完全一样
Engine engine = JFinalViewResolver.engine;
// 热加载配置能对后续配置产生影响,需要放在最前面
engine.setDevMode(true);
// 使用 ClassPathSourceFactory 从 class path 与 jar 包中加载模板文件
engine.setToClassPathSourceFactory();
// 在使用 ClassPathSourceFactory 时要使用 setBaseTemplatePath
// 代替 jfr.setPrefix("/view/")
engine.setBaseTemplatePath("/template/");
// 添加模板函数
//engine.addSharedFunction("/common/_layout.html");
//engine.addSharedFunction("/common/_paginate.html");
// 更多配置与前面章节完全一样
// engine.addDirective(...)
// engine.addSharedMethod(...);
return jfr;
}
}

71
ccmq/src/main/java/wiki/tall/ccmq/common/config/ExcepHandler.java

@ -0,0 +1,71 @@
package wiki.tall.ccmq.common.config;
import wiki.tall.ccmq.common.exception.BaseException;
import wiki.tall.ccmq.common.util.JsonResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
/**
* @author wei
*/
@ControllerAdvice
public class ExcepHandler {
private Logger logger = LoggerFactory.getLogger(ExcepHandler.class);
@ExceptionHandler(value = MethodArgumentNotValidException.class)
@ResponseBody
public JsonResponse handleValidateException(HttpServletRequest req,MethodArgumentNotValidException e){
logger.info("ExpHandler.MethodArgumentNotValidException: {}",e.getMessage());
BindingResult bindingResult = e.getBindingResult();
StringBuilder errorMesssage = new StringBuilder();
errorMesssage.append(bindingResult.getFieldErrors().get(0).getDefaultMessage());
e.printStackTrace();
return JsonResponse.newInstance().fail(-10,errorMesssage.toString());
}
@ExceptionHandler(value =BindException.class)
@ResponseBody
public JsonResponse handleBindException(BindException e) {
logger.info("ExpHandler.BindException: {}", e.getMessage());
FieldError fieldError = e.getFieldError();
StringBuilder sb = new StringBuilder();
sb.append(fieldError.getField()).append("=[").append(fieldError.getRejectedValue()).append("]")
.append(fieldError.getDefaultMessage());
e.printStackTrace();
return JsonResponse.newInstance().fail(-11,sb.toString());
}
@ExceptionHandler(value =HttpMessageNotReadableException.class)
@ResponseBody
public JsonResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
logger.info("ExpHandler.HttpMessageNotReadableException: {}", e.getMessage());
e.printStackTrace();
return JsonResponse.newInstance().fail(-12,e.getMessage());
}
@ExceptionHandler(value = BaseException.class)
@ResponseBody
public JsonResponse jsonBaseExceptionHandler(HttpServletRequest req, BaseException e) {
logger.info("ExpHandler.BaseException: {}",e.getMessage());
e.printStackTrace();
return JsonResponse.newInstance().fail(e.getCode(),e.getMessage());
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public JsonResponse jsonExceptionHandler(HttpServletRequest req, Exception e) {
logger.info("ExpHandler.Exception: {}",e.getMessage());
e.printStackTrace();
return JsonResponse.newInstance().fail(-1,e.getMessage());
}
}

25
ccmq/src/main/java/wiki/tall/ccmq/common/config/RabbitMqConfig.java

@ -0,0 +1,25 @@
package wiki.tall.ccmq.common.config;
import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author wei
*/
@Configuration
public class RabbitMqConfig {
@Autowired
private SettingProps settingProps;
@Bean
public Queue receivedQueue(){
return new Queue(settingProps.getMq().getInName());
}
@Bean
public Queue sendQueue(){
return new Queue(settingProps.getMq().getOutName());
}
}

39
ccmq/src/main/java/wiki/tall/ccmq/common/config/RedisConfig.java

@ -0,0 +1,39 @@
package wiki.tall.ccmq.common.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author wei
*/
@Configuration
public class RedisConfig {
@Bean("redisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}

74
ccmq/src/main/java/wiki/tall/ccmq/common/config/RestClientConfig.java

@ -0,0 +1,74 @@
package wiki.tall.ccmq.common.config;
import wiki.tall.ccmq.common.util.HttpsClientRequestFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
/**
* @author wei
*/
@Configuration
@AutoConfigureAfter(SpringConfig.class)
public class RestClientConfig {
@Autowired
private RestTemplateBuilder builder;
/**
* 支持http和https以及GZIP压缩UTF-8
* @return
*/
@Bean
public RestTemplate restTemplate(){
return builder.build();
}
@Bean
public RestTemplate sslRestTemplate(){
RestTemplate restTemplate = new RestTemplate(httpsClientRequestFactory());
changeConverters(restTemplate);
return restTemplate;
}
/**
* 发送HTTPS的逻辑代码是可以拿来发送HTTP的但是根据我们写得HttpsClientRequestFactory类中的代码可知会打印出异常(异常抛出后被catch了)
* 如果不想看见该异常,可以注释掉抛出异常的代码
* class HttpsClientRequestFactory:
* if (!(connection instanceof HttpsURLConnection)) {
* //throw new RuntimeException("An instance of HttpsURLConnection is expected");
* }
* @return
*/
@Bean
public HttpsClientRequestFactory httpsClientRequestFactory(){
return new HttpsClientRequestFactory();
}
private void changeConverters(RestTemplate restTemplate){
//解决有可能出现的中文乱码问题
List<MediaType> mediaTypeList = new ArrayList<>();
mediaTypeList.add(MediaType.TEXT_HTML);
mediaTypeList.add(MediaType.APPLICATION_JSON_UTF8);
List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> httpMessageConverter : converterList) {
if(httpMessageConverter instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) httpMessageConverter).setDefaultCharset(StandardCharsets.UTF_8);
}
if(httpMessageConverter instanceof MappingJackson2HttpMessageConverter) {
((MappingJackson2HttpMessageConverter) httpMessageConverter).setSupportedMediaTypes(mediaTypeList);
}
}
}
}

123
ccmq/src/main/java/wiki/tall/ccmq/common/config/ServletConfig.java

@ -0,0 +1,123 @@
package wiki.tall.ccmq.common.config;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 在springboot添加过滤器有两种方式
  1通过创建FilterRegistrationBean的方式
1.1 建议使用此种方式统一管理且通过注解的方式若不是本地调试
如果在filter中需要增加cookie可能会存在写不进前端情况
1.2 有多个filter就创建多个FilterRegistrationBean 若需注明filter的执行顺序
可通过registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE - 1)配置
值越大执行顺序越靠后 
2通过注解@WebFilter的方式
  2.1 在启动类上增加@ServletComponentScan注解自动扫描带有过滤器注解的包
2.2 在类上使用@WebFilter和@Order组合实现
3通过注解@WebFilter的方式
  3.1 在类上使用@WebFilter和@Order组合实现
3.2 在类上添加@Component注解
*/
/**
* 原生方案
* @WebServlet @WebListener@WebFilter
* 在启动类上增加@ServletComponentScan注解自动扫描带有Servlet原生方案注解的包
*
* SpringBoot方案
* SpringBoot提供了三种Bean
* FilterRegistrationBean
* ServletRegistrationBean
* ServletListenerRegistrationBean
* 分别对应配置原生的FilterServletListener
*/
/**
* 注册系统过滤器
* @author wei
*/
@Configuration
public class ServletConfig {
@Autowired
private DruidProps druidConfig;
//配置Filter
// @Bean
// public FilterRegistrationBean companyUrlFilterRegister() {
// FilterRegistrationBean registration = new FilterRegistrationBean();
// //注入过滤器
// registration.setFilter(new TestFilter1());
// //拦截规则
// registration.addUrlPatterns("/*");
// //过滤器名称
// registration.setName("testFilter1");
// //过滤器顺序
// registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
// return registration;
// }
//
// @Bean
// public FilterRegistrationBean outLinkSecurityFilterRegister() {
// FilterRegistrationBean registration = new FilterRegistrationBean();
// //注入过滤器
// registration.setFilter(new TestFilter2());
// //拦截规则
// registration.addUrlPatterns("/*");
// //过滤器名称
// registration.setName("testFilter2");
// //过滤器顺序
// registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE - 1);
// return registration;
// }
//配置Servlet
// @Bean
// public ServletRegistrationBean indexServletRegistration() {
// ServletRegistrationBean registration = new ServletRegistrationBean(new IndexServlet());
// registration.addUrlMappings("/hello");
// return registration;
// }
// //配置Listener
// @Bean
// public ServletListenerRegistrationBean servletListenerRegistrationBean(){
// ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean();
// servletListenerRegistrationBean.setListener(new IndexListener());
// return servletListenerRegistrationBean;
// }
@Bean
public ServletRegistrationBean<StatViewServlet> druidServlet() {
ServletRegistrationBean<StatViewServlet> reg = new ServletRegistrationBean<StatViewServlet>();
reg.setServlet(new StatViewServlet());
reg.setName(druidConfig.getFilterName());
reg.addUrlMappings(druidConfig.getServletUrlMapping());
//白名单:
//reg.addInitParameter("allow","127.0.0.1");
//IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
//reg.addInitParameter("deny","192.168.1.73");
reg.addInitParameter("loginUsername", druidConfig.getServletLoginUsername());
reg.addInitParameter("loginPassword", druidConfig.getServletLoginPassword());
reg.addInitParameter("logSlowSql", druidConfig.getServletLogSlowSql());
//是否能够重置数据.
reg.addInitParameter("resetEnable",druidConfig.getServletResetEnable());
return reg;
}
@Bean
public FilterRegistrationBean<WebStatFilter> druidFilter() {
FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.setName(druidConfig.getFilterName());
filterRegistrationBean.addUrlPatterns(druidConfig.getFilterUrlPattern());
filterRegistrationBean.addInitParameter("exclusions", druidConfig.getFilterExclusions());
filterRegistrationBean.addInitParameter("profileEnable", druidConfig.getFilterProfileEnable());
return filterRegistrationBean;
}
}

60
ccmq/src/main/java/wiki/tall/ccmq/common/config/SettingProps.java

@ -0,0 +1,60 @@
package wiki.tall.ccmq.common.config;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
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;
/**
* @author wei
*/
@Component
@PropertySource(value = {"classpath:setting-${spring.profiles.active}.properties"})
@ConfigurationProperties(prefix="setting")
@Getter @Setter @ToString
public class SettingProps {
@Getter @Setter @ToString
public static class Snowflake{
private String workerId;
private String dataCenterId;
}
@Getter @Setter @ToString
public static class MessageQueue{
private String inName;
private String outName;
}
@Getter @Setter @ToString
public static class Server{
private String name;
}
@Getter @Setter @ToString
public static class KeepAlive{
private boolean enable;
private Integer maxIdleSeconds;
}
private Snowflake snowflake;
private MessageQueue mq;
private Server server;
private KeepAlive keepAlive;
@Value("${setting.netty.ws.port}")
private Short nettyWsPort;
@Value("${setting.netty.ws.uri}")
private String nettyWsUri;
@Value("${setting.netty.ws.type}")
private String nettyWsType;
@Value("${setting.netty.tcptext.port}")
private String nettyTcpTextPort;
@Value("${setting.netty.tcptext.type}")
private String nettyTcpTextType;
@Value("${setting.netty.tcphex.port}")
private String nettyTcpHexPort;
@Value("${setting.netty.tcphex.type}")
private String nettyTcpHexType;
}

136
ccmq/src/main/java/wiki/tall/ccmq/common/config/SpringConfig.java

@ -0,0 +1,136 @@
package wiki.tall.ccmq.common.config;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import wiki.tall.ccmq.common.controller.interceptor.TokenInterceptor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.*;
import javax.sql.DataSource;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
/**
* @author wei
*/
@Configuration
public class SpringConfig implements WebMvcConfigurer {
@Autowired
private DruidProps druidPropsUtil;
@Autowired
private SettingProps settingProps;
/**
* 配置Converter
* @return
*/
@Bean
public HttpMessageConverter<String> responseStringConverter() {
return new StringHttpMessageConverter(StandardCharsets.UTF_8);
}
@Bean
public HttpMessageConverter<Object> responseJsonConverter(){
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
List<MediaType> mediaTypeList = new ArrayList<>();
mediaTypeList.add(MediaType.TEXT_HTML);
mediaTypeList.add(MediaType.APPLICATION_JSON_UTF8);
converter.setSupportedMediaTypes(mediaTypeList);
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
converter.setObjectMapper(objectMapper);
return converter;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(responseStringConverter());
converters.add(responseJsonConverter());
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
/**
* 配置视图解析器 SpringBoot建议使用Thymeleaf代替jsp动态页面默认路径resources/template静态页面默认路径: resources/static
* @return
*/
// @Bean
// public ViewResolver getViewResolver() {
// InternalResourceViewResolver resolver = new InternalResourceViewResolver();
// resolver.setPrefix("/WEB-INF/views/");
// resolver.setSuffix(".jsp");
// return resolver;
// }
// @Override
// public void configureDefaultServletHandling(
// DefaultServletHandlerConfigurer configurer) {
// configurer.enable();
// }
/**
* 配置静态资源
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
// registry.addResourceHandler("/uploads/**")
// .addResourceLocations("file:///home/umg/uploads/");
}
/**
* 配置拦截器
* @param registry
* @Descripton addPathPatterns 用于添加拦截规则excludePathPatterns 用于排除拦截
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor())
.addPathPatterns("/message/**");
}
@Bean
public TokenInterceptor tokenInterceptor(){
return new TokenInterceptor();
}
/**
* 配置数据源单数据源
*/
@Bean
public DataSource dataSource(){
return druidPropsUtil.createDruidDataSource();
}
@Bean
public Snowflake snowflake(){
return IdUtil.createSnowflake(Long.parseLong(settingProps.getSnowflake().getWorkerId()),
Long.parseLong(settingProps.getSnowflake().getDataCenterId()));
}
}

64
ccmq/src/main/java/wiki/tall/ccmq/common/config/SwaggerConfigure.java

@ -0,0 +1,64 @@
package wiki.tall.ccmq.common.config;
import wiki.tall.ccmq.common.util.WebConstant;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
/**
* @author wei
*/
@Configuration
@EnableSwagger2
public class SwaggerConfigure {
@Bean
public Docket customDocket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo()).select()
.apis(RequestHandlerSelectors
.basePackage("com.ccsens.ccmq"))
.build()
.globalOperationParameters(setHeaderToken());
}
private ApiInfo apiInfo() {
Contact contact = new Contact("__zHangSan", "", "weizezhao@gamil.com");
return new ApiInfo(
//大标题 title
"Anyring Core v3.0 Plugin Version.",
//小标题
"",
//版本
"1.0.0",
//termsOfServiceUrl
"",
//作者
contact.getName(),
//链接显示文字
"",
//网站链接
"www.ccsens.com"
);
}
private List<Parameter> setHeaderToken() {
ParameterBuilder tokenPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<>();
tokenPar.name(WebConstant.HEADER_KEY_TOKEN).description("token")
.defaultValue(WebConstant.HEADER_KEY_TOKEN_PREFIX)
.modelRef(new ModelRef("string")).parameterType("header").required(false).build();
pars.add(tokenPar.build());
return pars;
}
}

29
ccmq/src/main/java/wiki/tall/ccmq/common/config/TaskExecutorConfig.java

@ -0,0 +1,29 @@
package wiki.tall.ccmq.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author __zHangSan
*/
@Configuration
public class TaskExecutorConfig {
@Bean(name = "cc-msg-executor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(200);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("cc-msg-executor");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
return executor;
}
}

75
ccmq/src/main/java/wiki/tall/ccmq/common/controller/interceptor/TokenInterceptor.java

@ -0,0 +1,75 @@
package wiki.tall.ccmq.common.controller.interceptor;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.SignatureException;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import wiki.tall.ccmq.common.util.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author wei
*/
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("TokenInterceptor-->preHandle");
// 验证token是否存在
final String authHeader = httpServletRequest.getHeader(WebConstant.HEADER_KEY_TOKEN);
if (authHeader == null || !authHeader.startsWith(WebConstant.HEADER_KEY_TOKEN_PREFIX)) {
HttpServletUtil.responseJson(httpServletResponse,
JacksonUtil.beanToJson(JsonResponse.newInstance().tokenNotFound()));
return false;
}
final String token = authHeader.substring(WebConstant.HEADER_KEY_TOKEN_PREFIX.length());
//验证token是否有效
Claims claims = null;
try {
claims = JwtUtil.parseJWT(token, WebConstant.JWT_ACCESS_TOKEN_SECERT);
}catch(SignatureException e){
HttpServletUtil.responseJson(httpServletResponse,
JacksonUtil.beanToJson(JsonResponse.newInstance().tokenSignatureFail(e.getMessage())));
return false;
}catch(ExpiredJwtException e){
HttpServletUtil.responseJson(httpServletResponse,
JacksonUtil.beanToJson(JsonResponse.newInstance().tokenExpire(e.getMessage())));
return false;
}catch(Exception e){
HttpServletUtil.responseJson(httpServletResponse,
JacksonUtil.beanToJson(JsonResponse.newInstance().tokenFailed(e.getMessage())));
return false;
}
//验证用户存根
// if(userService.tokenNotExistInCache(Long.valueOf(claims.getSubject()))){
// HttpServletUtil.responseJson(httpServletResponse,
// JacksonUtil.beanToJson(JsonResponse.newInstance().tokenStubNotFound()));
// return false;
// }
//验证用户是否禁用
// User user = userService.getUserByAuthId(Long.valueOf(claims.getSubject()));
// if(user.getRecStatus() == WebConstant.REC_STATUS.Disabled.value){
// HttpServletUtil.responseJson(httpServletResponse,
// JacksonUtil.beanToJson(JsonResponse.newInstance().userDisabled()));
// return false;
// }
httpServletRequest.setAttribute(WebConstant.REQUEST_KEY_CLAIMS,claims);
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}

106
ccmq/src/main/java/wiki/tall/ccmq/common/controller/web/LearnController.java

@ -0,0 +1,106 @@
package wiki.tall.ccmq.common.controller.web;
import wiki.tall.ccmq.common.util.JsonResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author wei
*/
@Controller
@RequestMapping("/learn")
public class LearnController {
/**
* url forward (转发)
* @param request
* @param response
* @param model
* @return
* @throws Exception
*/
@RequestMapping(value = "/")
public String root(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
//forward:/index 中间不能有空格,/开头代表绝对路径,否则为相对路径
// return "forward:/index";
return "forward:index";
}
/**
* url redirect重定向
* @param request 请求
* @param response 响应
* @param model 模型
* @return
* @throws Exception
*/
@RequestMapping(value = "/home")
public String home(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
//redirect:/index 中间不能有空格,/开头代表绝对路径,否则为相对路径
// return "redirect:/index";
return "redirect:index";
}
/**
* 使用模板渲染页面
* @param request 请求
* @param response 响应
* @param model 模型
* @return
* @throws Exception
*/
@RequestMapping(value = "/index")
public String index(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
model.addAttribute("welcome","Welcome to tall-message.");
return "index";
}
/**
* Restful Json 请求
* @param request
* @param response
* @param model
* @return
* @throws Exception
*/
@RequestMapping(value = "/json",method = RequestMethod.GET,produces = {"application/json;charset=UTF-8"})
@ResponseBody
public JsonResponse api(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
return JsonResponse.newInstance().ok();
}
/**
* Restful Xml 请求
* @param request
* @param response
* @param model
* @return
* @throws Exception
*/
@RequestMapping(value = "/xml",method = RequestMethod.GET,produces = {"application/xml;charset=UTF-8"})
@ResponseBody
public JsonResponse xml(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
return JsonResponse.newInstance().ok();
}
/**
* 字符串请求
* @param request
* @param response
* @param model
* @return
* @throws Exception
*/
@RequestMapping(value = "/text",method = RequestMethod.GET,produces = {"text/plain;charset=UTF-8"})
@ResponseBody
public String text(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
model.addAttribute("welcome","Welcome to tall-message.");
return "welcome";
}
}

26
ccmq/src/main/java/wiki/tall/ccmq/common/controller/web/MessageController.java

@ -0,0 +1,26 @@
package wiki.tall.ccmq.common.controller.web;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author wei
*/
@RestController
@RequestMapping("/message")
public class MessageController {
// @RequestMapping(value = "/nodeMsg",method = RequestMethod.GET,produces = {"application/json;charset=UTF-8"})
// public JsonResponse getNodeMessage(HttpServletRequest request,Long taskId) throws Exception {
// Long currentUserId = Long.valueOf(((Claims) request.getAttribute(WebConstant.REQUEST_KEY_CLAIMS)).getSubject());
// List<BaseMessageDto> messages = messageService.getNodeMessages(currentUserId,taskId);
// return JsonResponse.newInstance().ok(messages);
// }
//
// @RequestMapping(value = "/userMsg",method = RequestMethod.GET,produces = {"application/json;charset=UTF-8"})
// public JsonResponse getUserMessage(HttpServletRequest request,Long projectId,Integer offset,Integer limit) throws Exception {
// Long currentUserId = Long.valueOf(((Claims) request.getAttribute(WebConstant.REQUEST_KEY_CLAIMS)).getSubject());
// List<BaseMessageDto> messages = messageService.getUserMessages(currentUserId,projectId,offset,limit);
// return JsonResponse.newInstance().ok(messages);
// }
}

17
ccmq/src/main/java/wiki/tall/ccmq/common/exception/BaseException.java

@ -0,0 +1,17 @@
package wiki.tall.ccmq.common.exception;
import lombok.Getter;
@Getter
public class BaseException extends RuntimeException {
private Integer code;
public BaseException(String message){
super(message);
this.code = -1;
}
public BaseException(Integer code,String message){
super(message);
this.code = code;
}
}

50
ccmq/src/main/java/wiki/tall/ccmq/common/util/BeanWrapperUtil.java

@ -0,0 +1,50 @@
package wiki.tall.ccmq.common.util;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import java.util.ArrayList;
import java.util.List;
public class BeanWrapperUtil {
public static <V,T> T warpVoToObj(V userVo,Class<T> tClazz){
if(userVo == null)
return null;
T user = null;
try {
user = tClazz.newInstance();
BeanUtil.copyProperties(userVo,user);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return user;
}
public static <V,T> V warpObjToVo(T user,Class<V> vClass){
if(user == null)
return null;
V userVo = null;
try {
userVo = vClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
BeanUtil.copyProperties(user,userVo);
return userVo;
}
public static <V,T> List<V> warpObjToVo(List<T> userList,Class<V> vClass){
if(CollectionUtil.isEmpty(userList))
return null;
List<V> userVoList = new ArrayList<>();
for(T user: userList) {
userVoList.add(warpObjToVo(user,vClass));
}
return userVoList;
}
}

30
ccmq/src/main/java/wiki/tall/ccmq/common/util/CRCUtil.java

@ -0,0 +1,30 @@
package wiki.tall.ccmq.common.util;
public class CRCUtil {
public static void crc16(byte crc[], byte data[], int index, int len) {
int wcrc = 0xFFFF;// 预置16位crc寄存器,初值全部为1
int temp;// 定义中间变量
int i = 0, j = 0, k = index;// 定义计数
for (i = 0; i < len; i++)// 循环计算每个数据
{
temp = (data[k] & 0xFF);// 将八位数据与crc寄存器亦或
k++;// 指针地址增加,指向下个数据
wcrc ^= temp;// 将数据存入crc寄存器
for (j = 0; j < 8; j++)// 循环计算数据的
{
if ((wcrc & 0x0001) == 1)// 判断右移出的是不是1,如果是1则与多项式进行异或。
{
wcrc >>= 1;// 先将数据右移一位
wcrc ^= 0XA001;// 与上面的多项式进行异或
} else// 如果不是1,则直接移出
{
wcrc >>= 1;// 直接移出
}
}
}
temp = wcrc;// crc的值
crc[0] = (byte)(wcrc & 0xFF); // crc的低八位
crc[1] = (byte)((wcrc >> 8) & 0xFF); // crc的高八位
}
}

41
ccmq/src/main/java/wiki/tall/ccmq/common/util/CcMessageUtil.java

@ -0,0 +1,41 @@
package wiki.tall.ccmq.common.util;
import cn.hutool.core.util.StrUtil;
import com.ccsens.ccmq.lowlevel.message.common.InMessage;
import com.ccsens.ccmq.lowlevel.message.common.MessageConstant;
import java.util.ArrayList;
import java.util.List;
/**
* @author __zHangSan
*/
public class CcMessageUtil {
private static final char TYPE_TO_JOIN_CHAR = '_';
/**
* tos命名矫正后的集合
* 为了避免 id重复queue的id和user的id将to的id矫正为 domain_id
* @param inMessage 消息
* @return tos命名矫正后的集合
*/
public static List<Object> getNameManglingToList(InMessage inMessage) {
List<Object> list = new ArrayList<Object>(inMessage.getTos().size());
for(String to : inMessage.getTos()){
list.add(StrUtil.format("{}{}{}",inMessage.getToDomain(),TYPE_TO_JOIN_CHAR,to));
}
return list;
}
public static String[] splitTypeAndUserId(String typeAndUserId) {
String []strings = new String[2];
int splitCharPos = typeAndUserId.indexOf(TYPE_TO_JOIN_CHAR);
strings[0] = typeAndUserId.substring(0,splitCharPos);
strings[1] = typeAndUserId.substring(splitCharPos+1,typeAndUserId.length());
return strings;
}
public static String getDomainTypeAndUserIdString(MessageConstant.DomainType domainType,String to){
return StrUtil.format("{}{}{}",domainType.name(),TYPE_TO_JOIN_CHAR,to);
}
}

15
ccmq/src/main/java/wiki/tall/ccmq/common/util/DateUtil.java

@ -0,0 +1,15 @@
package wiki.tall.ccmq.common.util;
import java.util.TimeZone;
public class DateUtil extends cn.hutool.core.date.DateUtil {
public static Long dateBeginSeconds(Long seconds){
if(seconds == null)
seconds = currentSeconds();
return (seconds - (seconds + TimeZone.getDefault().getRawOffset()/1000 )% (3600*24));
}
public static Long dateEndSeconds(Long seconds){
return dateBeginSeconds(seconds) + (3600 * 24 - 1);
}
}

285
ccmq/src/main/java/wiki/tall/ccmq/common/util/GenericsUtils.java

@ -0,0 +1,285 @@
package wiki.tall.ccmq.common.util;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* 泛型工具类
*
* @author <a href="http://www.blogjava.net/lishunli/"
* target="_jeecg">ShunLi</a>
* @notes Created on 2010-1-21<br>
* Revision of last commit:$Revision: 1.1 $<br>
* Author of last commit:$Author: ghp $<br>
* Date of last commit:$Date: 2010-01-25 16:48:17 +0800 (周一, 25 一月 2010)
* $<br>
* <p>
*/
public class GenericsUtils {
/**
* 通过反射,获得指定类的父类的泛型参数的实际类型. 如BuyerServiceBean extends DaoSupport<Buyer>
*
* @param clazz
* clazz 需要反射的类,该类必须继承范型父类
* @param index
* 泛型参数所在索引,从0开始.
* @return 范型参数的实际类型, 如果没有实现ParameterizedType接口即不支持泛型所以直接返回
* <code>Object.class</code>
*/
public static Class getSuperClassGenricType(Class clazz, int index) {
Type genType = clazz.getGenericSuperclass();// 得到泛型父类
// 如果没有实现ParameterizedType接口,即不支持泛型,直接返回Object.class
if (!(genType instanceof ParameterizedType)) {
Type genTypeArray[] = clazz.getGenericInterfaces();
boolean isParameterizedType = false;
for(Type tmpGenType : genTypeArray){
if(tmpGenType instanceof ParameterizedType) {
genType = tmpGenType;
isParameterizedType = true;
break;
}
}
if(isParameterizedType == false) {
return Object.class;
}
}
// 返回表示此类型实际类型参数的Type对象的数组,数组里放的都是对应类型的Class, 如BuyerServiceBean extends
// DaoSupport<Buyer,Contact>就返回Buyer和Contact类型
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0) {
throw new RuntimeException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));
}
if (!(params[index] instanceof Class)) {
return Object.class;
}
return (Class) params[index];
}
/**
* 通过反射,获得指定类的父类的第一个泛型参数的实际类型. 如BuyerServiceBean extends DaoSupport<Buyer>
*
* @param clazz
* clazz 需要反射的类,该类必须继承泛型父类
* @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口即不支持泛型所以直接返回
* <code>Object.class</code>
*/
@SuppressWarnings("unchecked")
public static Class getSuperClassGenricType(Class clazz) {
return getSuperClassGenricType(clazz, 0);
}
/**
* 通过反射,获得方法返回值泛型参数的实际类型. : public Map<String, Buyer> getNames(){}
*
* @param method 方法
* @param index 泛型参数所在索引,从0开始.
* @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口即不支持泛型所以直接返回
* <code>Object.class</code>
*/
@SuppressWarnings("unchecked")
public static Class getMethodGenericReturnType(Method method, int index) {
Type returnType = method.getGenericReturnType();
if (returnType instanceof ParameterizedType) {
ParameterizedType type = (ParameterizedType) returnType;
Type[] typeArguments = type.getActualTypeArguments();
if (index >= typeArguments.length || index < 0) {
throw new RuntimeException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));
}
return (Class) typeArguments[index];
}
return Object.class;
}
/**
* 通过反射,获得方法返回值第一个泛型参数的实际类型. : public Map<String, Buyer> getNames(){}
*
* @param method 方法
* @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口即不支持泛型所以直接返回
* <code>Object.class</code>
*/
@SuppressWarnings("unchecked")
public static Class getMethodGenericReturnType(Method method) {
return getMethodGenericReturnType(method, 0);
}
/**
* 通过反射,获得方法输入参数第index个输入参数的所有泛型参数的实际类型. : public void add(Map<String,
* Buyer> maps, List<String> names){}
*
* @param method 方法
* @param index 第几个输入参数
* @return 输入参数的泛型参数的实际类型集合, 如果没有实现ParameterizedType接口即不支持泛型所以直接返回空集合
*/
@SuppressWarnings("unchecked")
public static List<Class> getMethodGenericParameterTypes(Method method, int index) {
List<Class> results = new ArrayList<Class>();
Type[] genericParameterTypes = method.getGenericParameterTypes();
if (index >= genericParameterTypes.length || index < 0) {
throw new RuntimeException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));
}
Type genericParameterType = genericParameterTypes[index];
if (genericParameterType instanceof ParameterizedType) {
ParameterizedType aType = (ParameterizedType) genericParameterType;
Type[] parameterArgTypes = aType.getActualTypeArguments();
for (Type parameterArgType : parameterArgTypes) {
Class parameterArgClass = (Class) parameterArgType;
results.add(parameterArgClass);
}
return results;
}
return results;
}
/**
* 通过反射,获得方法输入参数第一个输入参数的所有泛型参数的实际类型. : public void add(Map<String, Buyer>
* maps, List<String> names){}
*
* @param method 方法
* @return 输入参数的泛型参数的实际类型集合, 如果没有实现ParameterizedType接口即不支持泛型所以直接返回空集合
*/
@SuppressWarnings("unchecked")
public static List<Class> getMethodGenericParameterTypes(Method method) {
return getMethodGenericParameterTypes(method, 0);
}
/**
* 通过反射,获得Field泛型参数的实际类型. : public Map<String, Buyer> names;
*
* @param field 字段
* @param index 泛型参数所在索引,从0开始.
* @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口即不支持泛型所以直接返回
* <code>Object.class</code>
*/
@SuppressWarnings("unchecked")
public static Class getFieldGenericType(Field field, int index) {
Type genericFieldType = field.getGenericType();
if (genericFieldType instanceof ParameterizedType) {
ParameterizedType aType = (ParameterizedType) genericFieldType;
Type[] fieldArgTypes = aType.getActualTypeArguments();
if (index >= fieldArgTypes.length || index < 0) {
throw new RuntimeException("你输入的索引" + (index < 0 ? "不能小于0" : "超出了参数的总数"));
}
return (Class) fieldArgTypes[index];
}
return Object.class;
}
/**
* 通过反射,获得Field泛型参数的实际类型. : public Map<String, Buyer> names;
*
* @param field 字段
* @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口即不支持泛型所以直接返回
* <code>Object.class</code>
*/
@SuppressWarnings("unchecked")
public static Class getFieldGenericType(Field field) {
return getFieldGenericType(field, 0);
}
/**
* 根据实体得到实体的所有属性
* @param objClass
* @return
* @throws ClassNotFoundException
*/
public static String[] getColumnNames(String objClass) throws ClassNotFoundException {
String[] wageStrArray = null;
if (objClass != null) {
Class class1 = Class.forName(objClass);
Field[] field = class1.getDeclaredFields();// 这里便是获得实体Bean中所有属性的方法
StringBuffer sb = new StringBuffer();
for (int i = 0; i < field.length; i++) {// 这里不多说了
sb.append(field[i].getName());
// 这是分割符 是为了去掉最后那个逗号
// 比如 如果不去最后那个逗号 最后打印出来的结果是 "id,name,"
// 去了以后打印出来的是 "id,name"
if (i < field.length - 1) {
sb.append(",");
}
}
// split(",");这是根据逗号来切割字符串使字符串变成一个数组
wageStrArray = sb.toString().split(",");
return wageStrArray;
} else {
return wageStrArray;
}
}
public static Object[] field2Value(Field[] f, Object o) throws Exception {
Object[] value = new Object[f.length];
for (int i = 0; i < f.length; i++) {
value[i] = f[i].get(o);
}
return value;
}
/**
* returns the current http session object
*
* @return session
*/
public HttpSession getSession() {
HttpSession session=null;
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpSession contextSess = attr == null ? session : attr.getRequest().getSession(true);
return contextSess;
}
/**
* 得到实体类
* @param objClass 实体类包含包名
* @return
*/
public static Class getEntityClass(String objClass){
Class entityClass = null;
try {
entityClass = Class.forName(objClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return entityClass;
}
/**
* 定义字符集
* @param
* @return
*/
private static char[] chars = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', 'A', 'B','C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
'Z'}; //72个字符集
/**
*
* @param passLength
* 随机密码长度
* @return 随机密码数组
*/
public static String getPasswords(int passLength) {
String passwords = "";// 新建一个长度为指定需要密码个数的字符串数组
Random random = new Random();
StringBuilder password = new StringBuilder("");// 保存生成密码的变量
for (int m = 1; m <= passLength; m++) {// 内循环 从1开始到密码长度 正式开始生成密码
password.append(chars[random.nextInt(62)]);// 为密码变量随机增加上面字符中的一个
}
passwords = password.toString();// 将生成出来的密码赋值给密码数组
return passwords;
}
}

59
ccmq/src/main/java/wiki/tall/ccmq/common/util/HttpServletUtil.java

@ -0,0 +1,59 @@
package wiki.tall.ccmq.common.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class HttpServletUtil {
public static void responseJson(HttpServletResponse response, String json) throws IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
out.append(json);
out.close();
}
/**
* 获取用户真实IP地址不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,
*
* 可是如果通过了多级反向代理的话X-Forwarded-For的值并不止一个而是一串IP值究竟哪个才是真正的用户端的真实IP呢
* 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串
*
* X-Forwarded-For192.168.1.110, 192.168.1.120, 192.168.1.130,
* 192.168.1.100
*
* 用户真实IP为 192.168.1.110
*
* @param request
* @return
*/
public static String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
public static String getSiteBasePath(HttpServletRequest request){
return request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort();
}
public static String getSiteContextPath(HttpServletRequest request){
return getSiteBasePath(request) + "/" + request.getContextPath();
}
}

133
ccmq/src/main/java/wiki/tall/ccmq/common/util/HttpsClientRequestFactory.java

@ -0,0 +1,133 @@
package wiki.tall.ccmq.common.util;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import javax.net.ssl.*;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Socket;
import java.security.cert.X509Certificate;
/**
* 声明:此代码摘录自https://blog.csdn.net/wltsysterm/article/details/80977455
* 声明:关于Socket的相关知识,本人会在后面的闲暇时间进行学习整理,请持续关注博客更新
*
* @author JustryDeng
* @DATE 2018年9月8日 下午4:34:02
*/
public class HttpsClientRequestFactory extends SimpleClientHttpRequestFactory {
@Override
protected void prepareConnection(HttpURLConnection connection, String httpMethod) {
try {
if (!(connection instanceof HttpsURLConnection)) {
throw new RuntimeException("An instance of HttpsURLConnection is expected");
}
HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
httpsConnection.setSSLSocketFactory(new MyCustomSSLSocketFactory(sslContext.getSocketFactory()));
httpsConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
super.prepareConnection(httpsConnection, httpMethod);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* We need to invoke sslSocket.setEnabledProtocols(new String[] {"SSLv3"});
* see http://www.oracle.com/technetwork/java/javase/documentation/cve-2014-3566-2342133.html (Java 8 section)
*/
// SSLSocketFactory用于创建 SSLSockets
private static class MyCustomSSLSocketFactory extends SSLSocketFactory {
private final SSLSocketFactory delegate;
public MyCustomSSLSocketFactory(SSLSocketFactory delegate) {
this.delegate = delegate;
}
// 返回默认启用的密码套件。除非一个列表启用,对SSL连接的握手会使用这些密码套件。
// 这些默认的服务的最低质量要求保密保护和服务器身份验证
@Override
public String[] getDefaultCipherSuites() {
return delegate.getDefaultCipherSuites();
}
// 返回的密码套件可用于SSL连接启用的名字
@Override
public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}
@Override
public Socket createSocket(final Socket socket, final String host, final int port,
final boolean autoClose) throws IOException {
final Socket underlyingSocket = delegate.createSocket(socket, host, port, autoClose);
return overrideProtocol(underlyingSocket);
}
@Override
public Socket createSocket(final String host, final int port) throws IOException {
final Socket underlyingSocket = delegate.createSocket(host, port);
return overrideProtocol(underlyingSocket);
}
@Override
public Socket createSocket(final String host, final int port, final InetAddress localAddress,
final int localPort) throws
IOException {
final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
return overrideProtocol(underlyingSocket);
}
@Override
public Socket createSocket(final InetAddress host, final int port) throws IOException {
final Socket underlyingSocket = delegate.createSocket(host, port);
return overrideProtocol(underlyingSocket);
}
@Override
public Socket createSocket(final InetAddress host, final int port, final InetAddress localAddress,
final int localPort) throws
IOException {
final Socket underlyingSocket = delegate.createSocket(host, port, localAddress, localPort);
return overrideProtocol(underlyingSocket);
}
private Socket overrideProtocol(final Socket socket) {
if (!(socket instanceof SSLSocket)) {
throw new RuntimeException("An instance of SSLSocket is expected");
}
((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1"});
return socket;
}
}
}

256
ccmq/src/main/java/wiki/tall/ccmq/common/util/HttpsUtil.java

@ -0,0 +1,256 @@
package wiki.tall.ccmq.common.util;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.*;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* 类名: MyX509TrustManager </br>
* 描述:信任管理器 </br>
* 开发人员 souvc </br>
* 创建时间 2015-11-27 </br>
* 发布版本V1.0 </br>
*/
class MyX509TrustManager implements X509TrustManager {
// 检查客户端证书
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
// 检查服务器端证书
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
// 返回受信任的X509证书数组
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
public class HttpsUtil {
/**
* 发送https请求
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式GETPOST
* @param postStr 提交的数据
* @return String(Json)
*/
public static String httpsRequest(String requestUrl, String requestMethod, String postStr) throws Exception {
StringBuffer buffer = null;
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = {new MyX509TrustManager()};
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
// 当outputStr不为null时向输出流写数据
if (null != postStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(postStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
return buffer == null ? null : buffer.toString();
}
/**
* 发送https请求
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式GETPOST
* @param postStr 提交的数据
* @param path 将结果以二进制方式写入文件
* @return void
*/
public static void httpsRequest(String requestUrl, String requestMethod, String postStr,String path)
throws Exception {
StringBuffer buffer = null;
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = {new MyX509TrustManager()};
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
// 当outputStr不为null时向输出流写数据
if (null != postStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(postStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(inputStream);
OutputStream os = new FileOutputStream(new File(path));
int len;
byte[] arr = new byte[1024];
while ((len = bis.read(arr)) != -1)
{
os.write(arr, 0, len);
os.flush();
}
os.close();
}
/**
* 发送https请求 使用PKCS12类型证书
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式GETPOST
* @param postStr 提交的数据
* @return String(Json)
*/
public static String httpsRequest(String requestUrl, String requestMethod, String postStr,String pKCS12Path,String pKCS12Pwd) throws Exception {
SSLContext sc = null;
FileInputStream instream = null;
KeyStore keyStore = null;
keyStore = KeyStore.getInstance("PKCS12");
instream = new FileInputStream(new File(pKCS12Path));
keyStore.load(instream,pKCS12Pwd.toCharArray());
instream.close();
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(
keyStore, pKCS12Pwd.toCharArray()).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
);
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf) .build();
HttpPost httpost = new HttpPost(requestUrl);
httpost.addHeader("Connection", "keep-alive");
httpost.addHeader("Accept", "*/*");
httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpost.addHeader("Host", "api.mch.weixin.qq.com");
httpost.addHeader("X-Requested-With", "XMLHttpRequest");
httpost.addHeader("Cache-Control", "max-age=0");
httpost.addHeader("User-Agent",
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
httpost.setEntity(new StringEntity(postStr, "UTF-8"));
CloseableHttpResponse response = httpclient.execute(httpost);
HttpEntity entity = response.getEntity();
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
EntityUtils.consume(entity);
return jsonStr;
}
/**
* 设置信任自签名证书
*
* @param keyStorePath 密钥库路径
* @param keyStorepass 密钥库密码
* @return
*/
public static SSLContext custom(String keyStorePath, String keyStorepass) {
SSLContext sc = null;
FileInputStream instream = null;
KeyStore trustStore = null;
try {
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
instream = new FileInputStream(new File(keyStorePath));
trustStore.load(instream, keyStorepass.toCharArray());
// 相信自己的CA和所有自签名的证书
sc = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
// 构造 javax.net.ssl.TrustManager 对象
TrustManagerFactory tmf =
TrustManagerFactory.getInstance("SunX509", "SunJSSE");
tmf.init(trustStore);
TrustManager tms [] = tmf.getTrustManagers();
// 使用构造好的 TrustManager 访问相应的 https 站点
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tms, new java.security.SecureRandom());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
instream.close();
} catch (IOException e) {
}
}
return sc;
}
public static String sendGet(String url, String charset, int timeout) {
String result = "";
try {
URL u = new URL(url);
try {
URLConnection conn = u.openConnection();
conn.connect();
conn.setConnectTimeout(timeout);
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset));
String line = "";
while ((line = in.readLine()) != null) {
result = result + line;
}
in.close();
} catch (IOException e) {
return result;
}
} catch (MalformedURLException e) {
return result;
}
return result;
}
}

15
ccmq/src/main/java/wiki/tall/ccmq/common/util/IDGenerator.java

@ -0,0 +1,15 @@
package wiki.tall.ccmq.common.util;
import cn.hutool.core.lang.Snowflake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class IDGenerator {
@Autowired
private Snowflake snowflake;
public Long nextId(){
return snowflake.nextId();
}
}

13
ccmq/src/main/java/wiki/tall/ccmq/common/util/ImgUtil.java

@ -0,0 +1,13 @@
package wiki.tall.ccmq.common.util;
import sun.font.FontDesignMetrics;
import java.awt.*;
public class ImgUtil {
public static int getStringWidth(String text,Font f){
FontMetrics fm = FontDesignMetrics.getMetrics(f);
int w = fm.stringWidth(text);
return w;
}
}

311
ccmq/src/main/java/wiki/tall/ccmq/common/util/JacksonUtil.java

@ -0,0 +1,311 @@
package wiki.tall.ccmq.common.util;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
/**
* @author wei
* @date 2019.11.25
*/
public class JacksonUtil {
private static ObjectMapper objectMapper = new ObjectMapper();
private static XmlMapper xmlMapper = new XmlMapper();
static {
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
}
/**
* 获取泛型的Collection Type
* eg: collectionClass==List.class elementClasses == MessageBean.class 则返回 List<MessageBean>对应的java类型
* @param collectionClass 泛型的Collection
* @param elementClasses 元素类
* @return JavaType Java类型
* @since 1.0
*/
private static JavaType getCollectionType(ObjectMapper mapper, Class<?> collectionClass, Class<?>... elementClasses) {
return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
}
/**
* Json And Bean Converter
* @param json 要转换的json
* @param clazz 目标类型类对象
* @param isSet 是否集合类型
* @param <T> 目标类型
* @return 集合如果只有1个对象则添加到集合中返回
* @throws IOException IO异常
*/
public static <T> List<T> jsonToBean(String json, Class<T> clazz, boolean isSet) throws IOException {
if (!isSet) {
return CollectionUtil.newArrayList(objectMapper.readValue(json, clazz));
}
else {
JavaType javaType = getCollectionType(objectMapper,List.class,clazz);
return objectMapper.readValue(json, javaType);
}
}
public static <T> T jsonToBean(String json, Class<T> clazz) throws IOException {
return objectMapper.readValue(json, clazz);
}
public static <T> String beanToJson(T bean, boolean pretty) throws JsonProcessingException {
if (!pretty) {
return objectMapper.writeValueAsString(bean);
}
else {
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(bean);
}
}
public static <T> String beanToJson(T bean) throws JsonProcessingException {
return beanToJson(bean,false);
}
/**
* Json And Map Converter
*
* @param json 要转换的json
* eg: {"time":"1574602523","from":{"id":"1","name":"zs"},"to":[{"id":"1","name":"ls","avatar":"xx.jpg"}],"rule":{"offlineDiscard":1}}
* @return Map<String,Object> 如果value还是一个json对象则也会被转化为map
* eg: entry1: "time"->String entry2: "from"--> Map<id:1,name:zs> entry3: "to"->List<Map> entry4: "rule"-->Map
* @throws IOException
*/
public static Map<String,Object> jsonToMap(String json) throws IOException {
JavaType javaType = getCollectionType(objectMapper,Map.class,String.class,Object.class);
return objectMapper.readValue(json,javaType);
}
public static String mapToJson(Map<String,Object> map,boolean pretty) throws JsonProcessingException {
if(!pretty){
return objectMapper.writeValueAsString(map);
}else{
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);
}
}
public static String mapToJson(Map<String,Object> map) throws JsonProcessingException {
return mapToJson(map,false);
}
/**
* Map And Bean Converter
* @param map 要转换的集合
* @param clazz 目标类型类对象
* @param <T> 目标类型
* @return JavaBean
* @throws IOException IO异常
*/
public static <T> T mapToBean(Map<String,Object> map,Class<T> clazz) throws IOException {
return jsonToBean(mapToJson(map),clazz);
}
public static <T> Map<String,Object> beanToMap(T bean) throws IOException {
return jsonToMap(beanToJson(bean));
}
/**
* Xml And Bean Converter
* Javabean可以使用Jackson xml标注 @JacksonXmlRootElement(localName = "Class") 指定root元素名称
* 其他标注@JacksonXmlElementWrapper(localName = "Students")指定List类型包装元素名称比如学生列表 @JacksonXmlProperty(localName = "Stu") 指定字段元素名称比如学生
* @param bean 要转换的JavaBean
* @param root xml root元素名称建议使用@JacksonXmlElementWrapper表示
* @param pretty 是否启用pretty模式
* @param <T> Javabean类型
* @return xml字符串
* @throws JsonProcessingException Json处理异常
*/
public static <T> String beanToXml(T bean,String root,boolean pretty) throws JsonProcessingException {
if(!pretty) {
if(StrUtil.isEmpty(root)) {
return xmlMapper.writeValueAsString(bean);
}else{
return xmlMapper.writer().with(SerializationFeature.WRAP_ROOT_VALUE).withRootName(root).writeValueAsString(bean);
}
}else{
if(StrUtil.isEmpty(root)) {
return xmlMapper.writerWithDefaultPrettyPrinter().writeValueAsString(bean);
}else{
return xmlMapper.writer().with(SerializationFeature.WRAP_ROOT_VALUE).withRootName(root).withDefaultPrettyPrinter().writeValueAsString(bean);
}
}
}
public static <T> String beanToXml(T bean,String root) throws JsonProcessingException {
return beanToXml(bean,root,false);
}
public static <T> String beanToXml(T bean,boolean pretty) throws JsonProcessingException {
return beanToXml(bean,null,pretty);
}
public static <T> String beanToXml(T bean) throws JsonProcessingException {
return beanToXml(bean,null,false);
}
public static <T> T xmlToBean(String xml, Class<T> clazz) throws IOException {
return xmlMapper.readValue(xml, clazz);
}
public static <T> T xmlToBean(InputStream xmlInStream, Class<T> clazz) throws IOException {
return xmlMapper.readValue(xmlInStream, clazz);
}
/**
* Xml And Map Converter
* 注意存在一直问题 xml转map时对于相同属性比如<receivers><to>123</to><to>234</to></receivers>不会自动转化为list而还是map由于map不能重复因此导致第二个to丢失
* 暂未找到解决办法
* 暂时解决办法xml转map时先转成beanbean再转map
* @param xml 要转换的xml字符串
* @return Map
* @throws IOException IO异常
*/
public static Map<String,Object> xmlToMap(String xml) throws IOException {
JavaType javaType = getCollectionType(objectMapper,Map.class,String.class,Object.class);
return xmlMapper.readValue(xml, javaType);
}
public static Map<String,Object> xmlToMap(InputStream xmlInStream) throws IOException {
JavaType javaType = getCollectionType(objectMapper,Map.class,String.class,Object.class);
return xmlMapper.readValue(xmlInStream, javaType);
}
public static String mapToXml(Map<String,Object> map,String root,boolean pretty) throws JsonProcessingException {
if(!pretty) {
if(StrUtil.isEmpty(root)) {
return xmlMapper.writeValueAsString(map);
}else{
return xmlMapper.writer().with(SerializationFeature.WRAP_ROOT_VALUE).withRootName(root).writeValueAsString(map);
}
}else{
if(StrUtil.isEmpty(root)) {
return xmlMapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);
}else{
return xmlMapper.writer().with(SerializationFeature.WRAP_ROOT_VALUE).withRootName(root).withDefaultPrettyPrinter().writeValueAsString(map);
}
}
}
public static String mapToXml(Map<String,Object> map,String root) throws JsonProcessingException {
return mapToXml(map,root,false);
}
public static String mapToXml(Map<String,Object> map,boolean pretty) throws JsonProcessingException {
return mapToXml(map,null,pretty);
}
public static String mapToXml(Map<String,Object> map) throws JsonProcessingException {
return mapToXml(map,null,false);
}
/**
* Json And Xml Converter
* @param json 要转换的json字符串
* @return xml
* @throws IOException IO异常
*/
public static String jsonToXml(String json) throws IOException {
return mapToXml(jsonToMap(json));
}
public static String jsonToXml(String json,String root) throws IOException {
return mapToXml(jsonToMap(json),root);
}
public static String jsonToXml(String json,boolean pretty) throws IOException {
return mapToXml(jsonToMap(json),pretty);
}
public static String jsonToXml(String json,String root,boolean pretty) throws IOException {
return mapToXml(jsonToMap(json),root,pretty);
}
public static String xmlToJson(String xml) throws IOException {
return mapToJson(xmlToMap(xml));
}
public static String xmlToJson(String xml,boolean pretty) throws IOException {
return mapToJson(xmlToMap(xml),pretty);
}
/**
* 获取单个字段值
* @param json
* @param property
* @return
* @throws IOException
*
* JsonNode tmpNode, node = objectMapper.readTree(json);
* System.out.println("voName:" + node.get("voName").textValue());
* System.out.println("pers: " + node.get("pers").toString());
* System.out.println("age: " + node.get("age").toString());
* JsonNode persNode = node.get("pers");
* if (persNode.isArray()) {
* for (int i = 0; i < persNode.size(); i++) {
* tmpNode = persNode.get(i);
* System.out.println(tmpNode.get("name"));
* JsonNode childNode = tmpNode.get("childs");
* if(!childNode.isNull() && childNode.isArray()){
* for(int j=0;j<childNode.size();j++){
* tmpNode = childNode.get(j);
* System.out.println("\t" + tmpNode.get("name"));
* }
* }
* }
* }
*/
public static JsonNode getJsonProperty(String json,String property) throws IOException {
return objectMapper.readTree(json).get(property);
}
public static JsonNode getJsonProperty(JsonNode jsonNode,String property) throws IOException {
return jsonNode.get(property);
}
/**
* 根据表达式返回对应的JsonNode
* @param json 要解析的Json字符串
* @param path JsonPath表达式 类似 $.a.b.c[2].d
* @return 对应的JsonNode
* @throws IOException IO异常
*/
public static JsonNode getJsonPropertyByPath(String json,String path) throws IOException{
//TODO
return null;
}
/**
* 根据表达式返回对应的JsonNode
* @param json 要解析的Json字符串
* @param path JsonPath表达式 类似 $.a.b.c[2].d
* @param t 预期类型
* @return 对应的JsonNode
* @throws IOException IO异常
*/
public static <T> T getJsonPropertyValueByPath(String json,String path,T t) throws IOException{
//TODO
return null;
}
}

42
ccmq/src/main/java/wiki/tall/ccmq/common/util/JsonPathUtil.java

@ -0,0 +1,42 @@
package wiki.tall.ccmq.common.util;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.spi.json.JacksonJsonProvider;
import com.jayway.jsonpath.spi.json.JsonProvider;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
import com.jayway.jsonpath.spi.mapper.MappingProvider;
import java.util.EnumSet;
import java.util.Set;
public class JsonPathUtil {
private Configuration jacksonConfiguration(){
Configuration conf = Configuration.defaultConfiguration();
Configuration conf2 = conf.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);
Configuration conf3 = Configuration.defaultConfiguration();
Configuration.setDefaults(new Configuration.Defaults() {
private final JsonProvider jsonProvider = new JacksonJsonProvider();
private final MappingProvider mappingProvider = new JacksonMappingProvider();
@Override
public JsonProvider jsonProvider() {
return jsonProvider;
}
@Override
public MappingProvider mappingProvider() {
return mappingProvider;
}
@Override
public Set<Option> options() {
return EnumSet.noneOf(Option.class);
}
});
return conf;
}
}

158
ccmq/src/main/java/wiki/tall/ccmq/common/util/JsonResponse.java

@ -0,0 +1,158 @@
package wiki.tall.ccmq.common.util;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel
public class JsonResponse<T> {
/**
* Common Error Constant
*/
public static class RegularError {
public static final int ERRCODE_SUCCESS = 200;
public static final String ERRCODE_SUCCESS_PHASE = "ok";
public static final int ERRCODE_FAIL = -1;
public static final String ERRCODE_FAIL_PHASE = "error";
}
/**
* Jwt Error Constant
*/
public static class TokenError{
public static final int TOKEN_ERRCODE_OK = JwtUtil.JwtError.TOKEN_ERRCODE_OK;
public static final String TOKEN_ERRCODE_OK_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_OK_PHASE;
public static final int TOKEN_ERRCODE_NOTFOUND = JwtUtil.JwtError.TOKEN_ERRCODE_NOTFOUND;
public static final String TOKEN_ERRCODE_NOTFOUND_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_NOTFOUND_PHASE;
public static final int TOKEN_ERRCODE_SIGNATURE_INVALIDATE = JwtUtil.JwtError.TOKEN_ERRCODE_SIGNATURE_INVALIDATE;
public static final String TOKEN_ERRCODE_SIGNATURE_INVALIDATE_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_SIGNATURE_INVALIDATE_PHASE;
public static final int TOKEN_ERRCODE_EXPIRE = JwtUtil.JwtError.TOKEN_ERRCODE_EXPIRE;
public static final String TOKEN_ERRCODE_EXPIRE_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_EXPIRE_PHASE;
public static final int TOKEN_ERRCODE_STUB_NOT_FOUND = JwtUtil.JwtError.TOKEN_ERRCODE_STUB_NOT_FOUND;
public static final String TOKEN_ERRCODE_STUB_NOT_FOUND_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_STUB_NOT_FOUND_PHASE;
public static final int TOKEN_ERRCODE_USER_DISABLED = JwtUtil.JwtError.TOKEN_ERRCODE_USER_DISABLED;
public static final String TOKEN_ERRCODE_USER_DISABLED_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_USER_DISABLED_PHASE;
public static final int TOKEN_ERRCODE_FAILED = JwtUtil.JwtError.TOKEN_ERRCODE_FAILED;
public static final String TOKEN_ERRCODE_FAILED_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_FAILED_PHASE;
}
@ApiModelProperty(value="状态码")
private Integer code;
@ApiModelProperty(value="数据")
private T data;
@ApiModelProperty(value="消息")
private String msg;
@ApiModelProperty(value="成功与否")
private boolean success;
private JsonResponse() {
}
public static JsonResponse newInstance(){
return new JsonResponse();
}
public JsonResponse ok(){
this.code = RegularError.ERRCODE_SUCCESS;
this.msg = RegularError.ERRCODE_SUCCESS_PHASE;
this.success = true;
return this;
}
public JsonResponse ok(T data){
ok();
this.data = data;
return this;
}
public JsonResponse fail(){
this.code = RegularError.ERRCODE_FAIL;
this.msg = RegularError.ERRCODE_FAIL_PHASE;
this.success = false;
return this;
}
public JsonResponse fail(String error){
fail();
this.msg = error;
return this;
}
public JsonResponse fail(int code){
fail();
this.code = code;
return this;
}
public JsonResponse fail(int code, String error){
fail();
this.code = code;
this.msg = error;
return this;
}
public JsonResponse fail(int code, String error, T obj){
fail();
this.code = code;
this.msg = error;
this.data = obj;
return this;
}
//Token null
public JsonResponse tokenNotFound(){
fail(TokenError.TOKEN_ERRCODE_NOTFOUND, TokenError.TOKEN_ERRCODE_NOTFOUND_PHASE);
return this;
}
//Token expire
public JsonResponse tokenExpire(){
fail(TokenError.TOKEN_ERRCODE_EXPIRE, TokenError.TOKEN_ERRCODE_EXPIRE_PHASE);
return this;
}
public JsonResponse tokenExpire(String phase){
fail(TokenError.TOKEN_ERRCODE_EXPIRE,phase);
return this;
}
public JsonResponse tokenSignatureFail(){
fail(TokenError.TOKEN_ERRCODE_SIGNATURE_INVALIDATE, TokenError.TOKEN_ERRCODE_SIGNATURE_INVALIDATE_PHASE);
return this;
}
public JsonResponse tokenSignatureFail(String phase){
fail(TokenError.TOKEN_ERRCODE_SIGNATURE_INVALIDATE,phase);
return this;
}
//Token Stub Not Found
public JsonResponse tokenStubNotFound(){
fail(TokenError.TOKEN_ERRCODE_STUB_NOT_FOUND, TokenError.TOKEN_ERRCODE_STUB_NOT_FOUND_PHASE);
return this;
}
public JsonResponse tokenDisabled(String phase){
fail(TokenError.TOKEN_ERRCODE_STUB_NOT_FOUND,phase);
return this;
}
//User Disabled
public JsonResponse userDisabled(){
fail(TokenError.TOKEN_ERRCODE_USER_DISABLED, TokenError.TOKEN_ERRCODE_USER_DISABLED_PHASE);
return this;
}
public JsonResponse userDisabled(String phase){
fail(TokenError.TOKEN_ERRCODE_USER_DISABLED,phase);
return this;
}
//Token Failed
public JsonResponse tokenFailed(){
fail(TokenError.TOKEN_ERRCODE_FAILED, TokenError.TOKEN_ERRCODE_FAILED_PHASE);
return this;
}
public JsonResponse tokenFailed(String phase){
fail(TokenError.TOKEN_ERRCODE_FAILED,phase);
return this;
}
}

298
ccmq/src/main/java/wiki/tall/ccmq/common/util/JsonResponse1.java

@ -0,0 +1,298 @@
package wiki.tall.ccmq.common.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class JsonResponse1 {
/**
* Hypermedia API
*/
private static class Link{
private String rel; //API与当前调用API的关系
private String href; //API url
private String title; //API title
private String type; //API 返回类型
public Link() {
}
public Link(String title,String rel, String href) {
this.title = title;
this.rel = rel;
this.href = href;
}
public Link(String title,String rel, String href,String type) {
this.title = title;
this.rel = rel;
this.href = href;
this.type = type;
}
public String getRel() {
return rel;
}
public void setRel(String rel) {
this.rel = rel;
}
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
/**
* Meta data
*/
public static class Meta{
/**
* Common Error Constant
*/
public static class RegularError {
public static final int ERRCODE_SUCCESS = 0;
public static final String ERRCODE_SUCCESS_PHASE = "ok";
public static final int ERRCODE_FAIL = -1;
public static final String ERRCODE_FAIL_PHASE = "error";
}
/**
* Jwt Error Constant
*/
public static class TokenError{
public static final int TOKEN_ERRCODE_OK = JwtUtil.JwtError.TOKEN_ERRCODE_OK;
public static final String TOKEN_ERRCODE_OK_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_OK_PHASE;
public static final int TOKEN_ERRCODE_NOTFOUND = JwtUtil.JwtError.TOKEN_ERRCODE_NOTFOUND;
public static final String TOKEN_ERRCODE_NOTFOUND_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_NOTFOUND_PHASE;
public static final int TOKEN_ERRCODE_SIGNATURE_INVALIDATE = JwtUtil.JwtError.TOKEN_ERRCODE_SIGNATURE_INVALIDATE;
public static final String TOKEN_ERRCODE_SIGNATURE_INVALIDATE_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_SIGNATURE_INVALIDATE_PHASE;
public static final int TOKEN_ERRCODE_EXPIRE = JwtUtil.JwtError.TOKEN_ERRCODE_EXPIRE;
public static final String TOKEN_ERRCODE_EXPIRE_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_EXPIRE_PHASE;
public static final int TOKEN_ERRCODE_STUB_NOT_FOUND = JwtUtil.JwtError.TOKEN_ERRCODE_STUB_NOT_FOUND;
public static final String TOKEN_ERRCODE_STUB_NOT_FOUND_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_STUB_NOT_FOUND_PHASE;
public static final int TOKEN_ERRCODE_USER_DISABLED = JwtUtil.JwtError.TOKEN_ERRCODE_USER_DISABLED;
public static final String TOKEN_ERRCODE_USER_DISABLED_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_USER_DISABLED_PHASE;
public static final int TOKEN_ERRCODE_FAILED = JwtUtil.JwtError.TOKEN_ERRCODE_FAILED;
public static final String TOKEN_ERRCODE_FAILED_PHASE = JwtUtil.JwtError.TOKEN_ERRCODE_FAILED_PHASE;
}
private int code;
private String error;
public Meta() {
}
public Meta(int code) {
this.code = code;
}
public Meta(int code,String error) {
this.code = code;
this.error = error;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
}
/**
* Page Data
*/
public class Data{
private long total;
private int size;
private Collection list;
public Data(){}
public Data(long total,Collection list){
if(list != null && list.size() == 1){ //处理Arrays.asList(null)的情况
if(list.toArray()[0] == null)
list = null;
}
this.total = total;
this.size = list == null ? 0 : list.size();
this.list = list;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public Collection getList() {
return list;
}
public void setList(Collection list) {
this.list = list;
}
}
private Meta meta;
private Data data;
private List<Link> links;
public static JsonResponse1 newInstance(){
return new JsonResponse1();
}
public JsonResponse1 addLink(String title, String rel, String url){
if(links==null)
links = new ArrayList<Link>();
links.add(new Link(title,rel,url));
return this;
}
public JsonResponse1 ok(){
this.meta = new Meta(Meta.RegularError.ERRCODE_SUCCESS, Meta.RegularError.ERRCODE_SUCCESS_PHASE);
return this;
}
public JsonResponse1 ok(Collection list){
ok();
this.data = new Data(-1,list);
return this;
}
public JsonResponse1 ok(long total, Collection list){
ok();
this.data = new Data(total,list);
return this;
}
public JsonResponse1 fail(){
this.meta = new Meta(Meta.RegularError.ERRCODE_FAIL, Meta.RegularError.ERRCODE_FAIL_PHASE);
return this;
}
public JsonResponse1 fail(String error){
this.meta = new Meta(Meta.RegularError.ERRCODE_FAIL,error);
return this;
}
public JsonResponse1 fail(int code){
this.meta = new Meta(code, Meta.RegularError.ERRCODE_FAIL_PHASE);
return this;
}
public JsonResponse1 fail(int code, String error){
this.meta = new Meta(code,error);
return this;
}
//Token null
public JsonResponse1 tokenNotFound(){
this.meta = new Meta(Meta.TokenError.TOKEN_ERRCODE_NOTFOUND, Meta.TokenError.TOKEN_ERRCODE_NOTFOUND_PHASE);
return this;
}
//Token expire
public JsonResponse1 tokenExpire(){
this.meta = new Meta(Meta.TokenError.TOKEN_ERRCODE_EXPIRE, Meta.TokenError.TOKEN_ERRCODE_EXPIRE_PHASE);
return this;
}
public JsonResponse1 tokenExpire(String phase){
this.meta = new Meta(Meta.TokenError.TOKEN_ERRCODE_EXPIRE,phase);
return this;
}
//Token Signature failed
public JsonResponse1 tokenSignatureFail(){
this.meta = new Meta(Meta.TokenError.TOKEN_ERRCODE_SIGNATURE_INVALIDATE, Meta.TokenError.TOKEN_ERRCODE_SIGNATURE_INVALIDATE_PHASE);
return this;
}
public JsonResponse1 tokenSignatureFail(String phase){
this.meta = new Meta(Meta.TokenError.TOKEN_ERRCODE_SIGNATURE_INVALIDATE,phase);
return this;
}
//Token Stub Not Found
public JsonResponse1 tokenStubNotFound(){
this.meta = new Meta(Meta.TokenError.TOKEN_ERRCODE_STUB_NOT_FOUND, Meta.TokenError.TOKEN_ERRCODE_STUB_NOT_FOUND_PHASE);
return this;
}public JsonResponse1 tokenDisabled(String phase){
this.meta = new Meta(Meta.TokenError.TOKEN_ERRCODE_STUB_NOT_FOUND,phase);
return this;
}
//User Disabled
public JsonResponse1 userDisabled(){
this.meta = new Meta(Meta.TokenError.TOKEN_ERRCODE_USER_DISABLED, Meta.TokenError.TOKEN_ERRCODE_USER_DISABLED_PHASE);
return this;
}public JsonResponse1 userDisabled(String phase){
this.meta = new Meta(Meta.TokenError.TOKEN_ERRCODE_USER_DISABLED,phase);
return this;
}
//Token Failed
public JsonResponse1 tokenFailed(){
this.meta = new Meta(Meta.TokenError.TOKEN_ERRCODE_FAILED, Meta.TokenError.TOKEN_ERRCODE_FAILED_PHASE);
return this;
}
public JsonResponse1 tokenFailed(String phase){
this.meta = new Meta(Meta.TokenError.TOKEN_ERRCODE_FAILED, phase);
return this;
}
public JsonResponse1() {
}
public Meta getMeta() {
return meta;
}
public Object getData() {
return data;
}
public Object setData(Data data) {
this.data = data;
return this;
}
public List<Link> getLinks() {
return links;
}
public void setLinks(List<Link> links) {
this.links = links;
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save