├── .gitignore
├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
├── sonar-project.properties
└── src
├── main
├── java
│ └── com
│ │ └── xbongbong
│ │ ├── LocalConstant.java
│ │ ├── XbbWebSocketApplication.java
│ │ ├── base
│ │ ├── BaseController.java
│ │ └── BaseModel.java
│ │ ├── component
│ │ ├── ApplicationContextHolder.java
│ │ └── RedisClient.java
│ │ ├── config
│ │ ├── RedisConfig.java
│ │ ├── TaskSchedulerConfig.java
│ │ ├── WebMvcConfig.java
│ │ └── WebSocketConfig.java
│ │ ├── controller
│ │ ├── BroadcastController.java
│ │ ├── ExampleController.java
│ │ └── UnicastController.java
│ │ ├── entity
│ │ ├── BroadcastMessageEntity.java
│ │ ├── PushMessageEntity.java
│ │ ├── SocketIdCardEntity.java
│ │ └── UnicastMessageEntity.java
│ │ ├── model
│ │ └── ResponseModal.java
│ │ ├── service
│ │ └── task
│ │ │ └── ScheduledTaskProducerService.java
│ │ ├── socket
│ │ └── XbbWebSocket.java
│ │ └── util
│ │ ├── CustomerInterceptor.java
│ │ ├── DateUtil.java
│ │ ├── ExceptionHandlerAdvice.java
│ │ ├── ExceptionUtil.java
│ │ ├── FIFOQueen.java
│ │ └── StringUtil.java
└── resources
│ ├── Banner.txt
│ ├── application-aliyun.yml
│ ├── application-dev.yml
│ ├── application-jushita.yml
│ ├── application-jushitaTest.yml
│ ├── application.yml
│ ├── commands
│ └── hello.groovy
│ ├── log4j2.xml
│ └── templates
│ ├── error.html
│ └── websocket.html
└── test
└── java
└── com
└── xbongbong
├── DemoBeanIntegrationTests.java
├── XbbWebSocketApplicationTests.java
├── bean
└── TestBean.java
└── config
└── TestConfig.java
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | .svn/
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 |
13 | ### IntelliJ IDEA ###
14 | .idea
15 | *.iws
16 | *.iml
17 | *.ipr
18 |
19 | ### NetBeans ###
20 | nbproject/private/
21 | build/
22 | nbbuild/
23 | dist/
24 | nbdist/
25 | .nb-gradle/
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nefeed/WebSocket-SpringBoot/592890e70f94750869273b3be9bb1dfa46f01d7c/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SpringBoot框架搭建的WebSocket项目
2 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | #
58 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look
59 | # for the new JDKs provided by Oracle.
60 | #
61 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
62 | #
63 | # Apple JDKs
64 | #
65 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
66 | fi
67 |
68 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
69 | #
70 | # Apple JDKs
71 | #
72 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
73 | fi
74 |
75 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
76 | #
77 | # Oracle JDKs
78 | #
79 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
80 | fi
81 |
82 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
83 | #
84 | # Apple JDKs
85 | #
86 | export JAVA_HOME=`/usr/libexec/java_home`
87 | fi
88 | ;;
89 | esac
90 |
91 | if [ -z "$JAVA_HOME" ] ; then
92 | if [ -r /etc/gentoo-release ] ; then
93 | JAVA_HOME=`java-config --jre-home`
94 | fi
95 | fi
96 |
97 | if [ -z "$M2_HOME" ] ; then
98 | ## resolve links - $0 may be a link to maven's home
99 | PRG="$0"
100 |
101 | # need this for relative symlinks
102 | while [ -h "$PRG" ] ; do
103 | ls=`ls -ld "$PRG"`
104 | link=`expr "$ls" : '.*-> \(.*\)$'`
105 | if expr "$link" : '/.*' > /dev/null; then
106 | PRG="$link"
107 | else
108 | PRG="`dirname "$PRG"`/$link"
109 | fi
110 | done
111 |
112 | saveddir=`pwd`
113 |
114 | M2_HOME=`dirname "$PRG"`/..
115 |
116 | # make it fully qualified
117 | M2_HOME=`cd "$M2_HOME" && pwd`
118 |
119 | cd "$saveddir"
120 | # echo Using m2 at $M2_HOME
121 | fi
122 |
123 | # For Cygwin, ensure paths are in UNIX format before anything is touched
124 | if $cygwin ; then
125 | [ -n "$M2_HOME" ] &&
126 | M2_HOME=`cygpath --unix "$M2_HOME"`
127 | [ -n "$JAVA_HOME" ] &&
128 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
129 | [ -n "$CLASSPATH" ] &&
130 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
131 | fi
132 |
133 | # For Migwn, ensure paths are in UNIX format before anything is touched
134 | if $mingw ; then
135 | [ -n "$M2_HOME" ] &&
136 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
137 | [ -n "$JAVA_HOME" ] &&
138 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
139 | # TODO classpath?
140 | fi
141 |
142 | if [ -z "$JAVA_HOME" ]; then
143 | javaExecutable="`which javac`"
144 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
145 | # readlink(1) is not available as standard on Solaris 10.
146 | readLink=`which readlink`
147 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
148 | if $darwin ; then
149 | javaHome="`dirname \"$javaExecutable\"`"
150 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
151 | else
152 | javaExecutable="`readlink -f \"$javaExecutable\"`"
153 | fi
154 | javaHome="`dirname \"$javaExecutable\"`"
155 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
156 | JAVA_HOME="$javaHome"
157 | export JAVA_HOME
158 | fi
159 | fi
160 | fi
161 |
162 | if [ -z "$JAVACMD" ] ; then
163 | if [ -n "$JAVA_HOME" ] ; then
164 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
165 | # IBM's JDK on AIX uses strange locations for the executables
166 | JAVACMD="$JAVA_HOME/jre/sh/java"
167 | else
168 | JAVACMD="$JAVA_HOME/bin/java"
169 | fi
170 | else
171 | JAVACMD="`which java`"
172 | fi
173 | fi
174 |
175 | if [ ! -x "$JAVACMD" ] ; then
176 | echo "Error: JAVA_HOME is not defined correctly." >&2
177 | echo " We cannot execute $JAVACMD" >&2
178 | exit 1
179 | fi
180 |
181 | if [ -z "$JAVA_HOME" ] ; then
182 | echo "Warning: JAVA_HOME environment variable is not set."
183 | fi
184 |
185 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
186 |
187 | # For Cygwin, switch paths to Windows format before running java
188 | if $cygwin; then
189 | [ -n "$M2_HOME" ] &&
190 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
191 | [ -n "$JAVA_HOME" ] &&
192 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
193 | [ -n "$CLASSPATH" ] &&
194 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
195 | fi
196 |
197 | # traverses directory structure from process work directory to filesystem root
198 | # first directory with .mvn subdirectory is considered project base directory
199 | find_maven_basedir() {
200 | local basedir=$(pwd)
201 | local wdir=$(pwd)
202 | while [ "$wdir" != '/' ] ; do
203 | if [ -d "$wdir"/.mvn ] ; then
204 | basedir=$wdir
205 | break
206 | fi
207 | wdir=$(cd "$wdir/.."; pwd)
208 | done
209 | echo "${basedir}"
210 | }
211 |
212 | # concatenates all lines of a file
213 | concat_lines() {
214 | if [ -f "$1" ]; then
215 | echo "$(tr -s '\n' ' ' < "$1")"
216 | fi
217 | }
218 |
219 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
220 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
221 |
222 | # Provide a "standardized" way to retrieve the CLI args that will
223 | # work with both Windows and non-Windows executions.
224 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
225 | export MAVEN_CMD_LINE_ARGS
226 |
227 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
228 |
229 | exec "$JAVACMD" \
230 | $MAVEN_OPTS \
231 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
232 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
233 | ${WRAPPER_LAUNCHER} "$@"
234 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
40 |
41 | @REM set %HOME% to equivalent of $HOME
42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
43 |
44 | @REM Execute a user defined script before this one
45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
49 | :skipRcPre
50 |
51 | @setlocal
52 |
53 | set ERROR_CODE=0
54 |
55 | @REM To isolate internal variables from possible post scripts, we use another setlocal
56 | @setlocal
57 |
58 | @REM ==== START VALIDATION ====
59 | if not "%JAVA_HOME%" == "" goto OkJHome
60 |
61 | echo.
62 | echo Error: JAVA_HOME not found in your environment. >&2
63 | echo Please set the JAVA_HOME variable in your environment to match the >&2
64 | echo location of your Java installation. >&2
65 | echo.
66 | goto error
67 |
68 | :OkJHome
69 | if exist "%JAVA_HOME%\bin\java.exe" goto init
70 |
71 | echo.
72 | echo Error: JAVA_HOME is set to an invalid directory. >&2
73 | echo JAVA_HOME = "%JAVA_HOME%" >&2
74 | echo Please set the JAVA_HOME variable in your environment to match the >&2
75 | echo location of your Java installation. >&2
76 | echo.
77 | goto error
78 |
79 | @REM ==== END VALIDATION ====
80 |
81 | :init
82 |
83 | set MAVEN_CMD_LINE_ARGS=%*
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 |
121 | set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar""
122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
123 |
124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
125 | if ERRORLEVEL 1 goto error
126 | goto end
127 |
128 | :error
129 | set ERROR_CODE=1
130 |
131 | :end
132 | @endlocal & set ERROR_CODE=%ERROR_CODE%
133 |
134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
138 | :skipRcPost
139 |
140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
142 |
143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
144 |
145 | exit /B %ERROR_CODE%
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.xbongbong
7 | xbb-web-socket
8 | 1.1.3-jushita
9 | jar
10 |
11 | xbb-web-socket
12 | A Web Socket Project for Xbb bySpring Boot
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 1.5.2.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 1.8
25 | 1.8.9-SNAPSHOT
26 | 0.0.4-SNAPSHOT
27 | 4.12
28 | 1.2.24
29 | 2.8.2
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-starter-thymeleaf
49 |
50 |
51 | org.springframework.boot
52 | spring-boot-starter-websocket
53 |
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-devtools
58 | runtime
59 |
60 |
61 | org.springframework.boot
62 | spring-boot-starter
63 |
64 |
65 | org.springframework.boot
66 | spring-boot-starter-logging
67 |
68 |
69 |
70 |
71 |
72 | org.springframework.boot
73 | spring-boot-starter-actuator
74 |
75 |
76 | org.springframework.boot
77 | spring-boot-starter-hateoas
78 |
79 |
80 |
81 | org.springframework.boot
82 | spring-boot-starter-log4j2
83 |
84 |
85 |
86 |
87 | redis.clients
88 | jedis
89 | ${jedis.version}
90 |
91 |
92 |
93 |
94 | com.alibaba
95 | fastjson
96 | ${fastjson.version}
97 |
98 |
99 |
100 |
101 | org.springframework.boot
102 | spring-boot-starter-test
103 | test
104 |
105 |
106 |
107 |
108 |
109 |
110 | src/main/resources
111 |
112 |
113 |
114 |
115 | org.springframework.boot
116 | spring-boot-maven-plugin
117 |
118 | true
119 |
120 |
121 |
122 | org.apache.maven.plugins
123 | maven-compiler-plugin
124 |
125 | 1.7
126 | 1.7
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | # must be unique in a given SonarQube instance
2 | sonar.projectKey=org.codehaus.sonar:xbbSocket
3 | # this is the name displayed in the SonarQube UI
4 | sonar.projectName=xbb-web-socket
5 | sonar.projectVersion=1.0
6 |
7 | # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
8 | # Since SonarQube 4.2, this property is optional if sonar.modules is set.
9 | # If not set, SonarQube starts looking for source code from the directory containing
10 | # the sonar-project.properties file.
11 | sonar.sources=src
12 | # sonar.exclusions=src/main/resources/**
13 |
14 | # Encoding of the source code. Default is default system encoding
15 | sonar.sourceEncoding=UTF-8
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/LocalConstant.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong;
2 |
3 | import org.springframework.boot.context.properties.ConfigurationProperties;
4 | import org.springframework.stereotype.Component;
5 |
6 | /**
7 | * User: Gavin
8 | * E-mail: GavinChangCN@163.com
9 | * Desc:
10 | * Date: 2017-03-23
11 | * Time: 11:26
12 | */
13 | @Component
14 | @ConfigurationProperties(prefix="localConstant")
15 | public class LocalConstant {
16 | protected static final String TAG = "localConstant";
17 |
18 | private String projectName;
19 |
20 | public void setProjectName(String projectName) {
21 | this.projectName = projectName;
22 | }
23 |
24 | public String getProjectName() {
25 | return projectName;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/XbbWebSocketApplication.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong;
2 |
3 | import org.springframework.boot.Banner;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.boot.builder.SpringApplicationBuilder;
6 |
7 | @SpringBootApplication
8 | public class XbbWebSocketApplication {
9 |
10 | public static void main(String[] args) {
11 | // SpringApplication.run(XbbWebSocketApplication.class, args);
12 | new SpringApplicationBuilder(XbbWebSocketApplication.class)
13 | .bannerMode(Banner.Mode.CONSOLE) // 控制 Banner 的显示模式,Banner 在resources中的 Banner.txt内,可以前往 http://patorjk.com/software/taag 进行自定义
14 | .run(args);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/base/BaseController.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.base;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.xbongbong.util.StringUtil;
5 |
6 | import java.io.IOException;
7 |
8 | /**
9 | * User: Gavin
10 | * E-mail: GavinChangCN@163.com
11 | * Desc:
12 | * Date: 2017-03-18
13 | * Time: 19:07
14 | */
15 | public class BaseController {
16 | protected static final String TAG = "BaseController";
17 |
18 | /**
19 | * 设置Controller的返回值
20 | *
21 | * @param errorCode
22 | * @param msg
23 | * @param param
24 | * @return
25 | * @throws IOException
26 | * @author huajun.zhang
27 | * @time 2017-02-21 上午10:25:00
28 | */
29 | public String formatResponse(int errorCode, String msg, String param) {
30 |
31 | // response.addHeader("content-type", "application/json;charset=utf-8");
32 | // response.addHeader("Access-Control-Allow-Origin", "*");
33 | // response.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
34 | JSONObject json = new JSONObject();
35 | json.put("code", errorCode);
36 | json.put("msg", msg);
37 | if (!StringUtil.isEmpty(param)) {
38 | json.put("param", param);
39 | }
40 | return json.toJSONString();
41 | }
42 |
43 | public String formatErrorResponse(int errorCode, String msg) {
44 | return formatResponse(errorCode, msg, null);
45 | }
46 |
47 | /**
48 | * 设置Controller的请求成功返回
49 | *
50 | * @return
51 | * @throws IOException
52 | * @author huajun.zhang
53 | * @time 2017-02-21 上午10:26:00
54 | */
55 | public String formatSuccessResponse(String param) {
56 | return formatResponse(1, "success", param);
57 | }
58 |
59 | /**
60 | * 设置Controller的请求成功返回
61 | *
62 | * @return
63 | * @throws IOException
64 | * @author huajun.zhang
65 | * @time 2017-02-21 上午10:26:00
66 | */
67 | public String formatSuccessResponse() {
68 | return formatResponse(1, "success", null);
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/base/BaseModel.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.base;
2 |
3 | /**
4 | * User: Gavin
5 | * E-mail: GavinChangCN@163.com
6 | * Desc:
7 | * Date: 2017-03-07
8 | * Time: 17:45
9 | */
10 | public class BaseModel {
11 | protected static final String TAG = "BaseModel";
12 |
13 | public BaseModel() {
14 | super();
15 | }
16 |
17 | public BaseModel(int code, boolean success, String message) {
18 | super();
19 | this.code = code;
20 | this.success = success;
21 | this.message = message;
22 | }
23 |
24 | private int code;
25 |
26 | private boolean success;
27 |
28 | private String message;
29 |
30 | public int getCode() {
31 | return code;
32 | }
33 |
34 | public void setCode(int code) {
35 | this.code = code;
36 | }
37 |
38 | public boolean isSuccess() {
39 | return success;
40 | }
41 |
42 | public void setSuccess(boolean success) {
43 | this.success = success;
44 | }
45 |
46 | public String getMessage() {
47 | return message;
48 | }
49 |
50 | public void setMessage(String message) {
51 | this.message = message;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/component/ApplicationContextHolder.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.component;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.context.ApplicationContext;
5 | import org.springframework.context.ApplicationContextAware;
6 | import org.springframework.stereotype.Component;
7 |
8 | /**
9 | * User: Gavin
10 | * E-mail: GavinChangCN@163.com
11 | * Desc:
12 | * Date: 2017-03-08
13 | * Time: 13:57
14 | */
15 | @Component
16 | public class ApplicationContextHolder implements ApplicationContextAware {
17 | private static ApplicationContext context;
18 |
19 | @Override
20 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
21 | context = applicationContext;
22 | }
23 |
24 | public static ApplicationContext getContext() {
25 | return context;
26 | }
27 | }
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/component/RedisClient.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.component;
2 |
3 | import com.xbongbong.LocalConstant;
4 | import org.apache.logging.log4j.LogManager;
5 | import org.apache.logging.log4j.Logger;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.stereotype.Component;
8 | import redis.clients.jedis.Jedis;
9 | import redis.clients.jedis.JedisPool;
10 |
11 | import java.util.List;
12 |
13 | /**
14 | * User: Gavin
15 | * E-mail: GavinChangCN@163.com
16 | * Desc:
17 | * Date: 2017-03-07
18 | * Time: 19:39
19 | */
20 | @Component
21 | public class RedisClient {
22 |
23 | private static final Logger LOG = LogManager
24 | .getLogger(RedisClient.class);
25 |
26 | @Autowired
27 | private LocalConstant localConstant;
28 | @Autowired
29 | private JedisPool jedisPool;
30 |
31 | public void set(String key, String value) throws Exception {
32 | Jedis jedis = null;
33 | String subUserHashKey = localConstant.getProjectName() + ":" + key;
34 | try {
35 | jedis = jedisPool.getResource();
36 | jedis.set(subUserHashKey, value);
37 | } finally {
38 | //返还到连接池
39 | if (jedis != null) {
40 | jedis.close();
41 | }
42 | }
43 | }
44 |
45 | public String get(String key) throws Exception {
46 | Jedis jedis = null;
47 | String subUserHashKey = localConstant.getProjectName() + ":" + key;
48 | try {
49 | jedis = jedisPool.getResource();
50 | return jedis.get(subUserHashKey);
51 | } finally {
52 | //返还到连接池
53 | if (jedis != null) {
54 | jedis.close();
55 | }
56 | }
57 | }
58 |
59 | public long lpush(String key, String value) throws Exception {
60 | Jedis jedis = null;
61 | String subUserHashKey = localConstant.getProjectName() + ":" + key;
62 | try {
63 | jedis = jedisPool.getResource();
64 | return jedis.lpush(subUserHashKey, value);
65 | } finally {
66 | //返还到连接池
67 | if (jedis != null) {
68 | jedis.close();
69 | }
70 | }
71 | }
72 |
73 | /**
74 | * 将任务 List 左边插入 key 的 jedis 队列
75 | * @param key
76 | * @param valueList
77 | * @return
78 | * @throws Exception
79 | */
80 | public void lpushList(String key, List valueList) throws Exception {
81 | Jedis jedis = null;
82 | String subUserHashKey = localConstant.getProjectName() + ":" + key;
83 | try {
84 | jedis = jedisPool.getResource();
85 | for (String value : valueList) {
86 | jedis.lpush(subUserHashKey, value);
87 | }
88 | } finally {
89 | //返还到连接池
90 | if (jedis != null) {
91 | jedis.close();
92 | }
93 | }
94 | }
95 |
96 | public String rpop(String key) throws Exception {
97 | Jedis jedis = null;
98 | String subUserHashKey = localConstant.getProjectName() + ":" + key;
99 | try {
100 | jedis = jedisPool.getResource();
101 | return jedis.rpop(subUserHashKey);
102 | } finally {
103 | //返还到连接池
104 | if (jedis != null) {
105 | jedis.close();
106 | }
107 | }
108 | }
109 |
110 | public String rpoplpush(String popKey, String pushKey) throws Exception {
111 | Jedis jedis = null;
112 | String subUserHashPopKey = localConstant.getProjectName() + ":" + popKey;
113 | String subUserHashPushKey = localConstant.getProjectName() + ":" + pushKey;
114 | try {
115 | jedis = jedisPool.getResource();
116 | return jedis.rpoplpush(subUserHashPopKey, subUserHashPushKey);
117 | } finally {
118 | //返还到连接池
119 | if (jedis != null) {
120 | jedis.close();
121 | }
122 | }
123 | }
124 |
125 | public Long showListLength(String key) throws Exception {
126 | Jedis jedis = null;
127 | String subUserHashKey = localConstant.getProjectName() + ":" + key;
128 | try {
129 | jedis = jedisPool.getResource();
130 | return jedis.llen(subUserHashKey);
131 | } finally {
132 | //返还到连接池
133 | if (jedis != null) {
134 | jedis.close();
135 | }
136 | }
137 | }
138 |
139 | }
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/config/RedisConfig.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.config;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.beans.factory.annotation.Qualifier;
5 | import org.springframework.beans.factory.annotation.Value;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.ComponentScan;
8 | import org.springframework.context.annotation.Configuration;
9 | import redis.clients.jedis.JedisPool;
10 | import redis.clients.jedis.JedisPoolConfig;
11 |
12 | /**
13 | * User: Gavin
14 | * E-mail: GavinChangCN@163.com
15 | * Desc:
16 | * Date: 2017-03-07
17 | * Time: 19:21
18 | */
19 | @Configuration
20 | @ComponentScan("com.xbongbong.component")
21 | public class RedisConfig {
22 |
23 | @Bean(name = "jedis.pool")
24 | @Autowired
25 | public JedisPool jedisPool(@Qualifier("jedis.pool.config") JedisPoolConfig config,
26 | @Value("${jedis.pool.host}") String host,
27 | @Value("${jedis.pool.port}") int port,
28 | @Value("${jedis.pool.timeout}") int timeout,
29 | @Value("${jedis.pool.password}") String password) {
30 | return new JedisPool(config, host, port, timeout, password);
31 | }
32 |
33 | @Bean(name = "jedis.pool.config")
34 | public JedisPoolConfig jedisPoolConfig(@Value("${jedis.pool.config.maxTotal}") int maxTotal,
35 | @Value("${jedis.pool.config.maxIdle}") int maxIdle,
36 | @Value("${jedis.pool.config.maxWaitMillis}") int maxWaitMillis) {
37 | JedisPoolConfig config = new JedisPoolConfig();
38 | config.setMaxTotal(maxTotal);
39 | config.setMaxIdle(maxIdle);
40 | config.setMaxWaitMillis(maxWaitMillis);
41 | return config;
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/config/TaskSchedulerConfig.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.config;
2 |
3 | import org.springframework.context.annotation.ComponentScan;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.scheduling.annotation.EnableScheduling;
6 |
7 | /**
8 | * User: Gavin
9 | * E-mail: GavinChangCN@163.com
10 | * Desc:
11 | * Date: 2017-03-08
12 | * Time: 14:41
13 | */
14 | @Configuration
15 | @ComponentScan(value = "com.xbongbong.service.task")
16 | @EnableScheduling
17 | public class TaskSchedulerConfig {
18 | protected static final String TAG = "TaskSchedulerConfig";
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/config/WebMvcConfig.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.config;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 | import org.springframework.web.servlet.config.annotation.*;
5 |
6 | /**
7 | * User: Gavin
8 | * E-mail: GavinChangCN@163.com
9 | * Desc:
10 | * Date: 2017-03-07
11 | * Time: 16:56
12 | */
13 | @Configuration
14 | @EnableWebMvc
15 | public class WebMvcConfig extends WebMvcConfigurerAdapter {
16 | protected static final String TAG = "WebMvcConfig";
17 |
18 | @Override
19 | public void addViewControllers(ViewControllerRegistry registry) {
20 | super.addViewControllers(registry);
21 | // urlPath 是希望 用户 访问的地址栏显示,ViewName 是 html 的目录+文件名
22 | registry.addViewController("/chat").setViewName("websocket");
23 | }
24 |
25 | // Spring Boot 管理平台,暂时关闭
26 | // @Bean
27 | // public CustomerInterceptor customerInterceptor() {
28 | // return new CustomerInterceptor();
29 | // }
30 | // @Override
31 | // public void addInterceptors(InterceptorRegistry registry) {
32 | // super.addInterceptors(registry);
33 | // registry.addInterceptor(customerInterceptor());
34 | // }
35 |
36 | // ------------------------------- Thymeleaf 的配置, Spring Boot 不需要,已经自动配置 Begin -------------------------------
37 | // @Bean
38 | // public TemplateResolver templateResolver() {
39 | // TemplateResolver templateResolver =
40 | // new ServletContextTemplateResolver();
41 | // templateResolver.setPrefix("/WEB-INF/templates");
42 | // templateResolver.setSuffix(".html");
43 | //// templateResolver.setContentType("text/html;charset=UTF-8");
44 | // templateResolver.setTemplateMode("HTML5");
45 | // return templateResolver;
46 | // }
47 | //
48 | // @Bean
49 | // public SpringTemplateEngine templateEngine() {
50 | // SpringTemplateEngine templateEngine = new SpringTemplateEngine();
51 | // templateEngine.setTemplateResolver(templateResolver());
52 | // return templateEngine;
53 | // }
54 | //
55 | // @Bean
56 | // public ThymeleafViewResolver thymeleafViewResolver() {
57 | // ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver();
58 | // thymeleafViewResolver.setTemplateEngine(templateEngine());
59 | // thymeleafViewResolver.setViewClass(ThymeleafView.class);
60 | // return thymeleafViewResolver;
61 | // }
62 | // ------------------------------- Thymeleaf 的配置, Spring Boot 不需要,已经自动配置 End -------------------------------
63 |
64 | @Override
65 | public void addResourceHandlers(ResourceHandlerRegistry registry) {
66 | super.addResourceHandlers(registry);
67 | registry.addResourceHandler("/**").addResourceLocations("classpath:/**");
68 | }
69 |
70 | @Override
71 | public void configurePathMatch(PathMatchConfigurer configurer) {
72 | super.configurePathMatch(configurer);
73 | configurer.setUseSuffixPatternMatch(false); // 不忽略 URL 请求中的"."
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/config/WebSocketConfig.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.web.socket.server.standard.ServerEndpointExporter;
6 |
7 | /**
8 | * User: Gavin
9 | * E-mail: GavinChangCN@163.com
10 | * Desc:
11 | * Date: 2017-03-06
12 | * Time: 19:18
13 | */
14 | @Configuration
15 | public class WebSocketConfig {
16 | protected static final String TAG = "WebSocketConfig";
17 |
18 | @Bean
19 | public ServerEndpointExporter serverEndpointExporter() {
20 | return new ServerEndpointExporter();
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/controller/BroadcastController.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.controller;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.xbongbong.base.BaseController;
5 | import com.xbongbong.component.RedisClient;
6 | import com.xbongbong.entity.BroadcastMessageEntity;
7 | import com.xbongbong.entity.PushMessageEntity;
8 | import com.xbongbong.socket.XbbWebSocket;
9 | import com.xbongbong.util.DateUtil;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.context.annotation.Bean;
12 | import org.springframework.web.bind.annotation.RequestMapping;
13 | import org.springframework.web.bind.annotation.RestController;
14 |
15 | /**
16 | * User: Gavin
17 | * E-mail: GavinChangCN@163.com
18 | * Desc:
19 | * Date: 2017-03-18
20 | * Time: 18:29
21 | */
22 | @RestController
23 | @RequestMapping(value = "/broadcast", produces = "application/json;charset=UTF-8")
24 | public class BroadcastController extends BaseController {
25 | protected static final String TAG = "BroadcastController";
26 |
27 | @Bean
28 | public XbbWebSocket webSocket() {
29 | return new XbbWebSocket();
30 | }
31 |
32 | @Autowired
33 | private RedisClient redisClient;
34 |
35 | /**
36 | * 紧急广播信息(只有标题,没有内容,立刻推送)
37 | *
38 | * @param title 广播标题
39 | * @param url 广播对应的 Html 地址
40 | * @return
41 | */
42 | @RequestMapping("/urgent")
43 | public String broadcastUrgent(String title, String url) {
44 | PushMessageEntity message = new PushMessageEntity(title, "", url);
45 | BroadcastMessageEntity broadcastMessage = new BroadcastMessageEntity(JSON.toJSONString(message), DateUtil.getInt());
46 | try {
47 | webSocket().sendBroadcast(JSON.toJSONString(broadcastMessage));
48 | return formatSuccessResponse();
49 | } catch (Exception e) {
50 | return formatErrorResponse(-1, "false");
51 | }
52 | }
53 |
54 | /**
55 | * 广播信息
56 | *
57 | * @param title 广播标题
58 | * @param content 广播内容
59 | * @param url 广播对应的 Html 地址
60 | * @param pushTime 广播推送时间
61 | * @return
62 | */
63 | @RequestMapping("/common")
64 | public String broadcastCommon(final String title, final String content, final String url, final int pushTime) {
65 | try {
66 | new Thread(new Runnable() {
67 | @Override
68 | public void run() {
69 | PushMessageEntity message = new PushMessageEntity(title, content, url);
70 | BroadcastMessageEntity broadcastMessage = new BroadcastMessageEntity(JSON.toJSONString(message), pushTime);
71 | boolean flag = true;
72 | while (flag) {
73 | if (DateUtil.getInt() > pushTime) {
74 | flag = false;
75 | webSocket().sendBroadcast(JSON.toJSONString(broadcastMessage));
76 | }
77 | }
78 | }
79 | }).start();
80 | return formatSuccessResponse();
81 | } catch (Exception e) {
82 | return formatErrorResponse(-1, "false");
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/controller/ExampleController.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.controller;
2 |
3 | import com.xbongbong.base.BaseController;
4 | import com.xbongbong.component.RedisClient;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.web.bind.annotation.RequestMapping;
7 | import org.springframework.web.bind.annotation.RestController;
8 |
9 | /**
10 | * User: Gavin
11 | * E-mail: GavinChangCN@163.com
12 | * Desc:
13 | * Date: 2017-03-07
14 | * Time: 19:25
15 | */
16 | @RestController
17 | @RequestMapping(value = "/example", produces = "application/json;charset=UTF-8")
18 | public class ExampleController extends BaseController {
19 |
20 | @Autowired
21 | private RedisClient redisClient;
22 |
23 | @RequestMapping("/set")
24 | public String set(String key, String value) throws Exception{
25 | redisClient.set(key, value);
26 | return formatSuccessResponse();
27 | }
28 |
29 | @RequestMapping("/get")
30 | public String get(String key) throws Exception {
31 | return formatSuccessResponse(redisClient.get(key));
32 | }
33 | }
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/controller/UnicastController.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.controller;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.xbongbong.base.BaseController;
5 | import com.xbongbong.component.RedisClient;
6 | import com.xbongbong.socket.XbbWebSocket;
7 | import org.apache.logging.log4j.LogManager;
8 | import org.apache.logging.log4j.Logger;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.context.annotation.Bean;
11 | import org.springframework.web.bind.annotation.RequestMapping;
12 | import org.springframework.web.bind.annotation.RestController;
13 |
14 | import java.util.List;
15 |
16 | /**
17 | * User: Gavin
18 | * E-mail: GavinChangCN@163.com
19 | * Desc:
20 | * Date: 2017-03-18
21 | * Time: 18:29
22 | */
23 | @RestController
24 | @RequestMapping(value = "/unicast", produces = "application/json;charset=UTF-8")
25 | public class UnicastController extends BaseController {
26 |
27 | private static final Logger LOG = LogManager.getLogger(UnicastController.class);
28 |
29 | protected static final String TAG = "UnicastController";
30 | private static final String REDIS_WEB_SOCKET_TASK_QUEUE_KEY = "socket-task-queue";
31 |
32 | @Bean
33 | public XbbWebSocket webSocket() {
34 | return new XbbWebSocket();
35 | }
36 |
37 | @Autowired
38 | private RedisClient redisClient;
39 |
40 | /**
41 | * 将单播信息插入Redis队列
42 | *
43 | * @param message
44 | * @return
45 | */
46 | @RequestMapping("/push2Redis")
47 | public String push2Redis(String message) {
48 |
49 | try {
50 | redisClient.lpush(REDIS_WEB_SOCKET_TASK_QUEUE_KEY, message);
51 | return formatSuccessResponse();
52 | } catch (Exception e) {
53 | LOG.info("插入到 Redis 任务队列 -> " + REDIS_WEB_SOCKET_TASK_QUEUE_KEY + " 失败!");
54 | e.printStackTrace();
55 | return formatErrorResponse(-1, "false");
56 | }
57 | }
58 |
59 | /**
60 | * 将单播信息列表插入Redis队列
61 | *
62 | * @param message
63 | * @return
64 | */
65 | @RequestMapping("/pushList2Redis")
66 | public String pushList2Redis(String message) {
67 | try {
68 | List webSocketTaskMessageList = JSON.parseArray(message, String.class);
69 | redisClient.lpushList(REDIS_WEB_SOCKET_TASK_QUEUE_KEY, webSocketTaskMessageList);
70 | return formatSuccessResponse();
71 | } catch (Exception e) {
72 | LOG.info("插入到 Redis 任务队列 -> " + REDIS_WEB_SOCKET_TASK_QUEUE_KEY + " 失败!");
73 | e.printStackTrace();
74 | return formatErrorResponse(-1, "false");
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/entity/BroadcastMessageEntity.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.entity;
2 |
3 | import com.xbongbong.util.DateUtil;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * User: Gavin
9 | * E-mail: GavinChangCN@163.com
10 | * Desc:
11 | * Date: 2017-03-08
12 | * Time: 16:57
13 | */
14 | public class BroadcastMessageEntity implements Serializable {
15 |
16 | /**
17 | * Comment for serialVersionUID
18 | */
19 | private static final long serialVersionUID = -1L;
20 |
21 | private String message;
22 | private int pushTime;
23 | private int addTime;
24 |
25 | public BroadcastMessageEntity() {
26 | }
27 |
28 | public BroadcastMessageEntity(String message, int pushTime) {
29 | this.message = message;
30 | this.pushTime = pushTime;
31 | this.addTime = DateUtil.getInt();
32 | }
33 |
34 | public String getMessage() {
35 | return message;
36 | }
37 |
38 | public void setMessage(String message) {
39 | this.message = message;
40 | }
41 |
42 | public int getPushTime() {
43 | return pushTime;
44 | }
45 |
46 | public void setPushTime(int pushTime) {
47 | this.pushTime = pushTime;
48 | }
49 |
50 | public int getAddTime() {
51 | return addTime;
52 | }
53 |
54 | public void setAddTime(int addTime) {
55 | this.addTime = addTime;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/entity/PushMessageEntity.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.entity;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * User: Gavin
7 | * E-mail: GavinChangCN@163.com
8 | * Desc:
9 | * Date: 2017-03-10
10 | * Time: 14:42
11 | */
12 | public class PushMessageEntity implements Serializable {
13 |
14 | /**
15 | * Comment for serialVersionUID
16 | */
17 | private static final long serialVersionUID = -1L;
18 |
19 | private String title;
20 | private String content;
21 | private String messageUrl;
22 |
23 | public PushMessageEntity() {
24 | }
25 |
26 | public PushMessageEntity(String title, String content, String messageUrl) {
27 | this.title = title;
28 | this.content = content;
29 | this.messageUrl = messageUrl;
30 | }
31 |
32 | public String getTitle() {
33 | return title;
34 | }
35 |
36 | public void setTitle(String title) {
37 | this.title = title;
38 | }
39 |
40 | public String getContent() {
41 | return content;
42 | }
43 |
44 | public void setContent(String content) {
45 | this.content = content;
46 | }
47 |
48 | public String getMessageUrl() {
49 | return messageUrl;
50 | }
51 |
52 | public void setMessageUrl(String messageUrl) {
53 | this.messageUrl = messageUrl;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/entity/SocketIdCardEntity.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.entity;
2 |
3 | import com.xbongbong.util.StringUtil;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * User: Gavin
9 | * E-mail: GavinChangCN@163.com
10 | * Desc:
11 | * Date: 2017-03-08
12 | * Time: 16:37
13 | */
14 | public class SocketIdCardEntity implements Serializable {
15 |
16 | /**
17 | * Comment for serialVersionUID
18 | */
19 | private static final long serialVersionUID = -1L;
20 |
21 | private String corpid;
22 | private String userId;
23 | private String platform;
24 |
25 | public SocketIdCardEntity() {
26 | }
27 |
28 | public SocketIdCardEntity(String corpid, String userId, String platform) {
29 | this.corpid = corpid;
30 | this.userId = userId;
31 | this.platform = platform;
32 | }
33 |
34 | public String getCorpid() {
35 | return corpid;
36 | }
37 |
38 | public void setCorpid(String corpid) {
39 | this.corpid = corpid;
40 | }
41 |
42 | public String getUserId() {
43 | return userId;
44 | }
45 |
46 | public void setUserId(String userId) {
47 | this.userId = userId;
48 | }
49 |
50 | public String getPlatform() {
51 | return platform;
52 | }
53 |
54 | public void setPlatform(String platform) {
55 | this.platform = platform;
56 | }
57 |
58 | @Override
59 | public boolean equals(Object obj) {
60 | if (obj instanceof SocketIdCardEntity) {
61 | SocketIdCardEntity another = (SocketIdCardEntity) obj;
62 | return (!StringUtil.isEmpty(this.getCorpid()) && this.getCorpid().equals(another.getCorpid()))
63 | && (!StringUtil.isEmpty(this.getUserId()) && this.getUserId().equals(another.getUserId()))
64 | && (!StringUtil.isEmpty(this.getPlatform()) && this.getPlatform().equals(another.getPlatform()));
65 | } else {
66 | return false;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/entity/UnicastMessageEntity.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.entity;
2 |
3 | import com.xbongbong.util.DateUtil;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * User: Gavin
9 | * E-mail: GavinChangCN@163.com
10 | * Desc:
11 | * Date: 2017-03-18
12 | * Time: 19:40
13 | */
14 | public class UnicastMessageEntity implements Serializable {
15 |
16 | /**
17 | * Comment for serialVersionUID
18 | */
19 | private static final long serialVersionUID = -1L;
20 |
21 | private String corpid;
22 | private String userId;
23 | private String message;
24 | private int pushTime;
25 | private int addTime;
26 |
27 | public UnicastMessageEntity() {
28 | }
29 |
30 | public UnicastMessageEntity(String corpid, String userId, String message, int pushTime) {
31 | this.corpid = corpid;
32 | this.userId = userId;
33 | this.message = message;
34 | this.pushTime = pushTime;
35 | this.addTime = DateUtil.getInt();
36 | }
37 |
38 | public String getCorpid() {
39 | return corpid;
40 | }
41 |
42 | public void setCorpid(String corpid) {
43 | this.corpid = corpid;
44 | }
45 |
46 | public String getUserId() {
47 | return userId;
48 | }
49 |
50 | public void setUserId(String userId) {
51 | this.userId = userId;
52 | }
53 |
54 | public String getMessage() {
55 | return message;
56 | }
57 |
58 | public void setMessage(String message) {
59 | this.message = message;
60 | }
61 |
62 | public int getPushTime() {
63 | return pushTime;
64 | }
65 |
66 | public void setPushTime(int pushTime) {
67 | this.pushTime = pushTime;
68 | }
69 |
70 | public int getAddTime() {
71 | return addTime;
72 | }
73 |
74 | public void setAddTime(int addTime) {
75 | this.addTime = addTime;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/model/ResponseModal.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.model;
2 |
3 |
4 | import com.xbongbong.base.BaseModel;
5 |
6 | /**
7 | * User: Gavin
8 | * E-mail: GavinChangCN@163.com
9 | * Desc:
10 | * Date: 2017-03-07
11 | * Time: 17:45
12 | */
13 | public class ResponseModal extends BaseModel {
14 |
15 |
16 | public ResponseModal(){
17 | super();
18 | }
19 |
20 | public ResponseModal(int code, boolean success, String message){
21 | super(code,success,message);
22 | }
23 |
24 | public ResponseModal(int code, boolean success, String message, Object obj){
25 | super(code,success,message);
26 | this.response = obj;
27 | }
28 |
29 | private Object response;
30 |
31 | public Object getResponse() {
32 | return response;
33 | }
34 |
35 | public void setResponse(Object response) {
36 | this.response = response;
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/service/task/ScheduledTaskProducerService.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.service.task;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.xbongbong.component.RedisClient;
5 | import com.xbongbong.entity.PushMessageEntity;
6 | import com.xbongbong.entity.UnicastMessageEntity;
7 | import com.xbongbong.socket.XbbWebSocket;
8 | import com.xbongbong.util.DateUtil;
9 | import com.xbongbong.util.ExceptionUtil;
10 | import org.apache.logging.log4j.LogManager;
11 | import org.apache.logging.log4j.Logger;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.context.annotation.Bean;
14 | import org.springframework.scheduling.annotation.Scheduled;
15 | import org.springframework.stereotype.Service;
16 |
17 | /**
18 | * User: Gavin
19 | * E-mail: GavinChangCN@163.com
20 | * Desc:
21 | * Date: 2017-03-08
22 | * Time: 14:36
23 | */
24 | @Service
25 | public class ScheduledTaskProducerService {
26 | protected static final String TAG = "ScheduledTaskProducerService";
27 |
28 | private static final String REDIS_WORK_ARRAY_KEY = "socket-task-queue";
29 | private static final String REDIS_TEMP_ARRAY_KEY = "socket-tmp-queue";
30 |
31 | private static final Logger LOG = LogManager
32 | .getLogger(ScheduledTaskProducerService.class);
33 |
34 | private int index = 0;
35 |
36 | @Autowired
37 | private RedisClient redisClient;
38 |
39 | @Bean
40 | public XbbWebSocket webSocket() {
41 | return new XbbWebSocket();
42 | }
43 |
44 | @Scheduled(fixedRate = 150)
45 | public void popUnicastMessage() {
46 | // 0.15s执行一次
47 | pushUnicastMessage();
48 | if ((++index) % 400 == 0) { // 每60秒输出一次当前用户和工作队列信息
49 | webSocket().showOnlineUserNum();
50 | index = 0;
51 | // 每十次显示一下当前队列中的数据
52 | try {
53 | LOG.info("Redis 中推送消息队列 socket-task-queue 的长度:" + redisClient.showListLength(REDIS_WORK_ARRAY_KEY));
54 | // LOG.info("Redis 中临时队列 socket-tmp-queue 的长度:" + redisClient.showListLength(REDIS_TEMP_ARRAY_KEY));
55 | } catch (Exception e) {
56 | LOG.error("捕获从 Redis 工作队列读取消息做处理准备时异常!异常内容:" + ExceptionUtil.getStackMsg(e));
57 | }
58 | }
59 | }
60 |
61 | // @Scheduled(cron = "0 25 10 ? * *")
62 | // public void fixTimeExecution() throws Exception {
63 | // LOG.info(String.format(" 在指定时间 " + dateFormat.format(new Date()) + " 执行"));
64 | // String popMessage = popTask4Jedis();
65 | // if (StringUtil.isEmpty(popMessage)) {
66 | // return;
67 | // }
68 | // LOG.info(popMessage);
69 | // }
70 |
71 | /**
72 | * 发送单播信息
73 | *
74 | * @throws Exception
75 | */
76 | private void pushUnicastMessage() {
77 | //从任务队列"socket-task-queue"中获取一个任务,并将该任务放入暂存队列"socket-tmp-queue"
78 | String messageJsonStr = null;
79 | try {
80 | messageJsonStr = redisClient.rpop(REDIS_WORK_ARRAY_KEY);
81 | } catch (Exception e) {
82 | LOG.error("捕获从 Redis 工作队列读取消息做处理准备时异常!异常内容:" + ExceptionUtil.getStackMsg(e));
83 | }
84 | if (messageJsonStr == null
85 | || !(messageJsonStr.startsWith("{") && messageJsonStr.endsWith("}"))) {
86 | // LOG.info("空信息,丢弃:" + messageJsonStr);
87 | return;
88 | }
89 | // try {
90 | // redisClient.lpush(REDIS_TEMP_ARRAY_KEY, messageJsonStr);
91 | // } catch (Exception e) {
92 | // LOG.error("捕获从 Redis 工作队列读取消息时异常!异常内容:" + ExceptionUtil.getStackMsg(e));
93 | // }
94 | // // todo 校验消息发送的顺序性预留位置
95 | // try {
96 | // messageJsonStr = redisClient.rpop(REDIS_TEMP_ARRAY_KEY);
97 | // } catch (Exception e) {
98 | // LOG.error("捕获从 Redis 临时队列读取消息做处理准备时异常!异常内容:" + ExceptionUtil.getStackMsg(e));
99 | // }
100 |
101 | UnicastMessageEntity uniCastMessage = JSON.parseObject(messageJsonStr, UnicastMessageEntity.class);
102 | Integer now = DateUtil.getInt();
103 | Integer pushTime = uniCastMessage.getPushTime();
104 | if (pushTime > now) {
105 | // 发送失败:未到发送信息的时间
106 | // LOG.warn("发送单播推送信息失败,未到消息的推送时间");
107 | try {
108 | redisClient.lpush(REDIS_WORK_ARRAY_KEY, messageJsonStr);
109 | } catch (Exception e) {
110 | LOG.error("未到达发送消息时间,捕获从 Redis 临时队列插入工作队列时异常!异常内容:" + ExceptionUtil.getStackMsg(e));
111 | }
112 | } else {
113 | if ((now - pushTime) < 3 * 24 * 60 * 60) { // 3 天内的有效信息
114 | if (webSocket().unicastMessage(uniCastMessage.getCorpid(), uniCastMessage.getUserId(), messageJsonStr)) {
115 | // 发送成功
116 | LOG.info("发送单播推送信息成功:corpid -> " + uniCastMessage.getCorpid() + "; userId -> " + uniCastMessage.getUserId()
117 | + "; content -> " + JSON.parseObject(uniCastMessage.getMessage(), PushMessageEntity.class).getContent());
118 | } else {
119 | // 发送失败:用户未登陆 WebSocket
120 | // LOG.error("发送单播推送信息失败,客户可能已经离线");
121 | try {
122 | redisClient.lpush(REDIS_WORK_ARRAY_KEY, messageJsonStr);
123 | } catch (Exception e) {
124 | LOG.error("正常发送消息失败,捕获从 Redis 临时队列插入工作队列时异常!异常内容:" + ExceptionUtil.getStackMsg(e));
125 | }
126 | }
127 | } else {
128 | // 超过 3 天未发送,垃圾信息,丢弃
129 | try {
130 | LOG.warn("超过 3 天未发送的垃圾信息,丢弃! 消息内容:" + messageJsonStr);
131 | } catch (Exception e) {
132 | LOG.error("捕获从 Redis 临时队列丢弃消息时异常!异常内容:" + ExceptionUtil.getStackMsg(e));
133 | }
134 | }
135 | }
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/socket/XbbWebSocket.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.socket;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.xbongbong.entity.SocketIdCardEntity;
5 | import com.xbongbong.util.ExceptionUtil;
6 | import com.xbongbong.util.StringUtil;
7 | import org.apache.logging.log4j.LogManager;
8 | import org.apache.logging.log4j.Logger;
9 | import org.springframework.stereotype.Component;
10 |
11 | import javax.websocket.*;
12 | import javax.websocket.server.ServerEndpoint;
13 | import java.io.EOFException;
14 | import java.io.IOException;
15 | import java.util.Map;
16 | import java.util.concurrent.ConcurrentHashMap;
17 | import java.util.concurrent.CopyOnWriteArraySet;
18 |
19 | /**
20 | * User: Gavin
21 | * E-mail: GavinChangCN@163.com
22 | * Desc:
23 | * Date: 2017-03-06
24 | * Time: 19:19
25 | */
26 | @ServerEndpoint(value = "/xbbWebSocket")
27 | @Component
28 | public class XbbWebSocket {
29 |
30 | private static final Logger LOG = LogManager
31 | .getLogger(XbbWebSocket.class);
32 |
33 | //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
34 | private static int onlineCount = 0;
35 |
36 | //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocket对象。
37 | private static CopyOnWriteArraySet xbbWebSocketSet = new CopyOnWriteArraySet<>();
38 | private static ConcurrentHashMap sessionIdMap = new ConcurrentHashMap<>();
39 |
40 | //与某个客户端的连接会话,需要通过它来给客户端发送数据
41 | private Session session;
42 |
43 | /**
44 | * 连接建立成功调用的方法
45 | */
46 | @OnOpen
47 | public void onOpen(Session session) {
48 | this.session = session;
49 | xbbWebSocketSet.add(this); //加入set中
50 | addOnlineCount(); //在线数加1
51 | // LOG.info("有新连接加入!当前在线人数为" + getOnlineCount() + " SessionId -> " + this.session.getId());
52 | }
53 |
54 | /**
55 | * 连接关闭调用的方法
56 | */
57 | @OnClose
58 | public void onClose() {
59 | xbbWebSocketSet.remove(this); //从set中删除
60 | subOnlineCount(); //在线数减1
61 | if (sessionIdMap.containsKey(this.session.getId())) {
62 | SocketIdCardEntity idCard = JSON.parseObject(sessionIdMap.get(this.session.getId()), SocketIdCardEntity.class);
63 | sessionIdMap.remove(this.session.getId()); // 去除 Table 中的 Session
64 | // LOG.info("有一连接关闭!当前在线人数为" + getOnlineCount() + " 离线客户的 SessionId:" + this.session.getId()
65 | // + " corpid -> " + idCard.getCorpid() + " userId -> " + idCard.getUserId());
66 | }
67 | // else {
68 | // LOG.info("有一连接关闭!当前在线人数为" + getOnlineCount() + " 离线客户的 SessionId:" + this.session.getId());
69 | // }
70 | }
71 |
72 | /**
73 | * 发生错误时调用
74 | */
75 | @OnError
76 | public void onError(Session session, Throwable error) {
77 | if (sessionIdMap.containsKey(this.session.getId())) {
78 | SocketIdCardEntity idCard = JSON.parseObject(sessionIdMap.get(this.session.getId()), SocketIdCardEntity.class);
79 | sessionIdMap.remove(this.session.getId()); // 去除 Table 中的 Session
80 | // LOG.error("发生错误! 错误由 Session -> " + this.session.getId() + "造成。"
81 | // + " corpid -> " + idCard.getCorpid() + " userId -> " + idCard.getUserId());
82 | } else {
83 | // LOG.error("发生错误! 错误由 Session -> " + this.session.getId() + "造成。");
84 | }
85 | if (error.getClass() != EOFException.class) {
86 | // 忽略 EOFException
87 | error.printStackTrace();
88 | LOG.error("发生错误!" + "错误信息:" + error.getMessage());
89 | }
90 | }
91 |
92 | /**
93 | * 收到客户端消息后调用的方法
94 | *
95 | * @param message 客户端发送过来的消息
96 | */
97 | @OnMessage
98 | public void onMessage(String message, Session session) {
99 | try {
100 | if (StringUtil.isEmpty(message)) {
101 | return;
102 | }
103 | // LOG.info("来自客户端 SessionId -> " + session.getId() + "的消息:" + message);
104 | message = message.trim();
105 | if (message.startsWith("{") && message.endsWith("}")) {
106 | SocketIdCardEntity idCard = JSON.parseObject(message, SocketIdCardEntity.class);
107 | if (StringUtil.isEmpty(idCard.getCorpid()) || StringUtil.isEmpty(idCard.getUserId())) {
108 | LOG.warn("客户 SessionId:" + this.session.getId()
109 | + "传递的唯一标识缺少主要信息!\n其信息内容:" + message);
110 | return;
111 | }
112 | if (sessionIdMap.containsKey(session.getId())) {
113 | SocketIdCardEntity originIdCard
114 | = JSON.parseObject(sessionIdMap.get(this.session.getId()), SocketIdCardEntity.class);
115 | if (!(originIdCard.equals(idCard))) {
116 | LOG.warn("客户 SessionId:" + this.session.getId()
117 | + "; corpid -> " + originIdCard.getCorpid()
118 | + "; userId -> " + originIdCard.getUserId()
119 | + "; platform -> " + originIdCard.getPlatform() + "想要修改 Session 唯一标识,已被阻止"
120 | + "\n其信息内容:" + message);
121 | }
122 | return;
123 | }
124 | for (Map.Entry entry : sessionIdMap.entrySet()) {
125 | String idCardStr = entry.getValue();
126 | if (StringUtil.isEmpty(idCardStr)
127 | || !(idCardStr.startsWith("{") && idCardStr.endsWith("}"))) {
128 | continue;
129 | }
130 | SocketIdCardEntity originIdCard = JSON.parseObject(idCardStr, SocketIdCardEntity.class);
131 | if (originIdCard.equals(idCard)) {
132 | String tempSessionId = entry.getKey();
133 | sessionIdMap.remove(tempSessionId);
134 | for (XbbWebSocket item : xbbWebSocketSet) {
135 | if (item.session.getId().equals(tempSessionId)) {
136 | xbbWebSocketSet.remove(item);
137 | break;
138 | }
139 | }
140 | // LOG.warn("客户 SessionId:" + this.session.getId()
141 | // + "; corpid -> " + idCard.getCorpid()
142 | // + "; userId -> " + idCard.getUserId() + "被其他用户SessionId:" + tempSessionId + "占用,已踢出前用户!");
143 | break;
144 | }
145 | }
146 | // LOG.info("当前在线人数为:" + getOnlineCount() + "\n客户 SessionId:" + this.session.getId()
147 | // + "添加唯一标识 corpid -> " + idCard.getCorpid()
148 | // + " userId -> " + idCard.getUserId());
149 | sessionIdMap.putIfAbsent(session.getId(), message);
150 | }
151 | } catch (Exception e) {
152 | LOG.error("捕获异常,由客户 SessionId:" + this.session.getId() + "造成!异常内容:" + ExceptionUtil.getStackMsg(e));
153 | }
154 | }
155 |
156 | private void sendMessage(String message) {
157 | try {
158 | this.session.getBasicRemote().sendText(message); // 同步发送消息,多条消息会阻塞排队
159 | } catch (IOException e) {
160 | LOG.error("捕获IO异常,由客户 SessionId:" + this.session.getId() + "造成!异常内容:" + ExceptionUtil.getStackMsg(e));
161 | }
162 | //this.session.getAsyncRemote().sendText(message); // 异步发送消息,多条消息会异步发送
163 | }
164 |
165 | /**
166 | * 单播信息:如果当前 Session 在线就发送信息并返回 true,否则返回 false
167 | *
168 | * @param corpid
169 | * @param userId
170 | * @param message
171 | * @return
172 | * @throws IOException
173 | */
174 | public boolean unicastMessage(String corpid, String userId, String message) {
175 | Session unicastSession = null;
176 | for (XbbWebSocket item : xbbWebSocketSet) {
177 | if (sessionIdMap.containsKey(item.session.getId())) {
178 | SocketIdCardEntity idCard = JSON.parseObject(sessionIdMap.get(item.session.getId()), SocketIdCardEntity.class);
179 | if (corpid.equals(idCard.getCorpid()) && userId.equals(idCard.getUserId())) {
180 | unicastSession = item.session;
181 | break;
182 | }
183 | }
184 | }
185 | if (unicastSession == null) {
186 | // LOG.warn("客户"
187 | // + " corpid -> " + corpid + " userId -> " + userId + "离线或未连接,发送失败! 消息内容:" + message);
188 | return false;
189 | }
190 | // todo 因为用户现在会在 vue 和 普通Web 界面切换,所以不能保证准确推送率
191 | // LOG.info("向客户 SeesionId -> " + unicastSession.getId()
192 | // + " corpid -> " + corpid + " userId -> " + userId + " 发送消息:" + message);
193 | try {
194 | unicastSession.getBasicRemote().sendText(message);
195 | } catch (IOException e) {
196 | LOG.error("捕获IO异常,由客户 SessionId:" + this.session.getId() + "造成!异常内容:" + ExceptionUtil.getStackMsg(e));
197 | }
198 | return true;
199 | }
200 |
201 | /**
202 | * 群发自定义消息
203 | */
204 | public void sendBroadcast(String message) {
205 | for (XbbWebSocket item : xbbWebSocketSet) {
206 | item.sendMessage(message);
207 | }
208 | }
209 |
210 | /**
211 | * 显示当前的在线人数
212 | */
213 | public void showOnlineUserNum() {
214 | LOG.info("当前在线人数为:" + getOnlineCount());
215 | }
216 |
217 | private static synchronized int getOnlineCount() {
218 | return onlineCount;
219 | }
220 |
221 | private static synchronized void addOnlineCount() {
222 | XbbWebSocket.onlineCount++;
223 | }
224 |
225 | private static synchronized void subOnlineCount() {
226 | XbbWebSocket.onlineCount--;
227 | }
228 | }
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/util/CustomerInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.util;
2 |
3 | import org.apache.logging.log4j.LogManager;
4 | import org.apache.logging.log4j.Logger;
5 | import org.springframework.web.servlet.ModelAndView;
6 | import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
7 |
8 | import javax.servlet.http.HttpServletRequest;
9 | import javax.servlet.http.HttpServletResponse;
10 |
11 | /**
12 | * User: Gavin
13 | * E-mail: GavinChangCN@163.com
14 | * Desc:
15 | * Date: 2017-03-27
16 | * Time: 14:37
17 | */
18 | public class CustomerInterceptor extends HandlerInterceptorAdapter {
19 | private static final Logger LOG = LogManager.getLogger(CustomerInterceptor.class);
20 | protected static final String TAG = "CustomerInterceptor";
21 |
22 | private static final String KEY_START_TIME = "startTime";
23 | private static final String KEY_HANDLING_TIME = "handlingTime";
24 |
25 | @Override
26 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
27 | long startTime = DateUtil.getLong();
28 | request.setAttribute(KEY_START_TIME, startTime);
29 | return super.preHandle(request, response, handler);
30 | }
31 |
32 | @Override
33 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
34 | super.postHandle(request, response, handler, modelAndView);
35 | long startTime = (Long) request.getAttribute(KEY_START_TIME);
36 | request.removeAttribute(KEY_START_TIME);
37 | long endTime = DateUtil.getLong();
38 | LOG.info("URL:" + request.getRequestURL() + "耗时:" + (endTime - startTime) + "ms");
39 | request.setAttribute(KEY_HANDLING_TIME, endTime - startTime);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/util/DateUtil.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.util;
2 |
3 |
4 | import org.apache.logging.log4j.LogManager;
5 | import org.apache.logging.log4j.Logger;
6 |
7 | import java.text.ParseException;
8 | import java.text.SimpleDateFormat;
9 | import java.util.Calendar;
10 | import java.util.Date;
11 | import java.util.GregorianCalendar;
12 |
13 | public final class DateUtil {
14 | private static final Logger LOG = LogManager.getLogger(DateUtil.class);
15 |
16 | public static SimpleDateFormat SDF = new SimpleDateFormat(
17 | "yyyy-MM-dd HH:mm:ss");
18 | public static SimpleDateFormat SDF_NoFormat = new SimpleDateFormat(
19 | "yyyyMMddHHmmss");
20 | public static SimpleDateFormat SDFYMDHM = new SimpleDateFormat(
21 | "yyyy-MM-dd HH:mm");
22 | public static SimpleDateFormat SDFDate = new SimpleDateFormat("yyyy-MM-dd");
23 | public static SimpleDateFormat SDFDate_NoFormat = new SimpleDateFormat("yyyyMMdd");
24 | public static SimpleDateFormat SDFYears = new SimpleDateFormat("yyyy");
25 | public static SimpleDateFormat SDFTime = new SimpleDateFormat("HH:mm:ss");
26 | public static SimpleDateFormat SDFMonthDay = new SimpleDateFormat("MM-dd");
27 | public static SimpleDateFormat SDFMonth = new SimpleDateFormat("yyyy-MM");
28 |
29 | // long
30 | public static long getLong() {
31 | Date dt = new Date();
32 | long nowtTme = dt.getTime();
33 | return nowtTme;
34 | }
35 |
36 | public static long getLong(Date date) {
37 | if(date==null) return 0;
38 |
39 | return date.getTime();
40 | }
41 |
42 | public static long getLong(String dateString) {
43 | return getLong(dateString,SDFYMDHM);
44 | }
45 |
46 | public static long getLong(String dateString,SimpleDateFormat format) {
47 | if(StringUtil.isEmpty(dateString)) return 0;
48 |
49 | Date dt =getDate(dateString,format);
50 | if(dt == null) return 0;
51 |
52 | return dt.getTime();
53 | }
54 |
55 | public static long getLong(String dateString,String formatStr) {
56 | return getLong(dateString , new SimpleDateFormat(formatStr));
57 | }
58 | // int
59 |
60 | /**
61 | * 获取当天00:00 ,东八区修正,与格林威治时间相差8个小时 28800秒
62 | * @return
63 | */
64 | public static int getTodayInt() {
65 | return getTodayInt(getInt()) ;
66 | }
67 | /**
68 | * 获取当天00:00 ,东八区修正,与格林威治时间相差8个小时 28800秒
69 | * @return
70 | */
71 | public static int getTodayInt(int day) {
72 | return (int)(day+28800) / 86400 * 86400 - 28800;
73 | }
74 |
75 | public static int getInt() {
76 | return (int)(getLong()/1000);
77 | }
78 | public static int getInt(Date date) {
79 | return (int)(getLong( date)/1000);
80 | }
81 |
82 | public static int getInt(String dateString) {
83 |
84 | return (int)(getLong( dateString)/1000);
85 | }
86 |
87 | public static int getInt(String dateString,SimpleDateFormat format) {
88 | if(StringUtil.isEmpty(dateString)) return 0;
89 |
90 | return (int)( getLong( dateString,format)/1000) ;
91 | }
92 | public static int getInt(String dateString,String formatStr) {
93 | return getInt( dateString , new SimpleDateFormat(formatStr));
94 | }
95 |
96 | public static int getNowSDFYears() {
97 | int years = 0;
98 | Date dt = new Date();
99 | String addtime = SDFYears.format(dt);
100 | years = StringUtil.StringToInteger(addtime, 0);
101 | return years;
102 | }
103 |
104 | // String
105 |
106 | public static String getString(SimpleDateFormat format) {
107 | Date dt = new Date();
108 | String addtime = format.format(dt);
109 | return addtime;
110 | }
111 |
112 | public static String getString(String formatStr) {
113 |
114 | return getString(new SimpleDateFormat(formatStr));
115 | }
116 |
117 | public static String getString(Date dt,SimpleDateFormat format) {
118 | if (dt == null) return null;
119 |
120 | String addtime = format.format(dt);
121 | return addtime;
122 | }
123 | public static String getString(Date dt,String formatStr) {
124 | return getString(dt,new SimpleDateFormat(formatStr));
125 | }
126 | public static String getString(Long datetime,SimpleDateFormat format) {
127 | if(datetime == null) return null;
128 |
129 | if(datetime == 0) return "";
130 |
131 | Date dt = new Date(datetime);
132 | String addtime = format.format(dt);
133 | return addtime;
134 | }
135 |
136 | public static String getString(Long datetime,String formatStr) {
137 | return getString(datetime,new SimpleDateFormat(formatStr));
138 | }
139 |
140 | public static String getString(Integer time,SimpleDateFormat format) {
141 | if(time == null) return null;
142 | return getString(1000L*time,format);
143 | }
144 |
145 | public static String getString(Integer time,String formatStr) {
146 | return getString(time,new SimpleDateFormat(formatStr));
147 | }
148 |
149 |
150 | public static String getString() {
151 | return getString(SDFYMDHM);
152 | }
153 |
154 | // public static String getString(Date dt) {
155 | // return getString( dt,SDFYMDHM) ;
156 | // }
157 | public static String getString(Date dt) {
158 | return getString( dt,SDF) ;
159 | }
160 |
161 | public static String getString(long time) {
162 | return getString(time,SDFYMDHM);
163 | }
164 |
165 | public static String getString(int time) {
166 | return getString(time,SDFYMDHM);
167 | }
168 |
169 | public static String getDateString(int time) {
170 | return getString(time,SDFDate);
171 | }
172 | public static String getDateString(Date time) {
173 | return getString(time,SDFDate);
174 | }
175 |
176 | public static String getLeftTime(int startTime,int limitTime) {
177 | String leftTime = null;
178 | Integer now = DateUtil.getInt();
179 | //LOG.info("now:"+now);
180 | Integer differenceTime = now - startTime;
181 | if(differenceTime>=0){
182 | //LOG.info("limitTime:"+limitTime+" differenceTime:"+differenceTime);
183 | Integer leftTimeInt = limitTime - differenceTime;
184 | if(leftTimeInt<0){
185 | leftTimeInt = 0;
186 | }
187 | String h = (leftTimeInt/3600)+"";
188 | String m = (leftTimeInt%3600)/60+"";
189 | //LOG.info(h+"="+leftTimeInt+"/3600");
190 | //LOG.info(m+"="+(leftTimeInt%3600)+"/60");
191 | leftTime = h+"小时"+m+"分钟";
192 | }
193 | //LOG.info("leftTime:"+leftTime);
194 | return leftTime;
195 | }
196 |
197 | // date
198 | public static Date getDate(Long time) {
199 | if(time == null ) return null;
200 | return new Date(time);
201 |
202 | }
203 | public static Date getDate(Integer time) {
204 | if(time == null) return null;
205 |
206 | return new Date(1000L*time);
207 | }
208 | public static Date getDate( ) {
209 | return new Date();
210 | }
211 |
212 | public static Date getDate(String dateString,SimpleDateFormat format) {
213 | try {
214 | if(StringUtil.isEmpty(dateString)){
215 | dateString = getDateString(0);
216 |
217 | }
218 | Date d = format.parse(dateString);
219 | return d;
220 | } catch (ParseException e) {
221 | e.printStackTrace();
222 | return null;
223 | }
224 | }
225 |
226 | public static Date getDate(String dateString ) {
227 | return getDate( dateString, SDFYMDHM);
228 | }
229 |
230 |
231 | //获取当前年份1月1日0点0时0分
232 | public static final int getFirstDateOfYear(){
233 | return getFirstDateOfYear(getInt());
234 | }
235 | //获取当前年份12月31日24点24时24分 即 下一年的1月1日0点0时0分
236 | public static final int getLastDateOfYear(){
237 | return getLastDateOfYear(getInt());
238 | }
239 | //获取当前年份1月1日0点0时0分
240 | public static final int getFirstDateOfYear(Integer someday){
241 | Calendar calendar = Calendar.getInstance();
242 | calendar.setTime(new Date((long)(someday) * 1000));
243 | calendar.set(calendar.get(Calendar.YEAR), 0, 1,0,0,0);
244 | return (int)(( calendar.getTimeInMillis())/1000);
245 | }
246 |
247 | //获取前一年的1月1日0点0时0分
248 | public static final int getFirstDateOfPreviousYear(){
249 | return getFirstDateOfPreviousYear(getInt());
250 | }
251 |
252 | //获取前一年的1月1日0点0时0分
253 | public static final int getFirstDateOfPreviousYear(Integer someday){
254 | Calendar calendar = Calendar.getInstance();
255 |
256 | calendar.setTime(new Date( (long)(someday)* 1000));
257 | calendar.set(calendar.get(Calendar.YEAR)-1, 0, 1,0,0,0);
258 | return (int)(( calendar.getTimeInMillis())/1000);
259 | }
260 |
261 | //获取当前年份12月31日24点24时24分 即 下一年的1月1日0点0时0分
262 | public static final int getLastDateOfYear(Integer someday){
263 | Calendar calendar = Calendar.getInstance();
264 | calendar.setTime(new Date((long)(someday) * 1000));
265 | calendar.set(calendar.get(Calendar.YEAR)+1, 0, 1,0,0,0);
266 | return (int)(( calendar.getTimeInMillis())/1000);
267 | }
268 |
269 | public static final int getLastDateOfFirstSeason(){
270 | return getLastDateOfFirstSeason(getInt());
271 | }
272 | //获取当前年份第一季度结束时间
273 | public static final int getLastDateOfFirstSeason(Integer someday){
274 | Calendar calendar = Calendar.getInstance();
275 |
276 | calendar.setTime(new Date( (long)(someday)* 1000));
277 | calendar.set(calendar.get(Calendar.YEAR), 3, 1,0,0,0);
278 | return (int)(( calendar.getTimeInMillis())/1000);
279 | }
280 |
281 | /**
282 | *
283 | * 1 第一季度 2 第二季度 3 第三季度 4 第四季度
284 | *
285 | * @param someday
286 | * @return
287 | */
288 | public static int getSeason(Integer someday) {
289 |
290 | int season = 0;
291 |
292 | Calendar calendar = Calendar.getInstance();
293 | calendar.setTime(new Date((long)(someday) * 1000));
294 | int month = calendar.get(Calendar.MONTH);
295 | switch (month) {
296 | case Calendar.JANUARY:
297 | case Calendar.FEBRUARY:
298 | case Calendar.MARCH:
299 | season = 1;
300 | break;
301 | case Calendar.APRIL:
302 | case Calendar.MAY:
303 | case Calendar.JUNE:
304 | season = 2;
305 | break;
306 | case Calendar.JULY:
307 | case Calendar.AUGUST:
308 | case Calendar.SEPTEMBER:
309 | season = 3;
310 | break;
311 | case Calendar.OCTOBER:
312 | case Calendar.NOVEMBER:
313 | case Calendar.DECEMBER:
314 | season = 4;
315 | break;
316 | default:
317 | break;
318 | }
319 | return season;
320 | }
321 |
322 | /**
323 | *
324 | * 获得当前季度的第一天
325 | *
326 | * @param someday
327 | * @return
328 | */
329 | public static int getFirstDateOfSeason(Integer someday) {
330 | int m = 0;
331 |
332 | Calendar calendar = Calendar.getInstance();
333 | calendar.setTime(new Date((long)(someday) * 1000));
334 | int month = calendar.get(Calendar.MONTH);
335 | switch (month) {
336 | case Calendar.JANUARY:
337 | case Calendar.FEBRUARY:
338 | case Calendar.MARCH:
339 | m = 0;
340 | break;
341 | case Calendar.APRIL:
342 | case Calendar.MAY:
343 | case Calendar.JUNE:
344 | m = 3;
345 | break;
346 | case Calendar.JULY:
347 | case Calendar.AUGUST:
348 | case Calendar.SEPTEMBER:
349 | m = 6;
350 | break;
351 | case Calendar.OCTOBER:
352 | case Calendar.NOVEMBER:
353 | case Calendar.DECEMBER:
354 | m = 9;
355 | break;
356 | default:
357 | break;
358 | }
359 | calendar.set(calendar.get(Calendar.YEAR), m, 1,0,0,0);
360 | return (int)(( calendar.getTimeInMillis())/1000);
361 | }
362 |
363 | /**
364 | *
365 | * 获得当前季度的最后一天
366 | *
367 | * @param someday
368 | * @return
369 | */
370 | public static int getLastDateOfSeason(Integer someday) {
371 | int m = 0;
372 |
373 | Calendar calendar = Calendar.getInstance();
374 | calendar.setTime(new Date((long)(someday) * 1000));
375 | int month = calendar.get(Calendar.MONTH);
376 | switch (month) {
377 | case Calendar.JANUARY:
378 | case Calendar.FEBRUARY:
379 | case Calendar.MARCH:
380 | m = 3;
381 | break;
382 | case Calendar.APRIL:
383 | case Calendar.MAY:
384 | case Calendar.JUNE:
385 | m = 6;
386 | break;
387 | case Calendar.JULY:
388 | case Calendar.AUGUST:
389 | case Calendar.SEPTEMBER:
390 | m = 9;
391 | break;
392 | case Calendar.OCTOBER:
393 | case Calendar.NOVEMBER:
394 | case Calendar.DECEMBER:
395 | m = 0;
396 | break;
397 | default:
398 | break;
399 | }
400 | int year = calendar.get(Calendar.YEAR);
401 | //第四季度截止时间跨年问题
402 | if(m == 0) {
403 | year = year + 1;
404 | }
405 | calendar.set(year, m, 1,0,0,0);
406 | return (int)(( calendar.getTimeInMillis())/1000);
407 | }
408 |
409 | //获取当前月份的1日0时0分0秒
410 | public static final int getFirstDateOfThisMonth(){
411 | Calendar calendar = Calendar.getInstance();
412 | calendar.set(calendar.get(Calendar.YEAR),calendar.get(Calendar.MONTH),1,0,0,0);
413 | return (int)(( calendar.getTimeInMillis())/1000);
414 | }
415 | //获取某天所在月份的1日0时0分0秒
416 | public static final int getFirstDateOfMonthInSomeday(Integer someday){
417 | Calendar calendar = Calendar.getInstance();
418 | calendar.setTime(new Date((long)(someday) * 1000));
419 | calendar.set(calendar.get(Calendar.YEAR),calendar.get(Calendar.MONTH),1,0,0,0);
420 | return (int)(( calendar.getTimeInMillis())/1000);
421 | }
422 |
423 | /**
424 | * 同比, 获取上年同月的第一天
425 | * 比如传入的时间是2016年6月,则该方法得到2015年6月1日0时0分0秒
426 | * @param someday
427 | * @return
428 | */
429 | public static final int getFirstDateOfLastYear(Integer someday){
430 |
431 | Calendar calendar = Calendar.getInstance();
432 |
433 | calendar.setTime(new Date( (long)(someday)* 1000));
434 | calendar.set(calendar.get(Calendar.YEAR)-1, calendar.get(Calendar.MONTH), 1,0,0,0);
435 | return (int)(( calendar.getTimeInMillis())/1000);
436 | }
437 | /**
438 | * 同比,获取上年同月的最后一天
439 | * 比如传入的时间是2016年6月,则该方法得到2015年7月1日0时0分0秒(即6月末)
440 | * @param someday
441 | * @return
442 | */
443 | public static final int getLastDateOfLastYear(Integer someday){
444 |
445 | Calendar calendar = Calendar.getInstance();
446 |
447 | calendar.setTime(new Date( (long)(someday)* 1000));
448 | calendar.set(calendar.get(Calendar.YEAR)-1, calendar.get(Calendar.MONTH)+1, 1,0,0,0);
449 | return (int)(( calendar.getTimeInMillis())/1000);
450 | }
451 |
452 | //获取某天所在月份下个月的1日0时0分0秒
453 | public static final int getLastDateOfMonthInSomeday(Integer someday){
454 | Calendar calendar = Calendar.getInstance();
455 | calendar.setTime(new Date((long)(someday) * 1000));
456 | calendar.set(calendar.get(Calendar.YEAR),calendar.get(Calendar.MONTH) + 1,1,0,0,0);
457 | return (int)(( calendar.getTimeInMillis())/1000);
458 | }
459 |
460 | //获取当前月份的上一个月份的1日0时0分0秒
461 | public static final int getFirstDateOfLastMonth(){
462 | Calendar calendar = Calendar.getInstance();
463 | calendar.set(calendar.get(Calendar.YEAR),calendar.get(Calendar.MONTH) - 1,1,0,0,0);
464 | return (int)(( calendar.getTimeInMillis())/1000);
465 | }
466 |
467 | //获取某天所在月份的上一个月份的1日0时0分0秒
468 | public static final int getFirstDateOfLastMonth(Integer someday){
469 | Calendar calendar = Calendar.getInstance();
470 | calendar.setTime(new Date((long)(someday) * 1000));
471 | calendar.set(calendar.get(Calendar.YEAR),calendar.get(Calendar.MONTH) - 1,1,0,0,0);
472 | return (int)(( calendar.getTimeInMillis())/1000);
473 | }
474 |
475 | //获取当前月份的最后一天的24时24分24秒 即 下一个月的1日0时0分0秒
476 | public static final int getLastDateOfThisMonth(){
477 | Calendar calendar = Calendar.getInstance();
478 | calendar.set(calendar.get(Calendar.YEAR),calendar.get(Calendar.MONTH) + 1,1,0,0,0);
479 | return (int)(( calendar.getTimeInMillis())/1000);
480 | }
481 | //获取某天所在月份的下一个月的最后一天的23时59分59秒 即 下两个个月的1日0时0分0秒
482 | public static final int getLastDateOfNextMonthInSomeday(Integer someday){
483 | Calendar calendar = Calendar.getInstance();
484 | calendar.setTime(new Date((long)(someday) * 1000));
485 | calendar.set(calendar.get(Calendar.YEAR),calendar.get(Calendar.MONTH) + 2,1,0,0,0);
486 | return (int)(( calendar.getTimeInMillis())/1000);
487 | }
488 |
489 | //获取今年2月1日的0时0分0秒 用于推算其他月份的时间
490 | public static final int getFirstDateOfFeb(){
491 | Calendar calendar = Calendar.getInstance();
492 | calendar.set(calendar.get(Calendar.YEAR),1,1,0,0,0);
493 | return (int)(( calendar.getTimeInMillis())/1000);
494 | }
495 |
496 | //获取今年3月1日的0时0分0秒 用于推算其他月份的时间
497 | public static final int getFirstDateOfMar(){
498 | Calendar calendar = Calendar.getInstance();
499 | calendar.set(calendar.get(Calendar.YEAR),2,1,0,0,0);
500 | return (int)(( calendar.getTimeInMillis())/1000);
501 | }
502 |
503 | //获得本周一0点时间
504 | public static int getThisWeekMorning(){
505 | return getWeekMorningInSomeday(getInt());
506 | }
507 | //获取某天所在周的周一的0点
508 | public static final int getWeekMorningInSomeday(Integer someday){
509 | Calendar calendar = Calendar.getInstance();
510 | calendar.setTime(new Date((long)(someday) * 1000));
511 | calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DATE), 0, 0, 0);
512 | int day_of_week = calendar.get(Calendar.DAY_OF_WEEK) - 1;
513 | if (day_of_week == 0)
514 | day_of_week = 7;
515 | calendar.add(Calendar.DATE, -day_of_week + 1);
516 | return (int) (calendar.getTimeInMillis()/1000);
517 | }
518 |
519 | //获取某天所在周是周几, 0-6,代表周日到周六
520 | public static final int getWeekInSomeday(Integer someday){
521 | Calendar calendar = Calendar.getInstance();
522 | calendar.setTime(new Date((long)(someday) * 1000));
523 | Integer week = calendar.get(Calendar.DAY_OF_WEEK);
524 | return week-1;
525 | }
526 |
527 | //获取某个月有多少天
528 | public static final int getDaysOfSomeMonth(int someday){
529 | Date date = new Date((long)(someday) * 1000);
530 | Calendar calendar = new GregorianCalendar();
531 | calendar.setTime(date);
532 | return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
533 | }
534 | //获取某个月有多少周
535 | public static final int getWeeksOfSomeMonth(int someday){
536 | Date date = new Date((long)(someday) * 1000);
537 | Calendar calendar = new GregorianCalendar();
538 | calendar.setTime(date);
539 | return calendar.getActualMaximum(Calendar.WEEK_OF_MONTH);
540 | }
541 |
542 | /**
543 | * 获取当天是该月的第几周
544 | * @param someday
545 | * @return
546 | */
547 | public static final int getWeekOfMonth(int someday) {
548 | Calendar calendar = Calendar.getInstance();
549 | calendar.setTime(new Date((long)(someday) * 1000));
550 | return calendar.get(Calendar.WEEK_OF_MONTH);
551 | }
552 |
553 | /**
554 | * 获取当天是该年的第几周
555 | * @param someday
556 | * @return
557 | */
558 | public static final int getWeekOfYear(int someday) {
559 | Calendar calendar = Calendar.getInstance();
560 | calendar.setTime(new Date((long)(someday) * 1000));
561 | return calendar.get(Calendar.WEEK_OF_YEAR);
562 | }
563 |
564 | //获得两个时间点之间跨度几月 例如:2015-5-12 2015-5-15 return 0
565 | public static final int getMonthBetweenSomeday(int startTime,int endTime){
566 | Date startDate = new Date((long)(startTime) * 1000);
567 | Date endDate = new Date((long)(endTime) * 1000);
568 | int yearNum = endDate.getYear() - startDate.getYear();
569 | int monthNum = endDate.getMonth() - startDate.getMonth();
570 | return yearNum*12+monthNum;
571 | }
572 |
573 |
574 | //获得两个时间点之间跨度几季度 例如:2015-5-12 2015-5-15 return 0
575 | public static final int getSeasonBetweenSomeday(int startTime,int endTime){
576 | Date startDate = new Date((long)(startTime) * 1000);
577 | Date endDate = new Date((long)(endTime) * 1000);
578 | int yearNum = endDate.getYear() - startDate.getYear();
579 | int seasonNum = getSeason(endTime) - getSeason(startTime);
580 | return yearNum*4+seasonNum;
581 | }
582 |
583 | //获得两个时间点之间跨度几年 例如:2015-5-12 2015-5-15 return 0
584 | public static final int getYearBetweenSomeday(int startTime,int endTime){
585 | Date startDate = new Date((long)(startTime) * 1000);
586 | Date endDate = new Date((long)(endTime) * 1000);
587 | int yearNum = endDate.getYear() - startDate.getYear();
588 | return yearNum;
589 | }
590 |
591 | //获得两个时间点之间已满几个月
592 | public static final int getMonthNum(int startTime,int endTime){
593 | Date startDate = new Date((long)(startTime) * 1000);
594 | Date endDate = new Date((long)(endTime) * 1000);
595 | int yearNum = endDate.getYear() - startDate.getYear();
596 | int monthNum = endDate.getMonth() - startDate.getMonth();
597 | int dayNum = endDate.getDate() - startDate.getDate();
598 |
599 | int ret = 0;
600 | LOG.info("dayNum========="+dayNum);
601 | if(dayNum<0){
602 | ret = yearNum*12+monthNum-1;
603 | }else{
604 | ret = yearNum*12+monthNum;
605 | }
606 |
607 | return ret;
608 | }
609 |
610 | //日程
611 | /**
612 | * 返回年 如 2015
613 | * @param time
614 | * @return
615 | */
616 | public static String getYear(Integer time) {
617 | if (time == null) {
618 | return null;
619 | }
620 |
621 | return getString(time).substring(0, 4);
622 | }
623 | /**
624 | * 返回月 如 04
625 | * @param time
626 | * @return
627 | */
628 | public static String getMonth(Integer time) {
629 | if (time == null) {
630 | return null;
631 | }
632 |
633 | return getString(time).substring(5, 7);
634 | }
635 | /**
636 | * 返回日 如 14
637 | * @param time
638 | * @return
639 | */
640 | public static String getDay(Integer time) {
641 | if (time == null) {
642 | return null;
643 | }
644 |
645 | return getString(time).substring(8, 10);
646 | }
647 | /**
648 | * 返回 HH:mm
649 | * @param time
650 | * @return HH:mm
651 | */
652 | public static String getHour(Integer time) {
653 | if (time == null) {
654 | return null;
655 | }
656 |
657 | return getString(time).substring(11);
658 | }
659 |
660 | //start + l毫秒
661 | public static Date addDate(Date start,long l) {
662 |
663 | return new Date(start.getTime()+l);
664 |
665 | }
666 | /**
667 | * 获得一个前num个周一的日期数组,如:{"2015-4-26",...,"2015-3-15"}
668 | * @param num
669 | * @return
670 | */
671 | public static String[] getWeekArray(Integer num){
672 | String[] weekArray = new String[num];
673 | Integer weekInt = getThisWeekMorning();
674 |
675 | for(int i = 0;i < num;i++){
676 | Integer week = weekInt - 86400*7*i;
677 | weekArray[i] = getDateString(week);
678 | }
679 | return weekArray;
680 | }
681 | /**
682 | * 获得前num个月的1月1号,如:{"2015-4-1",......,"2014-1-1"}
683 | * @param num
684 | * @return
685 | */
686 | public static String[] getMonthArray(Integer num){
687 | String[] monthArray = new String[num];
688 | int now = getInt();
689 | for(int i = 0;i < num;i++){
690 | now = getFirstDateOfLastMonth(now);
691 | monthArray[i] = getDateString(now);
692 | }
693 | return monthArray;
694 | }
695 | /**
696 | * 获得前num年,如:{"2015",...,"2010"}
697 | * @param num
698 | * @return
699 | */
700 | public static String[] getYearArray(Integer num){
701 | String[] yearArray = new String[num];
702 | Integer now = getInt();
703 | for(int i = 0;i < num;i++){
704 | now = getFirstDateOfPreviousYear(now);
705 | yearArray[i] = getString(now,SDFYears);
706 | LOG.info("now:"+getString(now));
707 | }
708 | return yearArray;
709 | }
710 |
711 | /**
712 | * 计算两个时间 相差天数
713 | * @param beforeDay
714 | * @param lastDay
715 | * @return
716 | */
717 | public static int betweenDays(int beforeDay, int lastDay) {
718 | int day = (lastDay - beforeDay) / (24 * 3600);
719 | /**----不返回小时数了----------*/
720 | // if (day == 0) {//小于一天的 按照小时
721 | // Calendar calendarB = Calendar.getInstance();
722 | // calendarB.setTime(getDate(beforeDay));
723 | // int hourB = calendarB.get(Calendar.HOUR_OF_DAY);
724 | // int dayB = calendarB.get(Calendar.DAY_OF_MONTH);
725 | //
726 | // Calendar calendarL = Calendar.getInstance();
727 | // calendarL.setTime(getDate(lastDay));
728 | // int dayL = calendarL.get(Calendar.DAY_OF_MONTH);
729 | // int hourL = calendarL.get(Calendar.HOUR_OF_DAY);
730 | //
731 | //// day = dayL - dayB;
732 | // day = hourL - hourB;
733 | // }
734 | return day;
735 | }
736 |
737 | /**
738 | *
739 | * @param lastConnectTime
740 | * @param now
741 | * @return
742 | */
743 | public static int lastConnect(int lastConnectTime, int now) {
744 | int day = (now - lastConnectTime) / (24 * 3600);
745 |
746 | if (day == 0 && lastConnectTime < getTodayInt(now)) {
747 | return 1;
748 | }
749 | return day;
750 | }
751 |
752 | //获取某时间点的这一年的第month个月的月初
753 | public static final int getFirstDateOfMonth(Integer someday,int month){
754 | Calendar calendar = Calendar.getInstance();
755 | calendar.setTime(new Date((long)(someday) * 1000));
756 | calendar.set(calendar.get(Calendar.YEAR), month-1, 1,0,0,0);
757 | return (int)(( calendar.getTimeInMillis())/1000);
758 | }
759 | //获取某时间点的这一年的第month个月的月末
760 | public static final int getEndDateOfMonth(Integer someday,int month){
761 | Calendar calendar = Calendar.getInstance();
762 | calendar.setTime(new Date((long)(someday) * 1000));
763 | calendar.set(calendar.get(Calendar.YEAR), month, 1,0,0,0);
764 | return (int)(( calendar.getTimeInMillis())/1000);
765 | }
766 | /**
767 | * 获取excel里的时间格式,一般是1900年以来的天数 ,50000以内
768 | * @param date
769 | * @return
770 | */
771 | public static Integer getExcelTime(String date){//获取excel中的格式各样的时间格式,统一格式解析
772 | Integer result=0;
773 | if(StringUtil.isEmpty(date)){
774 | return 0;
775 | }
776 | Integer dateInt= StringUtil.toInt(date);
777 | if(dateInt!=null && dateInt<50000)
778 | {
779 | result=(dateInt-25569)*86400-28800;
780 | if(dateInt==0){
781 | result=0;
782 | }
783 |
784 |
785 | }
786 | else{
787 | //excel中时间不是数字
788 | if(date.contains(".")){
789 | //2015.09.01格式
790 | date=date.replace(".", "-");
791 | }
792 | if(date.contains("/")){
793 | //2015/09/01格式
794 | date=date.replace("/", "-");
795 | }
796 | if(date.length()==8){
797 | //20150901格式
798 | date=date.substring(0,4)+"-"+date.substring(4, 6)+"-"+date.substring(6, 8);
799 | }
800 | if(date.contains("-")){
801 | try{
802 | result= DateUtil.getInt(date, DateUtil.SDFDate);
803 | }catch(Exception e){
804 | e.printStackTrace();
805 | result=0;
806 | }
807 |
808 | }
809 | }
810 | return result;
811 | }
812 |
813 | /**
814 | * 获取某个时间的半年开始时间
815 | * 比如,someday在前6个月,则该方法得到someday所在年的1月1日0点
816 | * someday在后6个月,则该方法得到someday所在年的6月1日0点
817 | * @param someday
818 | * @return
819 | * @author chuanpeng.zhang
820 | * @time 2016-8-4 上午10:59:20
821 | */
822 | public static int getHalfYearStartTime(Integer someday) {
823 | Calendar calendar = Calendar.getInstance();
824 | calendar.setTime(new Date((long)(someday) * 1000));
825 | int someMonth = calendar.get(Calendar.MONTH) + 1;
826 |
827 | Integer startTime = null;
828 | if (someMonth >= 1 && someMonth <= 6){
829 | startTime = getFirstDateOfMonth(someday, 1);
830 | }else if (someMonth >= 7 && someMonth <= 12){
831 | startTime = getFirstDateOfMonth(someday, 7);
832 | }
833 |
834 | return startTime;
835 | }
836 | /**
837 | * 获取某个时间的半年结束时间
838 | * 比如,someday在前6个月,则该方法得到someday所在年的6月30日24点--即7月1日0点
839 | * someday在后6个月,则该方法得到someday所在年的12月31日24点--即下年的1月1日0点
840 | * @param someday
841 | * @return
842 | * @author chuanpeng.zhang
843 | * @time 2016-8-4 上午11:01:01
844 | */
845 | public static int getHalfYearEndTime(Integer someday) {
846 | Calendar calendar = Calendar.getInstance();
847 | calendar.setTime(new Date((long)(someday) * 1000));
848 | int someMonth = calendar.get(Calendar.MONTH) + 1;
849 |
850 | Integer endTime = null;
851 | if (someMonth >= 1 && someMonth <= 6){
852 | endTime = getEndDateOfMonth(someday, 6);
853 | }else if (someMonth >= 7 && someMonth <= 12){
854 | endTime = getEndDateOfMonth(someday, 12);
855 | }
856 |
857 | return endTime;
858 | }
859 |
860 | public static void main(String[]args){
861 |
862 | DateUtil.getDate( null , DateUtil.SDF);
863 |
864 | Integer weekCount = getWeeksOfSomeMonth(DateUtil.getInt());
865 |
866 | LOG.info(getWeekOfMonth(getInt()));
867 | LOG.info(getFirstDateOfSeason(getInt()));
868 | LOG.info(getLastDateOfSeason(1475251200));
869 | LOG.info(getSeason(getInt()));
870 | LOG.info(getLastDateOfThisMonth());
871 | LOG.info(getLastDateOfMonthInSomeday(1475251200));
872 |
873 | LOG.info(getFirstDateOfLastMonth());
874 | LOG.info(getFirstDateOfThisMonth());
875 | LOG.info(getLastDateOfThisMonth());
876 |
877 |
878 | Integer someday = getInt("2015-1-1", SDFDate);
879 | LOG.info(getFirstDateOfLastYear(someday));
880 | LOG.info(getLastDateOfLastYear(someday));
881 |
882 | LOG.info(getYear(getFirstDateOfLastYear(someday)).substring(2));
883 |
884 | LOG.info("---getHalfYearStartTime:"+ getHalfYearStartTime(someday));
885 | LOG.info("---getHalfYearEndTime:"+ getHalfYearEndTime(someday));
886 |
887 | LOG.info("getLastDateOfFirstSeason:"+ getLastDateOfFirstSeason(someday));
888 |
889 | LOG.info(lastConnect(1488330000, getInt()));
890 | }
891 | }
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/util/ExceptionHandlerAdvice.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.util;
2 |
3 | import org.springframework.ui.Model;
4 | import org.springframework.web.bind.WebDataBinder;
5 | import org.springframework.web.bind.annotation.ControllerAdvice;
6 | import org.springframework.web.bind.annotation.ExceptionHandler;
7 | import org.springframework.web.bind.annotation.InitBinder;
8 | import org.springframework.web.bind.annotation.ModelAttribute;
9 | import org.springframework.web.context.request.WebRequest;
10 | import org.springframework.web.servlet.ModelAndView;
11 |
12 | /**
13 | * User: Gavin
14 | * E-mail: GavinChangCN@163.com
15 | * Desc:
16 | * Date: 2017-03-27
17 | * Time: 14:57
18 | */
19 | @ControllerAdvice
20 | public class ExceptionHandlerAdvice {
21 | protected static final String TAG = "ExceptionHandlerAdvice";
22 |
23 | @ExceptionHandler(value = Exception.class)
24 | public ModelAndView exception(Exception exception, WebRequest request) {
25 | ModelAndView modelAndView = new ModelAndView("error");
26 | modelAndView.addObject("errorMessage", exception.getMessage());
27 | return modelAndView;
28 | }
29 |
30 | @ModelAttribute
31 | public void addAttributes(Model model) {
32 | model.addAttribute("msg", "额外信息");
33 | }
34 |
35 | @InitBinder
36 | public void initBinder(WebDataBinder webDataBinder) {
37 | // webDataBinder.setDisallowedFields("id"); // 过滤当前字段的 Key
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/util/ExceptionUtil.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.util;
2 |
3 | /**
4 | * User: Gavin
5 | * E-mail: GavinChangCN@163.com
6 | * Desc:
7 | * Date: 2017-03-23
8 | * Time: 14:05
9 | */
10 | public class ExceptionUtil {
11 | protected static final String TAG = "ExceptionUtil";
12 |
13 | public static String getStackMsg(Exception e) {
14 | StringBuffer sb = new StringBuffer();
15 | StackTraceElement[] stackArray = e.getStackTrace();
16 | for (StackTraceElement element : stackArray) {
17 | sb.append(element.toString()).append("\n");
18 | }
19 | return sb.toString();
20 | }
21 |
22 | public static String getStackMsg(Throwable e) {
23 |
24 | StringBuffer sb = new StringBuffer();
25 | StackTraceElement[] stackArray = e.getStackTrace();
26 | for (StackTraceElement element : stackArray) {
27 | sb.append(element.toString()).append("\n");
28 | }
29 | return sb.toString();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/util/FIFOQueen.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.util;
2 |
3 | /**
4 | * User: Gavin
5 | * E-mail: GavinChangCN@163.com
6 | * Desc: 先进先出队列
7 | * Date: 2017-03-07
8 | * Time: 09:57
9 | */
10 | public class FIFOQueen {
11 | protected static final String TAG = "FIFOQueen";
12 | /**
13 | * 队列第一个元素
14 | */
15 | private Node first;
16 | /**
17 | * 队列最后元素
18 | */
19 | private Node last;
20 | /**
21 | * 队列大小
22 | */
23 | private int size = 0;
24 |
25 | /**
26 | * 队列结构
27 | */
28 | private class Node {
29 | T item;
30 | Node next;
31 | }
32 |
33 | /**
34 | * 队列是否为空
35 | *
36 | * @return
37 | */
38 | public boolean isEmpty() {
39 | return size == 0;
40 | }
41 |
42 | /**
43 | * 将元素压入队列尾部
44 | *
45 | * @param item
46 | */
47 | public void push(T item) {
48 | if (size == 0) {
49 | first = new Node();
50 | first.item = item;
51 | last = first;
52 | size++;
53 | } else if (size > 0) {
54 | Node newLast = new Node();
55 | newLast.item = item;
56 | last.next = newLast;
57 | last = newLast;
58 | size++;
59 | }
60 | }
61 |
62 | /**
63 | * 取出队列的第一个元素
64 | *
65 | * @return
66 | */
67 | public T pop() {
68 | if (size == 0) {
69 | throw new ArrayIndexOutOfBoundsException();
70 | }
71 | Node oldFirst = first;
72 | first = first.next;
73 | size--;
74 | return oldFirst.item;
75 | }
76 |
77 | /**
78 | * 取队列深度
79 | *
80 | * @return
81 | */
82 | public int size() {
83 | return size;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/com/xbongbong/util/StringUtil.java:
--------------------------------------------------------------------------------
1 | package com.xbongbong.util;
2 |
3 |
4 | import org.apache.logging.log4j.LogManager;
5 | import org.apache.logging.log4j.Logger;
6 |
7 | import java.io.UnsupportedEncodingException;
8 | import java.math.BigDecimal;
9 | import java.net.InetAddress;
10 | import java.net.URLDecoder;
11 | import java.net.UnknownHostException;
12 | import java.text.DecimalFormat;
13 | import java.util.*;
14 | import java.util.regex.Matcher;
15 | import java.util.regex.Pattern;
16 |
17 | public final class StringUtil {
18 | private static String[] units = { "", "十", "百", "千", "万", "十万", "百万", "千万", "亿", "十亿", "百亿", "千亿", "万亿" };
19 | private static char[] numArray = {' ','一', '二', '三', '四', '五', '六', '七', '八', '九' };
20 | private static final Logger LOG = LogManager.getLogger(StringUtil.class);
21 | private static long sequenceId = System.currentTimeMillis();
22 | private static String addrIp;
23 | private static final String regEx_html = "<[^>]+>";//定义HTML标签的正则表达式
24 | private static final String regEx_script = "
88 |
89 |