├── .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 = "]*?>[\\s\\S]*?<\\/script>"; // 定义script的正则表达式 25 | private static final String regEx_style = "]*?>[\\s\\S]*?<\\/style>"; // 定义style的正则表达式 26 | private static char[] chars = { '0', '1', '2', '3', '4', '5', '6', '7', 27 | '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 28 | 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 29 | 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 30 | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 31 | 'Y', 'Z', '!', '@', '#', '$', '%', '^', '&', '*', '~', '|' }; // 72个字符集 32 | 33 | /** 34 | * 获得随机密码数组 35 | * 36 | * @param type 37 | * 随机密码类型 type=1, 数字; type=2, 非数字; type=3, 所有字符, type=4 数字和英文小写字母 38 | * @param passLength 39 | * 随机密码长度 40 | * @param count 41 | * 随机密码个数 42 | * @return 随机密码数组 43 | */ 44 | public static String[] getRandomPasswords(int type, int passLength, 45 | int count) { 46 | String[] passwords = new String[count];// 新建一个长度为指定需要密码个数的字符串数组 47 | Random random = new Random(); 48 | if (type == 1) { 49 | for (int i = 0; i < count; i++) {// 外循环 从0开始为密码数组赋值 也就是开始一个一个的生成密码 50 | StringBuilder password = new StringBuilder("");// 保存生成密码的变量 51 | for (int m = 1; m <= passLength; m++) {// 内循环 从1开始到密码长度 正式开始生成密码 52 | password.append(chars[random.nextInt(10)]);// 为密码变量随机增加上面字符中的一个 53 | } 54 | passwords[i] = password.toString();// 将生成出来的密码赋值给密码数组 55 | } 56 | } else if (type == 2) { 57 | for (int i = 0; i < count; i++) {// 外循环 从0开始为密码数组赋值 也就是开始一个一个的生成密码 58 | StringBuilder password = new StringBuilder("");// 保存生成密码的变量 59 | for (int m = 1; m <= passLength; m++) {// 内循环 从1开始到密码长度 正式开始生成密码 60 | password.append(chars[random.nextInt(53) + 10]);// 为密码变量随机增加上面字符中的一个 61 | } 62 | passwords[i] = password.toString();// 将生成出来的密码赋值给密码数组 63 | } 64 | } else if (type == 3) { 65 | for (int i = 0; i < count; i++) {// 外循环 从0开始为密码数组赋值 也就是开始一个一个的生成密码 66 | StringBuilder password = new StringBuilder("");// 保存生成密码的变量 67 | for (int m = 1; m <= passLength; m++) {// 内循环 从1开始到密码长度 正式开始生成密码 68 | password.append(chars[random.nextInt(72)]);// 为密码变量随机增加上面字符中的一个 69 | } 70 | passwords[i] = password.toString();// 将生成出来的密码赋值给密码数组 71 | } 72 | } else if (type == 4) { 73 | for (int i = 0; i < count; i++) {// 外循环 从0开始为密码数组赋值 也就是开始一个一个的生成密码 74 | StringBuilder password = new StringBuilder("");// 保存生成密码的变量 75 | for (int m = 1; m <= passLength; m++) {// 内循环 从1开始到密码长度 正式开始生成密码 76 | password.append(chars[random.nextInt(36)]);// 为密码变量随机增加上面字符中的一个 77 | } 78 | passwords[i] = password.toString();// 将生成出来的密码赋值给密码数组 79 | } 80 | } else { 81 | LOG.error("type参数输入错误!"); 82 | LOG.info("type参数输入错误!"); 83 | } 84 | return passwords; 85 | } 86 | 87 | /** 88 | * 获得单个随机密码 89 | * 90 | * @param type 91 | * 随机密码类型 type=1, 数字; type=2, 非数字; type=3, 所有字符; type=4, 92 | * 数字和英文小写字母 93 | * @param passLength 94 | * 随机密码长度 95 | * @return 随机密码 96 | * 97 | */ 98 | public static String getRandomPassword(int type, int passLength) { 99 | return getRandomPasswords(type, passLength, 1)[0]; 100 | } 101 | 102 | /** 103 | * 获得单个随机密码 104 | * 105 | * @param passLength 106 | * 随机密码长度 107 | * @return 随机密码 108 | */ 109 | public static String getRandomPassword(int passLength) { 110 | return getRandomPassword(3, passLength); 111 | } 112 | 113 | public static synchronized String getNextId() { 114 | sequenceId++; 115 | if (addrIp == null) { 116 | try { 117 | InetAddress addr = InetAddress.getLocalHost(); 118 | addrIp = addr.getHostAddress().toString().replace(".", ""); 119 | 120 | } catch (UnknownHostException e) { 121 | // TODO Auto-generated catch block 122 | e.printStackTrace(); 123 | addrIp = ((Double) Math.random()).toString().substring(2, 14); 124 | } 125 | } 126 | LOG.info("sequenceId=" + addrIp + sequenceId); 127 | return "ID" + addrIp + sequenceId; 128 | } 129 | 130 | /* 将list转为以split分割的字符串,首尾都包含分割符,比如:|a|b|c|d| */ 131 | public static String listToString(List list, String split) { 132 | if (list == null || list.size()==0) { 133 | return null; 134 | } 135 | StringBuffer buf = new StringBuffer(); 136 | buf.append(split); 137 | for (T t : list) { 138 | buf.append(t.toString()); 139 | buf.append(split); 140 | } 141 | return buf.toString(); 142 | } 143 | 144 | public static String getUtf8(String str) { 145 | return getUtf8(str, null); 146 | } 147 | 148 | public static String getUtf8(String str, String encoding) { 149 | if (isEmpty(str)) { 150 | return null; 151 | } 152 | String retStr = null; 153 | try { 154 | if(!StringUtil.isEmpty(encoding)){ 155 | retStr= new String(str.getBytes(encoding), "UTF-8"); 156 | return retStr; 157 | } 158 | 159 | if(new String(str.getBytes("ISO-8859-1"),"ISO-8859-1").equals(str)){ 160 | LOG.info("===========ISO-8859-1"); 161 | 162 | retStr = new String(str.getBytes("ISO-8859-1"), "UTF-8"); 163 | 164 | }else if(new String(str.getBytes("UTF-8"),"UTF-8").equals(str)){ 165 | LOG.info("UTF-8"); 166 | retStr = str; 167 | }else if(new String(str.getBytes("GBK"),"GBK").equals(str)){ 168 | LOG.info("GBK"); 169 | retStr = new String(str.getBytes("GBK"), "UTF-8"); 170 | 171 | }else if(new String(str.getBytes("GB2312"),"GB2312").equals(str)){ 172 | LOG.info("GB2312"); 173 | retStr = new String(str.getBytes("GB2312"), "UTF-8"); 174 | } 175 | } catch (UnsupportedEncodingException e) { 176 | // TODO Auto-generated catch block 177 | e.printStackTrace(); 178 | return null; 179 | } 180 | return retStr; 181 | } 182 | 183 | /** 184 | * 185 | * @param str 186 | * @param len 187 | * @return 取str的最多len位,若str的长度小于len,返回全部 188 | */ 189 | public static String getSummary(String str, Integer len) { 190 | if (str == null || str.length() <= len) { 191 | return str; 192 | } 193 | return str.substring(0, len - 3) + "..."; 194 | } 195 | 196 | public static String getSummary(String str, Integer len,String fix) { 197 | if (str == null || str.length() <= len) { 198 | return str; 199 | } 200 | 201 | return str.substring(0, len - fix.length()) + fix; 202 | 203 | } 204 | 205 | /* 将array转为以split分割的字符串,首尾都包含分割符,比如:|a|b|c|d| */ 206 | public static String arrayToString(T[] array, String split) { 207 | if(array == null ) return ""; 208 | StringBuffer buf = new StringBuffer(); 209 | buf.append(split); 210 | for (T t : array) { 211 | buf.append(t.toString()); 212 | buf.append(split); 213 | } 214 | return buf.toString(); 215 | } 216 | /** 217 | * 将roleIds转为以List 218 | * @param roleIds 格式为|1|2|3|4| 219 | * @return 220 | */ 221 | public static List roleIdToList(String roleIds) { 222 | if (isEmpty(roleIds)) { 223 | return null; 224 | } 225 | 226 | String roleIdArr [] = roleIds.substring(1, roleIds.length() - 1).split("\\|"); 227 | //获取不重复的roleId ID列表 228 | Set roleIdsSet = new LinkedHashSet();//按顺序 229 | for (String roleIdStr : roleIdArr) { 230 | roleIdsSet.add(roleIdStr); 231 | } 232 | 233 | List roleIdList = new ArrayList(roleIdsSet); 234 | 235 | return roleIdList; 236 | } 237 | 238 | /** 239 | * 将roleIds转为以List 240 | * @param roleIds 格式为|1|2|3|4| 241 | * @return 242 | */ 243 | public static List roleIdToListInt(String roleIds) { 244 | if (isEmpty(roleIds)) { 245 | return null; 246 | } 247 | 248 | String roleIdArr [] = roleIds.substring(1, roleIds.length() - 1).split("\\|"); 249 | 250 | //获取不重复的roleId ID列表 251 | Set roleIdsSet = new LinkedHashSet();//按顺序 252 | for (String roleIdStr : roleIdArr) { 253 | roleIdsSet.add(Integer.valueOf(roleIdStr)); 254 | } 255 | 256 | List roleIdList = new ArrayList(roleIdsSet); 257 | 258 | return roleIdList; 259 | } 260 | 261 | 262 | public static Double toDouble(String str ){ 263 | return toDouble(str,0d); 264 | } 265 | public static Double toDouble(String str,Double defaultValue ){ 266 | if (StringUtil.isEmpty(str)) 267 | return defaultValue; 268 | 269 | try { 270 | return Double.valueOf(str.trim()); 271 | } catch (Exception e) { 272 | // e.printStackTrace(); 273 | LOG.warn("todefaultValue canot deal with arg:[" + str 274 | + "] ,and will renturn defaultValue " + defaultValue); 275 | return defaultValue; 276 | } 277 | } 278 | 279 | public static Float toFloat(String str ){ 280 | return toFloat(str,0f); 281 | } 282 | public static Float toFloat(String str,Float defaultValue ){ 283 | if (StringUtil.isEmpty(str)) 284 | return defaultValue; 285 | 286 | try { 287 | return Float.valueOf(str.trim()); 288 | } catch (Exception e) { 289 | // e.printStackTrace(); 290 | LOG.warn("todefaultValue canot deal with arg:[" + str 291 | + "] ,and will renturn defaultValue " + defaultValue); 292 | return defaultValue; 293 | } 294 | } 295 | 296 | 297 | public static String getSexStr(Integer sex ){ 298 | if(sex == null || sex ==0){ 299 | return "未知"; 300 | }else if(sex == 1 ){ 301 | return "男"; 302 | }else if(sex == 2 ){ 303 | return "女"; 304 | }else { 305 | return "其他"; 306 | } 307 | } 308 | 309 | 310 | /* 将字符串转为Integer,作空指针和首尾空检查,如果异常,返回缺省值defaultValue */ 311 | public static Integer toInt(String str, Integer defaultValue){ 312 | return StringToInteger( str, defaultValue); 313 | } 314 | public static Integer toInt(String str ){ 315 | return StringToInteger( str, null); 316 | } 317 | public static Integer StringToInteger(String str) { 318 | return StringToInteger(str, null); 319 | } 320 | 321 | public static Integer StringToInteger(String str, Integer defaultValue) { 322 | if (StringUtil.isEmpty(str)) 323 | return defaultValue; 324 | 325 | try { 326 | return Integer.valueOf(str.trim()); 327 | } catch (Exception e) { 328 | LOG.warn("StringToInteger canot deal with arg:[" + str 329 | + "] ,and will renturn defaultValue " + defaultValue); 330 | return defaultValue; 331 | } 332 | 333 | } 334 | 335 | 336 | /** 337 | * 将字符串转为Integer,作空指针和首尾空检查,如果异常,返回缺省值defaultValue 338 | * @param str 339 | * @param defaultValue 340 | * @return 341 | */ 342 | public static Long StringToLong(String str, Long defaultValue) { 343 | if (StringUtil.isEmpty(str)) 344 | return defaultValue; 345 | 346 | try { 347 | return Long.valueOf(str.trim()); 348 | } catch (Exception e) { 349 | // e.printStackTrace(); 350 | LOG.warn("StringToInteger canot deal with arg:[" + str 351 | + "] ,and will renturn defaultValue " + defaultValue); 352 | return defaultValue; 353 | } 354 | } 355 | 356 | public static Long StringToLong(String str) { 357 | return StringToLong(str, null); 358 | } 359 | 360 | public static boolean isEmpty(String value, boolean trim, char... trimChars) { 361 | if (trim) 362 | return value == null || trim(value, trimChars).length() <= 0; 363 | return value == null || value.length() <= 0; 364 | } 365 | 366 | public static boolean isEmpty(String value, boolean trim) { 367 | return isEmpty(value, trim, ' '); 368 | } 369 | 370 | public static boolean isEmpty(String value) { 371 | return isEmpty(value, true); 372 | } 373 | 374 | public static String nullSafeString(String value) { 375 | return value == null ? "" : value; 376 | } 377 | 378 | public static String trim(String value) { 379 | value = trim(3, value, ' ');//英文 380 | value = trim(3, value, ' ');//中文全角空格 381 | return value; 382 | } 383 | 384 | public static String trim(String value, char... chars) { 385 | return trim(3, value, chars); 386 | } 387 | 388 | public static String trimStart(String value, char... chars) { 389 | return trim(1, value, chars); 390 | } 391 | 392 | public static String trimEnd(String value, char... chars) { 393 | return trim(2, value, chars); 394 | } 395 | 396 | private static String trim(int mode, String value, char... chars) { 397 | if (value == null || value.length() <= 0) 398 | return value; 399 | value = value.trim(); 400 | int startIndex = 0, endIndex = value.length(), index = 0; 401 | if (mode == 1 || mode == 3) { 402 | // trim头部 403 | while (index < endIndex) { 404 | if (contains(chars, value.charAt(index++))) { 405 | startIndex++; 406 | continue; 407 | } 408 | break; 409 | } 410 | } 411 | 412 | if (startIndex >= endIndex) 413 | return ""; 414 | 415 | if (mode == 2 || mode == 3) { 416 | // trim尾部 417 | index = endIndex - 1; 418 | while (index >= 0) { 419 | if (contains(chars, value.charAt(index--))) { 420 | endIndex--; 421 | continue; 422 | } 423 | break; 424 | } 425 | } 426 | 427 | if (startIndex >= endIndex) 428 | return ""; 429 | 430 | return value.substring(startIndex, endIndex); 431 | } 432 | 433 | private static boolean contains(char[] chars, char chr) { 434 | if (chars == null || chars.length <= 0) 435 | return false; 436 | for (int i = 0; i < chars.length; i++) { 437 | if (chars[i] == chr) 438 | return true; 439 | } 440 | return false; 441 | } 442 | 443 | public static String URLDecode(String str) { 444 | if (str == null) 445 | return ""; 446 | try { 447 | return URLDecoder.decode(str, "UTF-8"); 448 | } catch (UnsupportedEncodingException e) { 449 | // TODO Auto-generated catch block 450 | e.printStackTrace(); 451 | LOG.warn("URLDecode UnsupportedEncodingException" + str); 452 | return str; 453 | } catch (Exception e) { 454 | e.printStackTrace(); 455 | LOG.warn("URLDecode Exception" + str); 456 | return str; 457 | } 458 | } 459 | 460 | /** 461 | * 判断输入的字符串是否为自然数 462 | * 463 | * @param str 464 | * @return 465 | */ 466 | public static boolean isNumeric(String str) { 467 | 468 | if(str == null || "".equals(str)) { 469 | return false; 470 | } 471 | 472 | Pattern pattern = Pattern.compile("^0$|(^(\\+)?[1-9]([0-9]*))"); 473 | Matcher isNum = pattern.matcher(str); 474 | if (!isNum.matches()) { 475 | return false; 476 | } 477 | return true; 478 | } 479 | 480 | 481 | /** 482 | * 验证所有电话格式 总结起来就是第一位必定为1,第二位必定为3或4或5或7或8,6,9,其他位置的可以为0-9, 区号为86可不填 483 | */ 484 | public static boolean isMobile(String mobiles) { 485 | /* 486 | 移动:134、135、136、137、138、139、150、151、157(TD)、158、159、187、188 487 | 联通:130、131、132、152、155、156、185、186 488 | 电信:133、153、180、189、(1349卫通) 489 | 网络电话: 17 490 | 总结起来就是第一位必定为1,第二位必定为3或5或7或8,其他位置的可以为0-9, 区号为86可不填 491 | 492 | 香港号码:区号为00852或852 香港手机号码是5/6/9开头的8位数字的号码,座机是2/3开头的8位数的号码 493 | 494 | 台湾号码:区号为00886或886 台湾手机10位数,皆以09起头,拨打台湾手机,先拨台湾的国际区码00886,接着拨去起头0的手机号码,譬如0960XXXXXX,则拨00886-960XXXXXX 495 | */ 496 | String telRegex = "(^(86)?[1][3456789]\\d{9}$)|(^(00852|852)?[569]\\d{7}$)|(^(00886|886)?0?[9]\\d{8}$)";//"[1]"代表第1位为数字1,"[358]"代表第二位可以为3、5、7、8中的一个,"\\d{9}"代表后面是可以是0~9的数字,有9位。 497 | if (isEmpty(mobiles)) return false; 498 | else return mobiles.matches(telRegex); 499 | } 500 | 501 | /** 502 | * 验证手机号格式 type为"china" 503 | */ 504 | public static boolean isMobile(String mobiles,String type) { 505 | /* 506 | 移动:134、135、136、137、138、139、150、151、157(TD)、158、159、187、188 507 | 联通:130、131、132、152、155、156、185、186 508 | 电信:133、153、180、189、(1349卫通) 509 | */ 510 | String telRegex = ""; 511 | if("china".equals(type)){ 512 | telRegex = "(^(86)?[1][3578]\\d{9}$)"; 513 | } 514 | 515 | if (isEmpty(mobiles)) return false; 516 | else return mobiles.matches(telRegex); 517 | } 518 | 519 | /** 520 | * 验证手机格式 521 | */ 522 | public static boolean isPhone(String phone) { 523 | 524 | String telRegex = "^(\\d+[-]?\\d+)+$";//"[1]"代表第1位为数字1,"[358]"代表第二位可以为3、5、7、8中的一个,"\\d{9}"代表后面是可以是0~9的数字,有9位。 525 | if (isEmpty(phone)) return false; 526 | else return phone.matches(telRegex); 527 | } 528 | 529 | public static boolean isEmail(String str){ 530 | if(str == null || "".equals(str)) { 531 | return false; 532 | } 533 | String regExp = "[\\w\\.\\-]+@([\\w\\-]+\\.)+[\\w\\-]+"; 534 | return str.matches(regExp); 535 | } 536 | 537 | public static boolean isIdcard(String str){ 538 | if(str == null || "".equals(str)) { 539 | return false; 540 | } 541 | String regExp15="^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$"; 542 | String regExp18 = "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$"; 543 | 544 | //定义判别用户身份证号的正则表达式(要么是15位,要么是18位,最后一位可以为字母) 545 | Matcher idNumMatcher=null; 546 | if(str.length()==15){ 547 | Pattern idNumPattern = Pattern.compile(regExp15); 548 | idNumMatcher = idNumPattern.matcher(str); 549 | }else{ 550 | Pattern idNumPattern = Pattern.compile(regExp18); 551 | idNumMatcher = idNumPattern.matcher(str); 552 | } 553 | 554 | 555 | return idNumMatcher.matches(); 556 | } 557 | 558 | public static String ifEmptyThenDefault(String str, String defaultStr) { 559 | if(isEmpty(str)) { 560 | return defaultStr; 561 | } 562 | return str; 563 | } 564 | 565 | /** 566 | * 输出内容保留空格,换行等 567 | * @param content 568 | * @return 569 | */ 570 | public static String outHtml(String content) { 571 | if (isEmpty(content)) { 572 | return ""; 573 | } 574 | 575 | content = ((content.replaceAll("<(.+?)>","<$1>")).replaceAll(" "," ")).replaceAll("\n","
"); 576 | 577 | return content; 578 | } 579 | 580 | 581 | /** 582 | * 过滤sql 注入的语法 , = ' 583 | * @param content 584 | * @return 585 | */ 586 | public static String filterSql(String content) { 587 | if (isEmpty(content)) { 588 | return ""; 589 | } 590 | 591 | content = content.replaceAll("'","").replaceAll(",","").replaceAll("=",""); 592 | 593 | return content; 594 | } 595 | 596 | /** 597 | * 隐藏手机号中间4位 598 | * @param phone 599 | * @return 600 | */ 601 | public static String phoneHideMid(String phone) { 602 | if (isEmpty(phone)) { 603 | return ""; 604 | } 605 | char[] temp = phone.toCharArray(); 606 | String ret = ""; 607 | for (int i = 0; i < temp.length; ++i) { 608 | if (i==3 || i==4 || i==5 || i==6) { 609 | temp[i] = '*'; 610 | } 611 | ret += temp[i]; 612 | } 613 | 614 | return ret; 615 | } 616 | /** 617 | * 判断字符串分割后是否含有目标的字符串 618 | * @param str 源字符串 619 | * @param split 分隔符 620 | * @param tarStr 目标字符串 621 | * @return 622 | */ 623 | public static boolean contains(String str, String split, String tarStr) { 624 | if (isEmpty(str) || isEmpty(split) || isEmpty(tarStr)) { 625 | return false; 626 | } 627 | String[] splitedStr = str.split(split); 628 | for (String singleStr : splitedStr) { 629 | if (tarStr.equals(singleStr)) { 630 | return true; 631 | } 632 | } 633 | return false; 634 | } 635 | 636 | /** 637 | * 638 | * @param doub 639 | * @param formatStr 转换格式 默认为钱币格式(#,##0.00) 如:123,456,789.12 640 | * 还可以是###0.0或###0.00等 641 | * @return 642 | */ 643 | public static String formatDouble (Object doub, String formatStr){ 644 | if (doub == null) { 645 | return "0.0"; 646 | } 647 | if (isEmpty(formatStr)) { 648 | formatStr = "#,##0.00"; 649 | } 650 | 651 | DecimalFormat decimalFormat = new DecimalFormat(formatStr);//格式化设置 652 | return decimalFormat.format(doub); 653 | } 654 | public static String formatDouble (Object doub){ 655 | if (doub == null) { 656 | return "0.0"; 657 | } 658 | return formatDouble(doub, "#,##0.00"); 659 | } 660 | 661 | /** 662 | * 格式化数据,返回纯数字 663 | * @param doub 664 | * @param decimalDigit 保留小数位 665 | * @param divisor 除数,比如统计图标x轴单位为“万元”,需要除以10000 666 | * @return 无“,”号,无单位,纯数字 667 | */ 668 | public static String formatDouble (Double doub, int decimalDigit, int divisor){ 669 | if (doub == null) { 670 | return "0.0"; 671 | } 672 | if (divisor == 0) {//除数不能为0 673 | divisor = 1; 674 | } 675 | 676 | return BigDecimal.valueOf(doub).divide(new BigDecimal(divisor)).setScale(decimalDigit, BigDecimal.ROUND_HALF_UP).toPlainString(); 677 | } 678 | 679 | 680 | /** 681 | * 682 | * @param strs "adad,asdasd,司法所地方,第三方,sdfa,adf"(中英文逗号) 683 | * @return 684 | */ 685 | public static List getStringList(String strs){ 686 | List list = new ArrayList(); 687 | if(strs==null){ 688 | return null; 689 | } 690 | String[] strsArray1 = strs.split(","); 691 | for(String strs1 : strsArray1){ 692 | String[] productArray = strs1.split(","); 693 | for(String str : productArray){ 694 | list.add(str); 695 | } 696 | } 697 | return list; 698 | } 699 | 700 | public static List getListByCommaStr(String strs){ 701 | List list = new ArrayList(); 702 | String[] strsArray = strs.split(","); 703 | for(String strs1 : strsArray){ 704 | String[] strArray = strs1.split(","); 705 | for(String str : strArray){ 706 | list.add(str); 707 | } 708 | } 709 | return list; 710 | } 711 | 712 | public static Integer indexof(String str, String searchvalue){ 713 | return str.indexOf(searchvalue); 714 | } 715 | /** 716 | * 过滤特殊字符表情方法 717 | * @param codePoint 718 | * @return 719 | */ 720 | public static boolean isNotEmojiCharacter(char codePoint){ 721 | return (codePoint == 0x0) || 722 | (codePoint == 0x9) || 723 | (codePoint == 0xA) || 724 | (codePoint == 0xD) || 725 | ((codePoint >= 0x20) && (codePoint <= 0xD7FF)) || 726 | ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) || 727 | ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF)); 728 | } 729 | 730 | /** 731 | * 过滤emoji 或者 其他非文字类型的字符 732 | * @param source 733 | * @return 734 | */ 735 | public static String filterEmoji(String source){ 736 | if (StringUtil.isEmpty(source)) { 737 | return ""; 738 | } 739 | int len = source.length(); 740 | StringBuilder buf = new StringBuilder(len); 741 | for (int i = 0; i < len; i++) 742 | { 743 | char codePoint = source.charAt(i); 744 | if (isNotEmojiCharacter(codePoint)) 745 | { 746 | buf.append(codePoint); 747 | }else { 748 | buf.append("*"); 749 | } 750 | } 751 | return buf.toString(); 752 | } 753 | 754 | public static Object text(Object a){ 755 | 756 | return a; 757 | } 758 | 759 | public static String intToChineseNum(int num) { 760 | char[] val = String.valueOf(num).toCharArray(); 761 | int len = val.length; 762 | StringBuilder sb = new StringBuilder(); 763 | for (int i = 0; i < len; i++) { 764 | String m = val[i] + ""; 765 | int n = Integer.valueOf(m); 766 | boolean isZero = n == 0; 767 | String unit = units[(len - 1) - i]; 768 | if (isZero) { 769 | if ('0' == val[i - 1]) { 770 | // not need process if the last digital bits is 0 771 | continue; 772 | } else { 773 | // no unit for 0 774 | sb.append(numArray[n]); 775 | } 776 | } else { 777 | if(len < 3 && len > 1){ 778 | if(i != 0 || n != 1){ 779 | sb.append(numArray[n]); 780 | } 781 | }else{ 782 | sb.append(numArray[n]); 783 | } 784 | 785 | sb.append(unit); 786 | } 787 | } 788 | return sb.toString(); 789 | } 790 | 791 | public static void main(String[] args) { 792 | /************ pcasunzip.js中地区格式 转 成jsonArray形式 **************/ 793 | /* JSONArray jsonArray = new JSONArray(); 794 | String str = "北京市$北京市,东城区,西城区,崇文区,宣武区,朝阳区,丰台区,石景山区,海淀区,门头沟区,房山区,通州区,顺义区,昌平区,大兴区,怀柔区,平谷区,密云县,延庆县#天津市$天津市,和平区,河东区,河西区,南开区,河北区,红桥区,塘沽区,汉沽区,大港区,东丽区,西青区,津南区,北辰区,武清区,宝坻区,宁河县,静海县,蓟县#河北省$石家庄市,长安区,桥东区,桥西区,新华区,井陉矿区,裕华区,井陉县,正定县,栾城县,行唐县,灵寿县,高邑县,深泽县,赞皇县,无极县,平山县,元氏县,赵县,辛集市,藁城市,晋州市,新乐市,鹿泉市|唐山市,路南区,路北区,古冶区,开平区,丰南区,丰润区,滦县,滦南县,乐亭县,迁西县,玉田县,唐海县,遵化市,迁安市|秦皇岛市,海港区,山海关区,北戴河区,青龙满族自治县,昌黎县,抚宁县,卢龙县|邯郸市,邯山区,丛台区,复兴区,峰峰矿区,邯郸县,临漳县,成安县,大名县,涉县,磁县,肥乡县,永年县,邱县,鸡泽县,广平县,馆陶县,魏县,曲周县,武安市|邢台市,桥东区,桥西区,邢台县,临城县,内丘县,柏乡县,隆尧县,任县,南和县,宁晋县,巨鹿县,新河县,广宗县,平乡县,威县,清河县,临西县,南宫市,沙河市|保定市,新市区,北市区,南市区,满城县,清苑县,涞水县,阜平县,徐水县,定兴县,唐县,高阳县,容城县,涞源县,望都县,安新县,易县,曲阳县,蠡县,顺平县,博野县,雄县,涿州市,定州市,安国市,高碑店市|张家口市,桥东区,桥西区,宣化区,下花园区,宣化县,张北县,康保县,沽源县,尚义县,蔚县,阳原县,怀安县,万全县,怀来县,涿鹿县,赤城县,崇礼县|承德市,双桥区,双滦区,鹰手营子矿区,承德县,兴隆县,平泉县,滦平县,隆化县,丰宁满族自治县,宽城满族自治县,围场满族蒙古族自治县|沧州市,新华区,运河区,沧县,青县,东光县,海兴县,盐山县,肃宁县,南皮县,吴桥县,献县,孟村回族自治县,泊头市,任丘市,黄骅市,河间市|廊坊市,安次区,广阳区,固安县,永清县,香河县,大城县,文安县,大厂回族自治县,霸州市,三河市|衡水市,桃城区,枣强县,武邑县,武强县,饶阳县,安平县,故城县,景县,阜城县,冀州市,深州市#山西省$太原市,小店区,迎泽区,杏花岭区,尖草坪区,万柏林区,晋源区,清徐县,阳曲县,娄烦县,古交市|大同市,城区,矿区,南郊区,新荣区,阳高县,天镇县,广灵县,灵丘县,浑源县,左云县,大同县|阳泉市,城区,矿区,郊区,平定县,盂县|长治市,城区,郊区,长治县,襄垣县,屯留县,平顺县,黎城县,壶关县,长子县,武乡县,沁县,沁源县,潞城市|晋城市,城区,沁水县,阳城县,陵川县,泽州县,高平市|朔州市,朔城区,平鲁区,山阴县,应县,右玉县,怀仁县|晋中市,榆次区,榆社县,左权县,和顺县,昔阳县,寿阳县,太谷县,祁县,平遥县,灵石县,介休市|运城市,盐湖区,临猗县,万荣县,闻喜县,稷山县,新绛县,绛县,垣曲县,夏县,平陆县,芮城县,永济市,河津市|忻州市,忻府区,定襄县,五台县,代县,繁峙县,宁武县,静乐县,神池县,五寨县,岢岚县,河曲县,保德县,偏关县,原平市|临汾市,尧都区,曲沃县,翼城县,襄汾县,洪洞县,古县,安泽县,浮山县,吉县,乡宁县,大宁县,隰县,永和县,蒲县,汾西县,侯马市,霍州市|吕梁市,离石区,文水县,交城县,兴县,临县,柳林县,石楼县,岚县,方山县,中阳县,交口县,孝义市,汾阳市#内蒙古$呼和浩特市,新城区,回民区,玉泉区,赛罕区,土默特左旗,托克托县,和林格尔县,清水河县,武川县|包头市,东河区,昆都仑区,青山区,石拐区,白云矿区,九原区,土默特右旗,固阳县,达尔罕茂明安联合旗|乌海市,海勃湾区,海南区,乌达区|赤峰市,红山区,元宝山区,松山区,阿鲁科尔沁旗,巴林左旗,巴林右旗,林西县,克什克腾旗,翁牛特旗,喀喇沁旗,宁城县,敖汉旗|通辽市,科尔沁区,科尔沁左翼中旗,科尔沁左翼后旗,开鲁县,库伦旗,奈曼旗,扎鲁特旗,霍林郭勒市|鄂尔多斯市,东胜区,达拉特旗,准格尔旗,鄂托克前旗,鄂托克旗,杭锦旗,乌审旗,伊金霍洛旗|呼伦贝尔市,海拉尔区,阿荣旗,莫力达瓦达斡尔族自治旗,鄂伦春自治旗,鄂温克族自治旗,陈巴尔虎旗,新巴尔虎左旗,新巴尔虎右旗,满洲里市,牙克石市,扎兰屯市,额尔古纳市,根河市|巴彦淖尔市,临河区,五原县,磴口县,乌拉特前旗,乌拉特中旗,乌拉特后旗,杭锦后旗|乌兰察布市,集宁区,卓资县,化德县,商都县,兴和县,凉城县,察哈尔右翼前旗,察哈尔右翼中旗,察哈尔右翼后旗,四子王旗,丰镇市|兴安盟,乌兰浩特市,阿尔山市,科尔沁右翼前旗,科尔沁右翼中旗,扎赉特旗,突泉县|锡林郭勒盟,二连浩特市,锡林浩特市,阿巴嘎旗,苏尼特左旗,苏尼特右旗,东乌珠穆沁旗,西乌珠穆沁旗,太仆寺旗,镶黄旗,正镶白旗,正蓝旗,多伦县|阿拉善盟,阿拉善左旗,阿拉善右旗,额济纳旗#辽宁省$沈阳市,和平区,沈河区,大东区,皇姑区,铁西区,苏家屯区,东陵区,新城子区,于洪区,辽中县,康平县,法库县,新民市|大连市,中山区,西岗区,沙河口区,甘井子区,旅顺口区,金州区,长海县,瓦房店市,普兰店市,庄河市|鞍山市,铁东区,铁西区,立山区,千山区,台安县,岫岩满族自治县,海城市|抚顺市,新抚区,东洲区,望花区,顺城区,抚顺县,新宾满族自治县,清原满族自治县|本溪市,平山区,溪湖区,明山区,南芬区,本溪满族自治县,桓仁满族自治县|丹东市,元宝区,振兴区,振安区,宽甸满族自治县,东港市,凤城市|锦州市,古塔区,凌河区,太和区,黑山县,义县,凌海市,北宁市|营口市,站前区,西市区,鲅鱼圈区,老边区,盖州市,大石桥市|阜新市,海州区,新邱区,太平区,清河门区,细河区,阜新蒙古族自治县,彰武县|辽阳市,白塔区,文圣区,宏伟区,弓长岭区,太子河区,辽阳县,灯塔市|盘锦市,双台子区,兴隆台区,大洼县,盘山县|铁岭市,银州区,清河区,铁岭县,西丰县,昌图县,调兵山市,开原市|朝阳市,双塔区,龙城区,朝阳县,建平县,喀喇沁左翼蒙古族自治县,北票市,凌源市|葫芦岛市,连山区,龙港区,南票区,绥中县,建昌县,兴城市#吉林省$长春市,南关区,宽城区,朝阳区,二道区,绿园区,双阳区,农安县,九台市,榆树市,德惠市|吉林市,昌邑区,龙潭区,船营区,丰满区,永吉县,蛟河市,桦甸市,舒兰市,磐石市|四平市,铁西区,铁东区,梨树县,伊通满族自治县,公主岭市,双辽市|辽源市,龙山区,西安区,东丰县,东辽县|通化市,东昌区,二道江区,通化县,辉南县,柳河县,梅河口市,集安市|白山市,八道江区,抚松县,靖宇县,长白朝鲜族自治县,江源县,临江市|松原市,宁江区,前郭尔罗斯蒙古族自治县,长岭县,乾安县,扶余县|白城市,洮北区,镇赉县,通榆县,洮南市,大安市|延边朝鲜族自治州,延吉市,图们市,敦化市,珲春市,龙井市,和龙市,汪清县,安图县#黑龙江省$哈尔滨市,道里区,南岗区,道外区,香坊区,动力区,平房区,松北区,呼兰区,依兰县,方正县,宾县,巴彦县,木兰县,通河县,延寿县,阿城市,双城市,尚志市,五常市|齐齐哈尔市,龙沙区,建华区,铁锋区,昂昂溪区,富拉尔基区,碾子山区,梅里斯达斡尔族区,龙江县,依安县,泰来县,甘南县,富裕县,克山县,克东县,拜泉县,讷河市|鸡西市,鸡冠区,恒山区,滴道区,梨树区,城子河区,麻山区,鸡东县,虎林市,密山市|鹤岗市,向阳区,工农区,南山区,兴安区,东山区,兴山区,萝北县,绥滨县|双鸭山市,尖山区,岭东区,四方台区,宝山区,集贤县,友谊县,宝清县,饶河县|大庆市,萨尔图区,龙凤区,让胡路区,红岗区,大同区,肇州县,肇源县,林甸县,杜尔伯特蒙古族自治县|伊春市,伊春区,南岔区,友好区,西林区,翠峦区,新青区,美溪区,金山屯区,五营区,乌马河区,汤旺河区,带岭区,乌伊岭区,红星区,上甘岭区,嘉荫县,铁力市|佳木斯市,永红区,向阳区,前进区,东风区,郊区,桦南县,桦川县,汤原县,抚远县,同江市,富锦市|七台河市,新兴区,桃山区,茄子河区,勃利县|牡丹江市,东安区,阳明区,爱民区,西安区,东宁县,林口县,绥芬河市,海林市,宁安市,穆棱市|黑河市,爱辉区,嫩江县,逊克县,孙吴县,北安市,五大连池市|绥化市,北林区,望奎县,兰西县,青冈县,庆安县,明水县,绥棱县,安达市,肇东市,海伦市|大兴安岭地区,呼玛县,塔河县,漠河县#上海市$上海市,黄浦区,卢湾区,徐汇区,长宁区,静安区,普陀区,闸北区,虹口区,杨浦区,闵行区,宝山区,嘉定区,浦东新区,金山区,松江区,青浦区,南汇区,奉贤区,崇明县#江苏省$南京市,玄武区,白下区,秦淮区,建邺区,鼓楼区,下关区,浦口区,栖霞区,雨花台区,江宁区,六合区,溧水县,高淳县|无锡市,崇安区,南长区,北塘区,锡山区,惠山区,滨湖区,江阴市,宜兴市|徐州市,鼓楼区,云龙区,九里区,贾汪区,泉山区,丰县,沛县,铜山县,睢宁县,新沂市,邳州市|常州市,天宁区,钟楼区,戚墅堰区,新北区,武进区,溧阳市,金坛市|苏州市,沧浪区,平江区,金阊区,虎丘区,吴中区,相城区,常熟市,张家港市,昆山市,吴江市,太仓市|南通市,崇川区,港闸区,海安县,如东县,启东市,如皋市,通州市,海门市|连云港市,连云区,新浦区,海州区,赣榆县,东海县,灌云县,灌南县|淮安市,清河区,楚州区,淮阴区,清浦区,涟水县,洪泽县,盱眙县,金湖县|盐城市,亭湖区,盐都区,响水县,滨海县,阜宁县,射阳县,建湖县,东台市,大丰市|扬州市,广陵区,邗江区,维扬区,宝应县,仪征市,高邮市,江都市|镇江市,京口区,润州区,丹徒区,丹阳市,扬中市,句容市|泰州市,海陵区,高港区,兴化市,靖江市,泰兴市,姜堰市|宿迁市,宿城区,宿豫区,沭阳县,泗阳县,泗洪县#浙江省$杭州市,上城区,下城区,江干区,拱墅区,西湖区,滨江区,萧山区,余杭区,桐庐县,淳安县,建德市,富阳市,临安市|宁波市,海曙区,江东区,江北区,北仑区,镇海区,鄞州区,象山县,宁海县,余姚市,慈溪市,奉化市|温州市,鹿城区,龙湾区,瓯海区,洞头县,永嘉县,平阳县,苍南县,文成县,泰顺县,瑞安市,乐清市|嘉兴市,秀城区,秀洲区,嘉善县,海盐县,海宁市,平湖市,桐乡市|湖州市,吴兴区,南浔区,德清县,长兴县,安吉县|绍兴市,越城区,绍兴县,新昌县,诸暨市,上虞市,嵊州市|金华市,婺城区,金东区,武义县,浦江县,磐安县,兰溪市,义乌市,东阳市,永康市|衢州市,柯城区,衢江区,常山县,开化县,龙游县,江山市|舟山市,定海区,普陀区,岱山县,嵊泗县|台州市,椒江区,黄岩区,路桥区,玉环县,三门县,天台县,仙居县,温岭市,临海市|丽水市,莲都区,青田县,缙云县,遂昌县,松阳县,云和县,庆元县,景宁畲族自治县,龙泉市#安徽省$合肥市,瑶海区,庐阳区,蜀山区,包河区,长丰县,肥东县,肥西县|芜湖市,镜湖区,弋江区,鸠江区,三山区,芜湖县,繁昌县,南陵县|蚌埠市,龙子湖区,蚌山区,禹会区,淮上区,怀远县,五河县,固镇县|淮南市,大通区,田家庵区,谢家集区,八公山区,潘集区,凤台县|马鞍山市,金家庄区,花山区,雨山区,当涂县|淮北市,杜集区,相山区,烈山区,濉溪县|铜陵市,铜官山区,狮子山区,郊区,铜陵县|安庆市,迎江区,大观区,宜秀区,怀宁县,枞阳县,潜山县,太湖县,宿松县,望江县,岳西县,桐城市|黄山市,屯溪区,黄山区,徽州区,歙县,休宁县,黟县,祁门县|滁州市,琅琊区,南谯区,来安县,全椒县,定远县,凤阳县,天长市,明光市|阜阳市,颍州区,颍东区,颍泉区,临泉县,太和县,阜南县,颍上县,界首市|宿州市,埇桥区,砀山县,萧县,灵璧县,泗县|巢湖市,居巢区,庐江县,无为县,含山县,和县|六安市,金安区,裕安区,寿县,霍邱县,舒城县,金寨县,霍山县|亳州市,谯城区,涡阳县,蒙城县,利辛县|池州市,贵池区,东至县,石台县,青阳县|宣城市,宣州区,郎溪县,广德县,泾县,绩溪县,旌德县,宁国市#福建省$福州市,鼓楼区,台江区,仓山区,马尾区,晋安区,闽侯县,连江县,罗源县,闽清县,永泰县,平潭县,福清市,长乐市|厦门市,思明区,海沧区,湖里区,集美区,同安区,翔安区|莆田市,城厢区,涵江区,荔城区,秀屿区,仙游县|三明市,梅列区,三元区,明溪县,清流县,宁化县,大田县,尤溪县,沙县,将乐县,泰宁县,建宁县,永安市|泉州市,鲤城区,丰泽区,洛江区,泉港区,惠安县,安溪县,永春县,德化县,金门县,石狮市,晋江市,南安市|漳州市,芗城区,龙文区,云霄县,漳浦县,诏安县,长泰县,东山县,南靖县,平和县,华安县,龙海市|南平市,延平区,顺昌县,浦城县,光泽县,松溪县,政和县,邵武市,武夷山市,建瓯市,建阳市|龙岩市,新罗区,长汀县,永定县,上杭县,武平县,连城县,漳平市|宁德市,蕉城区,霞浦县,古田县,屏南县,寿宁县,周宁县,柘荣县,福安市,福鼎市#江西省$南昌市,东湖区,西湖区,青云谱区,湾里区,青山湖区,南昌县,新建县,安义县,进贤县|景德镇市,昌江区,珠山区,浮梁县,乐平市|萍乡市,安源区,湘东区,莲花县,上栗县,芦溪县|九江市,庐山区,浔阳区,九江县,武宁县,修水县,永修县,德安县,星子县,都昌县,湖口县,彭泽县,瑞昌市|新余市,渝水区,分宜县|鹰潭市,月湖区,余江县,贵溪市|赣州市,章贡区,赣县,信丰县,大余县,上犹县,崇义县,安远县,龙南县,定南县,全南县,宁都县,于都县,兴国县,会昌县,寻乌县,石城县,瑞金市,南康市|吉安市,吉州区,青原区,吉安县,吉水县,峡江县,新干县,永丰县,泰和县,遂川县,万安县,安福县,永新县,井冈山市|宜春市,袁州区,奉新县,万载县,上高县,宜丰县,靖安县,铜鼓县,丰城市,樟树市,高安市|抚州市,临川区,南城县,黎川县,南丰县,崇仁县,乐安县,宜黄县,金溪县,资溪县,东乡县,广昌县|上饶市,信州区,上饶县,广丰县,玉山县,铅山县,横峰县,弋阳县,余干县,鄱阳县,万年县,婺源县,德兴市#山东省$济南市,历下区,市中区,槐荫区,天桥区,历城区,长清区,平阴县,济阳县,商河县,章丘市|青岛市,市南区,市北区,四方区,黄岛区,崂山区,李沧区,城阳区,胶州市,即墨市,平度市,胶南市,莱西市|淄博市,淄川区,张店区,博山区,临淄区,周村区,桓台县,高青县,沂源县|枣庄市,市中区,薛城区,峄城区,台儿庄区,山亭区,滕州市|东营市,东营区,河口区,垦利县,利津县,广饶县|烟台市,芝罘区,福山区,牟平区,莱山区,长岛县,龙口市,莱阳市,莱州市,蓬莱市,招远市,栖霞市,海阳市|潍坊市,潍城区,寒亭区,坊子区,奎文区,临朐县,昌乐县,青州市,诸城市,寿光市,安丘市,高密市,昌邑市|济宁市,市中区,任城区,微山县,鱼台县,金乡县,嘉祥县,汶上县,泗水县,梁山县,曲阜市,兖州市,邹城市|泰安市,泰山区,岱岳区,宁阳县,东平县,新泰市,肥城市|威海市,环翠区,文登市,荣成市,乳山市|日照市,东港区,岚山区,五莲县,莒县|莱芜市,莱城区,钢城区|临沂市,兰山区,罗庄区,河东区,沂南县,郯城县,沂水县,苍山县,费县,平邑县,莒南县,蒙阴县,临沭县|德州市,德城区,陵县,宁津县,庆云县,临邑县,齐河县,平原县,夏津县,武城县,乐陵市,禹城市|聊城市,东昌府区,阳谷县,莘县,茌平县,东阿县,冠县,高唐县,临清市|滨州市,滨城区,惠民县,阳信县,无棣县,沾化县,博兴县,邹平县|菏泽市,牡丹区,曹县,单县,成武县,巨野县,郓城县,鄄城县,定陶县,东明县#河南省$郑州市,中原区,二七区,管城回族区,金水区,上街区,惠济区,中牟县,巩义市,荥阳市,新密市,新郑市,登封市|开封市,龙亭区,顺河回族区,鼓楼区,禹王台区,金明区,杞县,通许县,尉氏县,开封县,兰考县|洛阳市,老城区,西工区,廛河回族区,涧西区,吉利区,洛龙区,孟津县,新安县,栾川县,嵩县,汝阳县,宜阳县,洛宁县,伊川县,偃师市|平顶山市,新华区,卫东区,石龙区,湛河区,宝丰县,叶县,鲁山县,郏县,舞钢市,汝州市|安阳市,文峰区,北关区,殷都区,龙安区,安阳县,汤阴县,滑县,内黄县,林州市|鹤壁市,鹤山区,山城区,淇滨区,浚县,淇县|新乡市,红旗区,卫滨区,凤泉区,牧野区,新乡县,获嘉县,原阳县,延津县,封丘县,长垣县,卫辉市,辉县市|焦作市,解放区,中站区,马村区,山阳区,修武县,博爱县,武陟县,温县,济源市,沁阳市,孟州市|濮阳市,华龙区,清丰县,南乐县,范县,台前县,濮阳县|许昌市,魏都区,许昌县,鄢陵县,襄城县,禹州市,长葛市|漯河市,源汇区,郾城区,召陵区,舞阳县,临颍县|三门峡市,湖滨区,渑池县,陕县,卢氏县,义马市,灵宝市|南阳市,宛城区,卧龙区,南召县,方城县,西峡县,镇平县,内乡县,淅川县,社旗县,唐河县,新野县,桐柏县,邓州市|商丘市,梁园区,睢阳区,民权县,睢县,宁陵县,柘城县,虞城县,夏邑县,永城市|信阳市,浉河区,平桥区,罗山县,光山县,新县,商城县,固始县,潢川县,淮滨县,息县|周口市,川汇区,扶沟县,西华县,商水县,沈丘县,郸城县,淮阳县,太康县,鹿邑县,项城市|驻马店市,驿城区,西平县,上蔡县,平舆县,正阳县,确山县,泌阳县,汝南县,遂平县,新蔡县#湖北省$武汉市,江岸区,江汉区,硚口区,汉阳区,武昌区,青山区,洪山区,东西湖区,汉南区,蔡甸区,江夏区,黄陂区,新洲区|黄石市,黄石港区,西塞山区,下陆区,铁山区,阳新县,大冶市|十堰市,茅箭区,张湾区,郧县,郧西县,竹山县,竹溪县,房县,丹江口市|宜昌市,西陵区,伍家岗区,点军区,猇亭区,夷陵区,远安县,兴山县,秭归县,长阳土家族自治县,五峰土家族自治县,宜都市,当阳市,枝江市|襄樊市,襄城区,樊城区,襄阳区,南漳县,谷城县,保康县,老河口市,枣阳市,宜城市|鄂州市,梁子湖区,华容区,鄂城区|荆门市,东宝区,掇刀区,京山县,沙洋县,钟祥市|孝感市,孝南区,孝昌县,大悟县,云梦县,应城市,安陆市,汉川市|荆州市,沙市区,荆州区,公安县,监利县,江陵县,石首市,洪湖市,松滋市|黄冈市,黄州区,团风县,红安县,罗田县,英山县,浠水县,蕲春县,黄梅县,麻城市,武穴市|咸宁市,咸安区,嘉鱼县,通城县,崇阳县,通山县,赤壁市|随州市,曾都区,广水市|恩施土家族苗族自治州,恩施市,利川市,建始县,巴东县,宣恩县,咸丰县,来凤县,鹤峰县|省直辖行政单位,仙桃市,潜江市,天门市,神农架林区#湖南省$长沙市,芙蓉区,天心区,岳麓区,开福区,雨花区,长沙县,望城县,宁乡县,浏阳市|株洲市,荷塘区,芦淞区,石峰区,天元区,株洲县,攸县,茶陵县,炎陵县,醴陵市|湘潭市,雨湖区,岳塘区,湘潭县,湘乡市,韶山市|衡阳市,珠晖区,雁峰区,石鼓区,蒸湘区,南岳区,衡阳县,衡南县,衡山县,衡东县,祁东县,耒阳市,常宁市|邵阳市,双清区,大祥区,北塔区,邵东县,新邵县,邵阳县,隆回县,洞口县,绥宁县,新宁县,城步苗族自治县,武冈市|岳阳市,岳阳楼区,云溪区,君山区,岳阳县,华容县,湘阴县,平江县,汨罗市,临湘市|常德市,武陵区,鼎城区,安乡县,汉寿县,澧县,临澧县,桃源县,石门县,津市市|张家界市,永定区,武陵源区,慈利县,桑植县|益阳市,资阳区,赫山区,南县,桃江县,安化县,沅江市|郴州市,北湖区,苏仙区,桂阳县,宜章县,永兴县,嘉禾县,临武县,汝城县,桂东县,安仁县,资兴市|永州市,零陵区,冷水滩区,祁阳县,东安县,双牌县,道县,江永县,宁远县,蓝山县,新田县,江华瑶族自治县|怀化市,鹤城区,中方县,沅陵县,辰溪县,溆浦县,会同县,麻阳苗族自治县,新晃侗族自治县,芷江侗族自治县,靖州苗族侗族自治县,通道侗族自治县,洪江市|娄底市,娄星区,双峰县,新化县,冷水江市,涟源市|湘西土家族苗族自治州,吉首市,泸溪县,凤凰县,花垣县,保靖县,古丈县,永顺县,龙山县#广东省$广州市,荔湾区,越秀区,海珠区,天河区,白云区,黄埔区,番禺区,花都区,南沙区,萝岗区,增城市,从化市|韶关市,武江区,浈江区,曲江区,始兴县,仁化县,翁源县,乳源瑶族自治县,新丰县,乐昌市,南雄市|深圳市,罗湖区,福田区,南山区,宝安区,龙岗区,盐田区|珠海市,香洲区,斗门区,金湾区|汕头市,龙湖区,金平区,濠江区,潮阳区,潮南区,澄海区,南澳县|佛山市,禅城区,南海区,顺德区,三水区,高明区|江门市,蓬江区,江海区,新会区,台山市,开平市,鹤山市,恩平市|湛江市,赤坎区,霞山区,坡头区,麻章区,遂溪县,徐闻县,廉江市,雷州市,吴川市|茂名市,茂南区,茂港区,电白县,高州市,化州市,信宜市|肇庆市,端州区,鼎湖区,广宁县,怀集县,封开县,德庆县,高要市,四会市|惠州市,惠城区,惠阳区,博罗县,惠东县,龙门县|梅州市,梅江区,梅县,大埔县,丰顺县,五华县,平远县,蕉岭县,兴宁市|汕尾市,城区,海丰县,陆河县,陆丰市|河源市,源城区,紫金县,龙川县,连平县,和平县,东源县|阳江市,江城区,阳西县,阳东县,阳春市|清远市,清城区,佛冈县,阳山县,连山壮族瑶族自治县,连南瑶族自治县,清新县,英德市,连州市|东莞市|中山市|潮州市,湘桥区,潮安县,饶平县|揭阳市,榕城区,揭东县,揭西县,惠来县,普宁市|云浮市,云城区,新兴县,郁南县,云安县,罗定市#广西$南宁市,兴宁区,青秀区,江南区,西乡塘区,良庆区,邕宁区,武鸣县,隆安县,马山县,上林县,宾阳县,横县|柳州市,城中区,鱼峰区,柳南区,柳北区,柳江县,柳城县,鹿寨县,融安县,融水苗族自治县,三江侗族自治县|桂林市,秀峰区,叠彩区,象山区,七星区,雁山区,阳朔县,临桂县,灵川县,全州县,兴安县,永福县,灌阳县,龙胜各族自治县,资源县,平乐县,荔蒲县,恭城瑶族自治县|梧州市,万秀区,蝶山区,长洲区,苍梧县,藤县,蒙山县,岑溪市|北海市,海城区,银海区,铁山港区,合浦县|防城港市,港口区,防城区,上思县,东兴市|钦州市,钦南区,钦北区,灵山县,浦北县|贵港市,港北区,港南区,覃塘区,平南县,桂平市|玉林市,玉州区,容县,陆川县,博白县,兴业县,北流市|百色市,右江区,田阳县,田东县,平果县,德保县,靖西县,那坡县,凌云县,乐业县,田林县,西林县,隆林各族自治县|贺州市,八步区,昭平县,钟山县,富川瑶族自治县|河池市,金城江区,南丹县,天峨县,凤山县,东兰县,罗城仫佬族自治县,环江毛南族自治县,巴马瑶族自治县,都安瑶族自治县,大化瑶族自治县,宜州市|来宾市,兴宾区,忻城县,象州县,武宣县,金秀瑶族自治县,合山市|崇左市,江洲区,扶绥县,宁明县,龙州县,大新县,天等县,凭祥市#海南省$海口市,秀英区,龙华区,琼山区,美兰区|三亚市|省直辖县级行政单位,五指山市,琼海市,儋州市,文昌市,万宁市,东方市,定安县,屯昌县,澄迈县,临高县,白沙黎族自治县,昌江黎族自治县,乐东黎族自治县,陵水黎族自治县,保亭黎族苗族自治县,琼中黎族苗族自治县,西沙群岛,南沙群岛,中沙群岛的岛礁及其海域#重庆市$重庆市,万州区,涪陵区,渝中区,大渡口区,江北区,沙坪坝区,九龙坡区,南岸区,北碚区,万盛区,双桥区,渝北区,巴南区,黔江区,长寿区,綦江县,潼南县,铜梁县,大足县,荣昌县,璧山县,梁平县,城口县,丰都县,垫江县,武隆县,忠县,开县,云阳县,奉节县,巫山县,巫溪县,石柱土家族自治县,秀山土家族苗族自治县,酉阳土家族苗族自治县,彭水苗族土家族自治县|县级市,江津市,合川市,永川市,南川市#四川省$成都市,锦江区,青羊区,金牛区,武侯区,成华区,龙泉驿区,青白江区,新都区,温江区,金堂县,双流县,郫县,大邑县,蒲江县,新津县,都江堰市,彭州市,邛崃市,崇州市|自贡市,自流井区,贡井区,大安区,沿滩区,荣县,富顺县|攀枝花市,东区,西区,仁和区,米易县,盐边县|泸州市,江阳区,纳溪区,龙马潭区,泸县,合江县,叙永县,古蔺县|德阳市,旌阳区,中江县,罗江县,广汉市,什邡市,绵竹市|绵阳市,涪城区,游仙区,三台县,盐亭县,安县,梓潼县,北川羌族自治县,平武县,江油市|广元市,市中区,元坝区,朝天区,旺苍县,青川县,剑阁县,苍溪县|遂宁市,船山区,安居区,蓬溪县,射洪县,大英县|内江市,市中区,东兴区,威远县,资中县,隆昌县|乐山市,市中区,沙湾区,五通桥区,金口河区,犍为县,井研县,夹江县,沐川县,峨边彝族自治县,马边彝族自治县,峨眉山市|南充市,顺庆区,高坪区,嘉陵区,南部县,营山县,蓬安县,仪陇县,西充县,阆中市|眉山市,东坡区,仁寿县,彭山县,洪雅县,丹棱县,青神县|宜宾市,翠屏区,宜宾县,南溪县,江安县,长宁县,高县,珙县,筠连县,兴文县,屏山县|广安市,广安区,岳池县,武胜县,邻水县,华蓥市|达州市,通川区,达县,宣汉县,开江县,大竹县,渠县,万源市|雅安市,雨城区,名山县,荥经县,汉源县,石棉县,天全县,芦山县,宝兴县|巴中市,巴州区,通江县,南江县,平昌县|资阳市,雁江区,安岳县,乐至县,简阳市|阿坝藏族羌族自治州,汶川县,理县,茂县,松潘县,九寨沟县,金川县,小金县,黑水县,马尔康县,壤塘县,阿坝县,若尔盖县,红原县|甘孜藏族自治州,康定县,泸定县,丹巴县,九龙县,雅江县,道孚县,炉霍县,甘孜县,新龙县,德格县,白玉县,石渠县,色达县,理塘县,巴塘县,乡城县,稻城县,得荣县|凉山彝族自治州,西昌市,木里藏族自治县,盐源县,德昌县,会理县,会东县,宁南县,普格县,布拖县,金阳县,昭觉县,喜德县,冕宁县,越西县,甘洛县,美姑县,雷波县#贵州省$贵阳市,南明区,云岩区,花溪区,乌当区,白云区,小河区,开阳县,息烽县,修文县,清镇市|六盘水市,钟山区,六枝特区,水城县,盘县|遵义市,红花岗区,汇川区,遵义县,桐梓县,绥阳县,正安县,道真仡佬族苗族自治县,务川仡佬族苗族自治县,凤冈县,湄潭县,余庆县,习水县,赤水市,仁怀市|安顺市,西秀区,平坝县,普定县,镇宁布依族苗族自治县,关岭布依族苗族自治县,紫云苗族布依族自治县|铜仁地区,铜仁市,江口县,玉屏侗族自治县,石阡县,思南县,印江土家族苗族自治县,德江县,沿河土家族自治县,松桃苗族自治县,万山特区|黔西南布依族苗族自治州,兴义市,兴仁县,普安县,晴隆县,贞丰县,望谟县,册亨县,安龙县|毕节地区,毕节市,大方县,黔西县,金沙县,织金县,纳雍县,威宁彝族回族苗族自治县,赫章县|黔东南苗族侗族自治州,凯里市,黄平县,施秉县,三穗县,镇远县,岑巩县,天柱县,锦屏县,剑河县,台江县,黎平县,榕江县,从江县,雷山县,麻江县,丹寨县|黔南布依族苗族自治州,都匀市,福泉市,荔波县,贵定县,瓮安县,独山县,平塘县,罗甸县,长顺县,龙里县,惠水县,三都水族自治县#云南省$昆明市,五华区,盘龙区,官渡区,西山区,东川区,呈贡县,晋宁县,富民县,宜良县,石林彝族自治县,嵩明县,禄劝彝族苗族自治县,寻甸回族彝族自治县,安宁市|曲靖市,麒麟区,马龙县,陆良县,师宗县,罗平县,富源县,会泽县,沾益县,宣威市|玉溪市,红塔区,江川县,澄江县,通海县,华宁县,易门县,峨山彝族自治县,新平彝族傣族自治县,元江哈尼族彝族傣族自治县|保山市,隆阳区,施甸县,腾冲县,龙陵县,昌宁县|昭通市,昭阳区,鲁甸县,巧家县,盐津县,大关县,永善县,绥江县,镇雄县,彝良县,威信县,水富县|丽江市,古城区,玉龙纳西族自治县,永胜县,华坪县,宁蒗彝族自治县|思茅市,翠云区,普洱哈尼族彝族自治县,墨江哈尼族自治县,景东彝族自治县,景谷傣族彝族自治县,镇沅彝族哈尼族拉祜族自治县,江城哈尼族彝族自治县,孟连傣族拉祜族佤族自治县,澜沧拉祜族自治县,西盟佤族自治县|临沧市,临翔区,凤庆县,云县,永德县,镇康县,双江拉祜族佤族布朗族傣族自治县,耿马傣族佤族自治县,沧源佤族自治县|楚雄彝族自治州,楚雄市,双柏县,牟定县,南华县,姚安县,大姚县,永仁县,元谋县,武定县,禄丰县|红河哈尼族彝族自治州,个旧市,开远市,蒙自县,屏边苗族自治县,建水县,石屏县,弥勒县,泸西县,元阳县,红河县,金平苗族瑶族傣族自治县,绿春县,河口瑶族自治县|文山壮族苗族自治州,文山县,砚山县,西畴县,麻栗坡县,马关县,丘北县,广南县,富宁县|西双版纳傣族自治州,景洪市,勐海县,勐腊县|大理白族自治州,大理市,漾濞彝族自治县,祥云县,宾川县,弥渡县,南涧彝族自治县,巍山彝族回族自治县,永平县,云龙县,洱源县,剑川县,鹤庆县|德宏傣族景颇族自治州,瑞丽市,潞西市,梁河县,盈江县,陇川县|怒江傈僳族自治州,泸水县,福贡县,贡山独龙族怒族自治县,兰坪白族普米族自治县|迪庆藏族自治州,香格里拉县,德钦县,维西傈僳族自治县#西藏$拉萨市,城关区,林周县,当雄县,尼木县,曲水县,堆龙德庆县,达孜县,墨竹工卡县|昌都地区,昌都县,江达县,贡觉县,类乌齐县,丁青县,察雅县,八宿县,左贡县,芒康县,洛隆县,边坝县|山南地区,乃东县,扎囊县,贡嘎县,桑日县,琼结县,曲松县,措美县,洛扎县,加查县,隆子县,错那县,浪卡子县|日喀则地区,日喀则市,南木林县,江孜县,定日县,萨迦县,拉孜县,昂仁县,谢通门县,白朗县,仁布县,康马县,定结县,仲巴县,亚东县,吉隆县,聂拉木县,萨嘎县,岗巴县|那曲地区,那曲县,嘉黎县,比如县,聂荣县,安多县,申扎县,索县,班戈县,巴青县,尼玛县|阿里地区,普兰县,札达县,噶尔县,日土县,革吉县,改则县,措勤县|林芝地区,林芝县,工布江达县,米林县,墨脱县,波密县,察隅县,朗县#陕西省$西安市,新城区,碑林区,莲湖区,灞桥区,未央区,雁塔区,阎良区,临潼区,长安区,蓝田县,周至县,户县,高陵县|铜川市,王益区,印台区,耀州区,宜君县|宝鸡市,渭滨区,金台区,陈仓区,凤翔县,岐山县,扶风县,眉县,陇县,千阳县,麟游县,凤县,太白县|咸阳市,秦都区,杨凌区,渭城区,三原县,泾阳县,乾县,礼泉县,永寿县,彬县,长武县,旬邑县,淳化县,武功县,兴平市|渭南市,临渭区,华县,潼关县,大荔县,合阳县,澄城县,蒲城县,白水县,富平县,韩城市,华阴市|延安市,宝塔区,延长县,延川县,子长县,安塞县,志丹县,吴起县,甘泉县,富县,洛川县,宜川县,黄龙县,黄陵县|汉中市,汉台区,南郑县,城固县,洋县,西乡县,勉县,宁强县,略阳县,镇巴县,留坝县,佛坪县|榆林市,榆阳区,神木县,府谷县,横山县,靖边县,定边县,绥德县,米脂县,佳县,吴堡县,清涧县,子洲县|安康市,汉滨区,汉阴县,石泉县,宁陕县,紫阳县,岚皋县,平利县,镇坪县,旬阳县,白河县|商洛市,商州区,洛南县,丹凤县,商南县,山阳县,镇安县,柞水县#甘肃省$兰州市,城关区,七里河区,西固区,安宁区,红古区,永登县,皋兰县,榆中县|嘉峪关市,市辖区|金昌市,金川区,永昌县|白银市,白银区,平川区,靖远县,会宁县,景泰县|天水市,秦城区,北道区,清水县,秦安县,甘谷县,武山县,张家川回族自治县|武威市,凉州区,民勤县,古浪县,天祝藏族自治县|张掖市,甘州区,肃南裕固族自治县,民乐县,临泽县,高台县,山丹县|平凉市,崆峒区,泾川县,灵台县,崇信县,华亭县,庄浪县,静宁县|酒泉市,肃州区,金塔县,安西县,肃北蒙古族自治县,阿克塞哈萨克族自治县,玉门市,敦煌市|庆阳市,西峰区,庆城县,环县,华池县,合水县,正宁县,宁县,镇原县|定西市,安定区,通渭县,陇西县,渭源县,临洮县,漳县,岷县|陇南市,武都区,成县,文县,宕昌县,康县,西和县,礼县,徽县,两当县|临夏回族自治州,临夏市,临夏县,康乐县,永靖县,广河县,和政县,东乡族自治县,积石山保安族东乡族撒拉族自治县|甘南藏族自治州,合作市,临潭县,卓尼县,舟曲县,迭部县,玛曲县,碌曲县,夏河县#青海省$西宁市,城东区,城中区,城西区,城北区,大通回族土族自治县,湟中县,湟源县|海东地区,平安县,民和回族土族自治县,乐都县,互助土族自治县,化隆回族自治县,循化撒拉族自治县|海北藏族自治州,门源回族自治县,祁连县,海晏县,刚察县|黄南藏族自治州,同仁县,尖扎县,泽库县,河南蒙古族自治县|海南藏族自治州,共和县,同德县,贵德县,兴海县,贵南县|果洛藏族自治州,玛沁县,班玛县,甘德县,达日县,久治县,玛多县|玉树藏族自治州,玉树县,杂多县,称多县,治多县,囊谦县,曲麻莱县|海西蒙古族藏族自治州,格尔木市,德令哈市,乌兰县,都兰县,天峻县#宁夏$银川市,兴庆区,西夏区,金凤区,永宁县,贺兰县,灵武市|石嘴山市,大武口区,惠农区,平罗县|吴忠市,利通区,盐池县,同心县,青铜峡市|固原市,原州区,西吉县,隆德县,泾源县,彭阳县|中卫市,沙坡头区,中宁县,海原县#新疆$乌鲁木齐市,天山区,沙依巴克区,新市区,水磨沟区,头屯河区,达坂城区,东山区,乌鲁木齐县|克拉玛依市,独山子区,克拉玛依区,白碱滩区,乌尔禾区|吐鲁番地区,吐鲁番市,鄯善县,托克逊县|哈密地区,哈密市,巴里坤哈萨克自治县,伊吾县|昌吉回族自治州,昌吉市,阜康市,米泉市,呼图壁县,玛纳斯县,奇台县,吉木萨尔县,木垒哈萨克自治县|博尔塔拉蒙古自治州,博乐市,精河县,温泉县|巴音郭楞蒙古自治州,库尔勒市,轮台县,尉犁县,若羌县,且末县,焉耆回族自治县,和静县,和硕县,博湖县|阿克苏地区,阿克苏市,温宿县,库车县,沙雅县,新和县,拜城县,乌什县,阿瓦提县,柯坪县|克孜勒苏柯尔克孜自治州,阿图什市,阿克陶县,阿合奇县,乌恰县|喀什地区,喀什市,疏附县,疏勒县,英吉沙县,泽普县,莎车县,叶城县,麦盖提县,岳普湖县,伽师县,巴楚县,塔什库尔干塔吉克自治县|和田地区,和田市,和田县,墨玉县,皮山县,洛浦县,策勒县,于田县,民丰县|伊犁哈萨克自治州,伊宁市,奎屯市,伊宁县,察布查尔锡伯自治县,霍城县,巩留县,新源县,昭苏县,特克斯县,尼勒克县|塔城地区,塔城市,乌苏市,额敏县,沙湾县,托里县,裕民县,和布克赛尔蒙古自治县|阿勒泰地区,阿勒泰市,布尔津县,富蕴县,福海县,哈巴河县,青河县,吉木乃县|省直辖行政单位,石河子市,阿拉尔市,图木舒克市,五家渠市#香港$香港,香港#澳门$澳门,澳门#台湾省$台北市,中正区,大同区,中山区,松山区,大安区,万华区,信义区,士林区,北投区,内湖区,南港区,文山区|高雄市,新兴区,前金区,芩雅区,盐埕区,鼓山区,旗津区,前镇区,三民区,左营区,楠梓区,小港区|基隆市,仁爱区,信义区,中正区,中山区,安乐区,暖暖区,七堵区|台中市,中区,东区,南区,西区,北区,北屯区,西屯区,南屯区|台南市,中西区,东区,南区,北区,安平区,安南区|新竹市,东区,北区,香山区|嘉义市,东区,西区|县,台北县(板桥市),宜兰县(宜兰市),新竹县(竹北市),桃园县(桃园市),苗栗县(苗栗市),台中县(丰原市),彰化县(彰化市),南投县(南投市),嘉义县(太保市),云林县(斗六市),台南县(新营市),高雄县(凤山市),屏东县(屏东市),台东县(台东市),花莲县(花莲市),澎湖县(马公市)"; 795 | 796 | String[] pArray = str.split("#"); 797 | for(String pStr : pArray){ 798 | JSONObject json = new JSONObject(); 799 | String[] array = pStr.split("\\$"); 800 | String province = array[0]; 801 | 802 | JSONArray cJsonArray = new JSONArray(); 803 | if(array.length > 1){ 804 | String[] cArray = array[1].split("\\|"); 805 | for(String cStr : cArray){ 806 | JSONObject cjson = new JSONObject(); 807 | String[] dArray = cStr.split(","); 808 | // JSONArray dJsonArray = new JSONArray(); 809 | // for(int i = 1 ; i < dArray.length ; i++){ 810 | // JSONObject djson = new JSONObject(); 811 | // djson.put("name", dArray[i]); 812 | // dJsonArray.add(djson); 813 | // } 814 | cjson.put("name", dArray[0]); 815 | // cjson.put("children", dJsonArray); 816 | cJsonArray.add(cjson); 817 | } 818 | } 819 | json.put("name", province); 820 | json.put("children", cJsonArray); 821 | jsonArray.add(json); 822 | } 823 | LOG.info(jsonArray.toJSONString()); */ 824 | /* String html = ""+ 825 | "
aaaa
"+ 826 | "
"+ 827 | "

此处显示商品名称

"+ 828 | "

¥350.00

"+ 829 | "
"+ 830 | "购买"+ 831 | "
"; 832 | String target = "购买"; 833 | html = html.replace(target, "aaa"); 834 | LOG.info("html:"+html);*/ 835 | // String str = "[3, 2, 162, 1]"; 836 | // List idIn = JSON.parseArray(str, Integer.class); 837 | // String a="'aaa'"; 838 | // LOG.info(trim(a,'\'')); 839 | // LOG.info(toList("56+45+69","+")); 840 | String a = ""; 841 | String[] aa = a.split(":"); 842 | LOG.info(aa.length); 843 | 844 | } 845 | 846 | 847 | /** 848 | * 将银行号除了后4位变为*号 849 | * @param bankCode 850 | * @return 851 | */ 852 | public static String hideBankCode(String bankCode) { 853 | if (isEmpty(bankCode)) { 854 | return ""; 855 | } 856 | if (bankCode.length() < 4 ) { 857 | return bankCode; 858 | } 859 | 860 | String beforeCode = bankCode.substring(0, bankCode.length()-4);//除了后4位 861 | String lastCode = bankCode.substring(bankCode.length()-4);//后4位 862 | 863 | String star = ""; 864 | for (int i = 0; i < beforeCode.length(); i++) { 865 | star += "*"; 866 | } 867 | 868 | return star + lastCode; 869 | } 870 | 871 | /*************************************************************************** 872 | * repeat - 通过源字符串重复生成N次组成新的字符串。 873 | * 874 | * @param src 875 | * - 源字符串 例如: 空格(" "), 星号("*"), "0", "浙江" 等等... 876 | * @param num 877 | * - 重复生成次数 878 | * @return 返回已生成的重复字符串 879 | * @author kaka 880 | **************************************************************************/ 881 | public static String repeat(String src, int num) { 882 | StringBuffer s = new StringBuffer(); 883 | for (int i = 0; i < num; i++) 884 | s.append(src); 885 | return s.toString(); 886 | } 887 | 888 | /** 889 | * 返回byte的数据大小对应的文本 890 | * @param size 891 | * @return 892 | */ 893 | public static String getDataSize(long size){ 894 | DecimalFormat formater = new DecimalFormat("####.00"); 895 | if(size<1024){ 896 | return size+"bytes"; 897 | }else if(size<1024*1024){ 898 | float kbsize = size/1024f; 899 | return formater.format(kbsize)+"KB"; 900 | }else if(size<1024*1024*1024){ 901 | float mbsize = size/1024f/1024f; 902 | return formater.format(mbsize)+"MB"; 903 | }else if(size<1024*1024*1024*1024){ 904 | float gbsize = size/1024f/1024f/1024f; 905 | return formater.format(gbsize)+"GB"; 906 | }else{ 907 | float gbsize = size/1024f/1024f/1024f; 908 | return formater.format(gbsize)+"GB"; 909 | } 910 | } 911 | 912 | /** 913 | * 将首字母转换为大写 914 | * @param str 915 | * @return 916 | */ 917 | public static String upperFirstChar(String str) { 918 | char[] chars = new char[1]; 919 | chars[0] = str.charAt(0); 920 | String tempStr = new String(chars); 921 | if (chars[0] >= 'a' && chars[0] <= 'z') { 922 | str = str.replaceFirst(tempStr, tempStr.toUpperCase()); 923 | } 924 | return str; 925 | } 926 | 927 | /** 928 | * 将首字母转换为小写 929 | * @param str 930 | * @return 931 | */ 932 | public static String lowerFirstChar(String str) { 933 | char[] chars = new char[1]; 934 | chars[0] = str.charAt(0); 935 | String tempStr = new String(chars); 936 | if (chars[0] >= 'A' && chars[0] <= 'Z') { 937 | str = str.replaceFirst(tempStr, tempStr.toLowerCase()); 938 | } 939 | return str; 940 | } 941 | 942 | } -------------------------------------------------------------------------------- /src/main/resources/Banner.txt: -------------------------------------------------------------------------------- 1 | __ __ ___. _________ __ __ 2 | / \ / \ ____\_ |__ / _____/ ____ ____ | | __ _____/ |_ 3 | \ \/\/ // __ \| __ \ \_____ \ / _ \_/ ___\| |/ // __ \ __\ 4 | \ /\ ___/| \_\ \/ ( <_> ) \___| <\ ___/| | 5 | \__/\ / \___ >___ /_______ /\____/ \___ >__|_ \\___ >__| 6 | \/ \/ \/ \/ \/ \/ \/ -------------------------------------------------------------------------------- /src/main/resources/application-aliyun.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | context-path: / 4 | localConstant: 5 | projectName: xbbDingtalkTest 6 | jedis: 7 | pool: 8 | host: redis.server 9 | port: 6379 10 | timeout: 0 11 | password: mUWPMPpWyv8I069o 12 | config: 13 | maxTotal: 30 14 | maxIdle: 10 15 | maxWaitMillis: 1500 -------------------------------------------------------------------------------- /src/main/resources/application-dev.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | context-path: / 4 | localConstant: 5 | projectName: xbbDingtalkLocal 6 | jedis: 7 | pool: 8 | host: 192.168.10.5 9 | port: 6379 10 | timeout: 0 11 | password: mUWPMPpWyv8I069o 12 | config: 13 | maxTotal: 30 14 | maxIdle: 10 15 | maxWaitMillis: 1500 -------------------------------------------------------------------------------- /src/main/resources/application-jushita.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 5051 3 | context-path: / 4 | localConstant: 5 | projectName: xbbDingtalk 6 | jedis: 7 | pool: 8 | host: 10.24.41.81 9 | port: 6379 10 | timeout: 0 11 | password: mUWPMPpWyv8I069o 12 | config: 13 | maxTotal: 30 14 | maxIdle: 10 15 | maxWaitMillis: 1500 -------------------------------------------------------------------------------- /src/main/resources/application-jushitaTest.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 5051 3 | context-path: / 4 | localConstant: 5 | projectName: xbbDingtalkTest 6 | jedis: 7 | pool: 8 | host: 10.24.41.81 9 | port: 6379 10 | timeout: 0 11 | password: mUWPMPpWyv8I069o 12 | config: 13 | maxTotal: 30 14 | maxIdle: 10 15 | maxWaitMillis: 1500 -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: jushita 4 | thymeleaf: 5 | cache: false #关闭thymeleaf的缓存 6 | management: 7 | security: 8 | enabled: false 9 | context-path: /manage 10 | logging: 11 | config: classpath:log4j2.xml -------------------------------------------------------------------------------- /src/main/resources/commands/hello.groovy: -------------------------------------------------------------------------------- 1 | package commands 2 | /** 3 | * User: Gavin 4 | * E-mail: GavinChangCN@163.com 5 | * Desc: 6 | * Date: 2017-03-28 7 | * Time: 17:37 8 | */ 9 | class hello { 10 | // def main(InvocationContext context) { 11 | // 12 | // } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d %p %C{1.} [%t] %m%n 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 错误页 18 | 19 | 20 | 21 |

22 | 23 | -------------------------------------------------------------------------------- /src/main/resources/templates/websocket.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 测试 WebSocket 的聊天室 18 | 19 | 20 | 21 | Welcome To Chat Room
22 | 23 | 24 | 25 |
26 |
27 | 28 | 29 | 88 | 89 | -------------------------------------------------------------------------------- /src/test/java/com/xbongbong/DemoBeanIntegrationTests.java: -------------------------------------------------------------------------------- 1 | package com.xbongbong; 2 | 3 | import com.xbongbong.bean.TestBean; 4 | import com.xbongbong.config.TestConfig; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.test.context.ActiveProfiles; 10 | import org.springframework.test.context.ContextConfiguration; 11 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 12 | 13 | /** 14 | * User: Gavin 15 | * E-mail: GavinChangCN@163.com 16 | * Desc: 17 | * Date: 2017-03-24 18 | * Time: 16:55 19 | */ 20 | @RunWith(SpringJUnit4ClassRunner.class) 21 | @ContextConfiguration(classes = {TestConfig.class}) 22 | @ActiveProfiles("prod") 23 | public class DemoBeanIntegrationTests { 24 | protected static final String TAG = "DemoBeanIntegrationTests"; 25 | 26 | @Autowired 27 | private TestBean testBean; 28 | 29 | @Test 30 | public void prodBeanShouldInject() { 31 | String expected = "from production profile"; 32 | String actual = testBean.getContent(); 33 | Assert.assertEquals(expected, actual); 34 | } 35 | 36 | @Test 37 | public void devBeanShouldInject() { 38 | String expected = "from development profile"; 39 | String actual = testBean.getContent(); 40 | Assert.assertEquals(expected, actual); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/xbongbong/XbbWebSocketApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.xbongbong; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.xbongbong.util.DateUtil; 6 | import org.apache.logging.log4j.LogManager; 7 | import org.apache.logging.log4j.Logger; 8 | import org.junit.After; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 13 | import org.springframework.test.context.web.WebAppConfiguration; 14 | 15 | @RunWith(SpringJUnit4ClassRunner.class) 16 | @WebAppConfiguration 17 | public class XbbWebSocketApplicationTests { 18 | 19 | private static final Logger LOG = LogManager 20 | .getLogger(XbbWebSocketApplicationTests.class); 21 | 22 | private int mStartTime; 23 | 24 | @Before 25 | public void beforeJunitTest() { 26 | mStartTime = DateUtil.getInt(); 27 | LOG.info("========================= 单元测试开始时间:" + DateUtil.getInt() + " =========================="); 28 | } 29 | 30 | @After 31 | public void afterJunitTest() { 32 | int endTime = DateUtil.getInt(); 33 | LOG.info("========================= 单元测试开始时间:" + endTime + " =========================="); 34 | LOG.info("*********************** 累计用时:" + (endTime - mStartTime) + "s ************************"); 35 | } 36 | 37 | @Test 38 | public void contextLoads() { 39 | JSONObject json = (JSONObject) JSON.parse("{\"addTime\":1489827964,\"corpid\":\"1\",\"message\":\"{\\\"content\\\":\\\"新建客户 1个客户 成功,请及时跟进!1个客户 ——来自销售自动化\\\",\\\"messageUrl\\\":\\\"http://localhost:8088//opportunity/detail.html?id=240%26dd_nav_bgcolor=ffff943e\\\",\\\"title\\\":\\\"1个客户需要关注,请及时跟进\\\"}\",\"pushTime\":1489827964,\"userId\":\"1\"}"); 40 | LOG.info(json.toJSONString()); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/xbongbong/bean/TestBean.java: -------------------------------------------------------------------------------- 1 | package com.xbongbong.bean; 2 | 3 | /** 4 | * User: Gavin 5 | * E-mail: GavinChangCN@163.com 6 | * Desc: 7 | * Date: 2017-03-24 8 | * Time: 16:52 9 | */ 10 | public class TestBean { 11 | protected static final String TAG = "TestBean"; 12 | 13 | private String content; 14 | 15 | public TestBean(String content) { 16 | this.content = content; 17 | } 18 | 19 | public String getContent() { 20 | return content; 21 | } 22 | 23 | public void setContent(String content) { 24 | this.content = content; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/xbongbong/config/TestConfig.java: -------------------------------------------------------------------------------- 1 | package com.xbongbong.config; 2 | 3 | import com.xbongbong.bean.TestBean; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Profile; 7 | 8 | /** 9 | * User: Gavin 10 | * E-mail: GavinChangCN@163.com 11 | * Desc: 12 | * Date: 2017-03-24 13 | * Time: 16:53 14 | */ 15 | @Configuration 16 | public class TestConfig { 17 | protected static final String TAG = "TestConfig"; 18 | 19 | @Bean 20 | @Profile("dev") 21 | public TestBean devTestBean() { 22 | return new TestBean("from development profile"); 23 | } 24 | 25 | @Bean 26 | @Profile("prod") 27 | public TestBean prodTestBean() { 28 | return new TestBean("from production profile"); 29 | } 30 | } 31 | --------------------------------------------------------------------------------