├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── example │ │ └── learnspring │ │ ├── LearnSpringApplication.java │ │ ├── WebSocketConfig.java │ │ ├── WebSocketServer.kt │ │ ├── bean │ │ ├── Contact.kt │ │ ├── RequestMsgBean.kt │ │ ├── ResponseMsgBean.kt │ │ ├── RoomBean.kt │ │ ├── SdpBean.kt │ │ ├── api │ │ │ ├── AllRoomListResponse.kt │ │ │ ├── ApiController.kt │ │ │ └── base │ │ │ │ └── BaseApiResponse.kt │ │ ├── request │ │ │ ├── BaseRequest.kt │ │ │ └── CreateRoomRequest.kt │ │ └── response │ │ │ ├── AddContactResponse.kt │ │ │ ├── AllContactResponse.kt │ │ │ ├── BaseResponse.kt │ │ │ ├── CreateRoomResponse.kt │ │ │ ├── JoinSuccessResponse.kt │ │ │ └── RemoveContactResponse.kt │ │ ├── constant │ │ └── RRType.kt │ │ ├── controller │ │ └── TestController.java │ │ ├── manager │ │ ├── ContactManager.kt │ │ ├── MessageManager.kt │ │ ├── RoomManager.kt │ │ └── SessionManager.kt │ │ └── utils │ │ └── JsonUtils.java ├── resources │ └── application.properties └── webapp │ └── index.jsp └── test └── java └── com └── example └── learnspring └── LearnSpringApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | import java.nio.channels.*; 20 | import java.util.Properties; 21 | 22 | public class MavenWrapperDownloader { 23 | 24 | private static final String WRAPPER_VERSION = "0.5.6"; 25 | /** 26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 27 | */ 28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 30 | 31 | /** 32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 33 | * use instead of the default one. 34 | */ 35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 36 | ".mvn/wrapper/maven-wrapper.properties"; 37 | 38 | /** 39 | * Path where the maven-wrapper.jar will be saved to. 40 | */ 41 | private static final String MAVEN_WRAPPER_JAR_PATH = 42 | ".mvn/wrapper/maven-wrapper.jar"; 43 | 44 | /** 45 | * Name of the property which should be used to override the default download url for the wrapper. 46 | */ 47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 48 | 49 | public static void main(String args[]) { 50 | System.out.println("- Downloader started"); 51 | File baseDirectory = new File(args[0]); 52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 53 | 54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 55 | // wrapperUrl parameter. 56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 57 | String url = DEFAULT_DOWNLOAD_URL; 58 | if (mavenWrapperPropertyFile.exists()) { 59 | FileInputStream mavenWrapperPropertyFileInputStream = null; 60 | try { 61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 62 | Properties mavenWrapperProperties = new Properties(); 63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 65 | } catch (IOException e) { 66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 67 | } finally { 68 | try { 69 | if (mavenWrapperPropertyFileInputStream != null) { 70 | mavenWrapperPropertyFileInputStream.close(); 71 | } 72 | } catch (IOException e) { 73 | // Ignore ... 74 | } 75 | } 76 | } 77 | System.out.println("- Downloading from: " + url); 78 | 79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 80 | if (!outputFile.getParentFile().exists()) { 81 | if (!outputFile.getParentFile().mkdirs()) { 82 | System.out.println( 83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wolongalick/LearnWebRtcServer/29ba0f90c1f04c6802b8028f2a7efb7a8c7c4cf2/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LearnWebRtcServer 2 | 这是一个用于音视频通话的webrtc服务端项目 3 | 4 | 安卓端:https://github.com/wolongalick/LearnWebRtc 5 | -------------------------------------------------------------------------------- /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 | # https://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 | # Maven 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 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | fi 118 | 119 | if [ -z "$JAVA_HOME" ]; then 120 | javaExecutable="`which javac`" 121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 122 | # readlink(1) is not available as standard on Solaris 10. 123 | readLink=`which readlink` 124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 125 | if $darwin ; then 126 | javaHome="`dirname \"$javaExecutable\"`" 127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 128 | else 129 | javaExecutable="`readlink -f \"$javaExecutable\"`" 130 | fi 131 | javaHome="`dirname \"$javaExecutable\"`" 132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 133 | JAVA_HOME="$javaHome" 134 | export JAVA_HOME 135 | fi 136 | fi 137 | fi 138 | 139 | if [ -z "$JAVACMD" ] ; then 140 | if [ -n "$JAVA_HOME" ] ; then 141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 142 | # IBM's JDK on AIX uses strange locations for the executables 143 | JAVACMD="$JAVA_HOME/jre/sh/java" 144 | else 145 | JAVACMD="$JAVA_HOME/bin/java" 146 | fi 147 | else 148 | JAVACMD="`which java`" 149 | fi 150 | fi 151 | 152 | if [ ! -x "$JAVACMD" ] ; then 153 | echo "Error: JAVA_HOME is not defined correctly." >&2 154 | echo " We cannot execute $JAVACMD" >&2 155 | exit 1 156 | fi 157 | 158 | if [ -z "$JAVA_HOME" ] ; then 159 | echo "Warning: JAVA_HOME environment variable is not set." 160 | fi 161 | 162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 163 | 164 | # traverses directory structure from process work directory to filesystem root 165 | # first directory with .mvn subdirectory is considered project base directory 166 | find_maven_basedir() { 167 | 168 | if [ -z "$1" ] 169 | then 170 | echo "Path not specified to find_maven_basedir" 171 | return 1 172 | fi 173 | 174 | basedir="$1" 175 | wdir="$1" 176 | while [ "$wdir" != '/' ] ; do 177 | if [ -d "$wdir"/.mvn ] ; then 178 | basedir=$wdir 179 | break 180 | fi 181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 182 | if [ -d "${wdir}" ]; then 183 | wdir=`cd "$wdir/.."; pwd` 184 | fi 185 | # end of workaround 186 | done 187 | echo "${basedir}" 188 | } 189 | 190 | # concatenates all lines of a file 191 | concat_lines() { 192 | if [ -f "$1" ]; then 193 | echo "$(tr -s '\n' ' ' < "$1")" 194 | fi 195 | } 196 | 197 | BASE_DIR=`find_maven_basedir "$(pwd)"` 198 | if [ -z "$BASE_DIR" ]; then 199 | exit 1; 200 | fi 201 | 202 | ########################################################################################## 203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 204 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 205 | ########################################################################################## 206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 207 | if [ "$MVNW_VERBOSE" = true ]; then 208 | echo "Found .mvn/wrapper/maven-wrapper.jar" 209 | fi 210 | else 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 213 | fi 214 | if [ -n "$MVNW_REPOURL" ]; then 215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 216 | else 217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 218 | fi 219 | while IFS="=" read key value; do 220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 221 | esac 222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 223 | if [ "$MVNW_VERBOSE" = true ]; then 224 | echo "Downloading from: $jarUrl" 225 | fi 226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 227 | if $cygwin; then 228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 229 | fi 230 | 231 | if command -v wget > /dev/null; then 232 | if [ "$MVNW_VERBOSE" = true ]; then 233 | echo "Found wget ... using wget" 234 | fi 235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 236 | wget "$jarUrl" -O "$wrapperJarPath" 237 | else 238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" 239 | fi 240 | elif command -v curl > /dev/null; then 241 | if [ "$MVNW_VERBOSE" = true ]; then 242 | echo "Found curl ... using curl" 243 | fi 244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 245 | curl -o "$wrapperJarPath" "$jarUrl" -f 246 | else 247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 248 | fi 249 | 250 | else 251 | if [ "$MVNW_VERBOSE" = true ]; then 252 | echo "Falling back to using Java to download" 253 | fi 254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 255 | # For Cygwin, switch paths to Windows format before running javac 256 | if $cygwin; then 257 | javaClass=`cygpath --path --windows "$javaClass"` 258 | fi 259 | if [ -e "$javaClass" ]; then 260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 261 | if [ "$MVNW_VERBOSE" = true ]; then 262 | echo " - Compiling MavenWrapperDownloader.java ..." 263 | fi 264 | # Compiling the Java class 265 | ("$JAVA_HOME/bin/javac" "$javaClass") 266 | fi 267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 268 | # Running the downloader 269 | if [ "$MVNW_VERBOSE" = true ]; then 270 | echo " - Running MavenWrapperDownloader.java ..." 271 | fi 272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 273 | fi 274 | fi 275 | fi 276 | fi 277 | ########################################################################################## 278 | # End of extension 279 | ########################################################################################## 280 | 281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 282 | if [ "$MVNW_VERBOSE" = true ]; then 283 | echo $MAVEN_PROJECTBASEDIR 284 | fi 285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 286 | 287 | # For Cygwin, switch paths to Windows format before running java 288 | if $cygwin; then 289 | [ -n "$M2_HOME" ] && 290 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 291 | [ -n "$JAVA_HOME" ] && 292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 293 | [ -n "$CLASSPATH" ] && 294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 295 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 297 | fi 298 | 299 | # Provide a "standardized" way to retrieve the CLI args that will 300 | # work with both Windows and non-Windows executions. 301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 302 | export MAVEN_CMD_LINE_ARGS 303 | 304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 305 | 306 | exec "$JAVACMD" \ 307 | $MAVEN_OPTS \ 308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 311 | -------------------------------------------------------------------------------- /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 https://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 Maven 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 keystroke 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 set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 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 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 124 | 125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 162 | if ERRORLEVEL 1 goto error 163 | goto end 164 | 165 | :error 166 | set ERROR_CODE=1 167 | 168 | :end 169 | @endlocal & set ERROR_CODE=%ERROR_CODE% 170 | 171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 175 | :skipRcPost 176 | 177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 179 | 180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 181 | 182 | exit /B %ERROR_CODE% 183 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.5.1 9 | 10 | 11 | com.example 12 | LearnWebRtcServer 13 | 0.0.1-SNAPSHOT 14 | LearnWebRtcServer 15 | Demo project for Spring Boot 16 | 17 | 1.8 18 | 1.5.10 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-web 24 | 25 | 26 | org.mybatis.spring.boot 27 | mybatis-spring-boot-starter 28 | 2.2.0 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-websocket 33 | 34 | 35 | mysql 36 | mysql-connector-java 37 | runtime 38 | 39 | 40 | org.projectlombok 41 | lombok 42 | true 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-test 47 | test 48 | 49 | 50 | org.apache.tomcat.embed 51 | tomcat-embed-jasper 52 | 9.0.45 53 | 54 | 55 | org.jetbrains.kotlin 56 | kotlin-stdlib-jdk8 57 | ${kotlin.version} 58 | 59 | 60 | org.jetbrains.kotlin 61 | kotlin-test 62 | ${kotlin.version} 63 | test 64 | 65 | 66 | com.google.code.gson 67 | gson 68 | 2.8.2 69 | 70 | 71 | com.vaadin.external.google 72 | android-json 73 | 0.0.20131108.vaadin1 74 | compile 75 | 76 | 77 | com.vaadin.external.google 78 | android-json 79 | 0.0.20131108.vaadin1 80 | compile 81 | 82 | 83 | 84 | 85 | 86 | 87 | org.springframework.boot 88 | spring-boot-maven-plugin 89 | 90 | 91 | 92 | org.projectlombok 93 | lombok 94 | 95 | 96 | 97 | 98 | 99 | org.jetbrains.kotlin 100 | kotlin-maven-plugin 101 | ${kotlin.version} 102 | 103 | 104 | compile 105 | compile 106 | 107 | compile 108 | 109 | 110 | 111 | test-compile 112 | test-compile 113 | 114 | test-compile 115 | 116 | 117 | 118 | 119 | 1.8 120 | 121 | 122 | 123 | org.apache.maven.plugins 124 | maven-compiler-plugin 125 | 126 | 127 | compile 128 | compile 129 | 130 | compile 131 | 132 | 133 | 134 | testCompile 135 | test-compile 136 | 137 | testCompile 138 | 139 | 140 | 141 | 142 | 143 | 144 | org.apache.maven.plugins 145 | maven-surefire-plugin 146 | 2.22.1 147 | 148 | true 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/LearnSpringApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.learnspring; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class LearnSpringApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(LearnSpringApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/WebSocketConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.learnspring; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; 7 | import org.springframework.web.socket.server.standard.ServerEndpointExporter; 8 | 9 | /** 10 | * 开启WebSocket支持 配置websocket并开启 11 | */ 12 | @Configuration 13 | public class WebSocketConfig extends WebMvcConfigurationSupport { 14 | @Bean 15 | public ServerEndpointExporter serverEndpointExporter() { 16 | return new ServerEndpointExporter(); 17 | } 18 | 19 | @Override 20 | protected void addResourceHandlers(ResourceHandlerRegistry registry) { 21 | super.addResourceHandlers(registry); 22 | // 相对路径 23 | // registry.addResourceHandler("image/**").addResourceLocations("classpath:/static/image/"); 24 | // 绝对路径 25 | // registry.addResourceHandler("image/**").addResourceLocations("file:" + "image/"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/WebSocketServer.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring 2 | 3 | import com.example.learnspring.bean.Contact 4 | import com.example.learnspring.bean.RoomBean 5 | import com.example.learnspring.bean.request.BaseRequest 6 | import com.example.learnspring.bean.request.CreateRoomRequest 7 | import com.example.learnspring.bean.response.* 8 | import com.example.learnspring.constant.RequestType 9 | import com.example.learnspring.manager.ContactManager 10 | import com.example.learnspring.manager.MessageManager 11 | import com.example.learnspring.manager.RoomManager 12 | import com.example.learnspring.manager.SessionManager 13 | import com.example.learnspring.utils.JsonUtils 14 | import javax.websocket.server.ServerEndpoint 15 | import javax.websocket.OnOpen 16 | import javax.websocket.server.PathParam 17 | import javax.websocket.OnClose 18 | import javax.websocket.OnMessage 19 | import org.slf4j.LoggerFactory 20 | import org.springframework.stereotype.Component 21 | import javax.websocket.Session 22 | 23 | @ServerEndpoint("/webSocket/{account}") 24 | @Component 25 | class WebSocketServer { 26 | 27 | companion object { 28 | private val LOG = LoggerFactory.getLogger(WebSocketServer::class.java) 29 | } 30 | 31 | private var account: String? = null 32 | 33 | // 用户userId登录进来 34 | @OnOpen 35 | fun onOpen(session: Session?, @PathParam("account") account: String) { 36 | this.account = account 37 | println("$account-->onOpen......,account:$account") 38 | SessionManager.addSession(account, session!!) 39 | val newContact = Contact(account) 40 | ContactManager.addContact(account, newContact) 41 | 42 | SessionManager.sessionMap.forEach { 43 | MessageManager.send(AddContactResponse(it.key, newContact)) 44 | } 45 | } 46 | 47 | // 用户下线 48 | @OnClose 49 | fun onClose() { 50 | println("$account-->onClose......") 51 | // 根据用户名查出房间, 52 | account?.let { it -> 53 | SessionManager.removeSession(it) 54 | SessionManager.sessionMap.forEach { entry -> 55 | MessageManager.send(RemoveContactResponse(entry.key, ContactManager.getContact(it)!!)) 56 | } 57 | } 58 | 59 | } 60 | 61 | @OnMessage 62 | fun onMessage(message: String, session: Session) { 63 | handleMessage(message, session) 64 | } 65 | 66 | // 处理各种消息 67 | private fun handleMessage(message: String, session: Session) { 68 | val baseRequest = JsonUtils.parseJson2Bean(message, BaseRequest::class.java) 69 | val msgType = baseRequest.msgType 70 | println("服务器接收的消息,msgType:$msgType,:$message") 71 | when (msgType) { 72 | RequestType.All_CONTACT -> { 73 | val list = mutableListOf() 74 | SessionManager.sessionMap.forEach { entry -> 75 | ContactManager.getContact(entry.key)?.apply { 76 | list.add(this) 77 | } 78 | } 79 | MessageManager.send(AllContactResponse(baseRequest.fromAccount, list)) 80 | } 81 | RequestType.SEND_SDP -> { 82 | 83 | } 84 | RequestType.CREATE -> { 85 | val createRoomRequest = JsonUtils.parseJson2Bean(message, CreateRoomRequest::class.java) 86 | val roomBean = RoomBean(createRoomRequest.roomId, createRoomRequest.fromAccount) 87 | roomBean.contactList.add(Contact(createRoomRequest.fromAccount)) 88 | roomBean.roomSize = 1 89 | roomBean.roomName = "第${RoomManager.getRoomTotalCount() + 1}个房间" 90 | RoomManager.addRoom(roomBean) 91 | val response = CreateRoomResponse(createRoomRequest.roomId, createRoomRequest.fromAccount, roomBean) 92 | MessageManager.send(response) 93 | } 94 | RequestType.INVITE -> { 95 | MessageManager.send(baseRequest.toAccount, msgType, message) 96 | } 97 | RequestType.CANCEL -> { 98 | RoomManager.removeRoom(baseRequest.roomId) 99 | MessageManager.send(baseRequest.toAccount, msgType, message) 100 | } 101 | RequestType.RING -> { 102 | MessageManager.send(baseRequest.toAccount, msgType, message) 103 | } 104 | RequestType.REJECT -> { 105 | RoomManager.removeRoom(baseRequest.roomId) 106 | MessageManager.send(baseRequest.toAccount, msgType, message) 107 | } 108 | RequestType.JOIN -> { 109 | val roomBean = RoomManager.getRoom(baseRequest.roomId) 110 | roomBean?.contactList?.let { 111 | if (!it.contains(Contact(baseRequest.fromAccount))) { 112 | it.add(Contact(baseRequest.fromAccount))//此时的fromAccount指的是被叫方,因为是JOIN只能是被叫方发来的消息 113 | } 114 | } 115 | 116 | //将被叫方加入房间成功的消息,分别发送给主叫方和被叫方 117 | val joinSuccessResponseMsg = JsonUtils.parseBean2json( 118 | JoinSuccessResponse( 119 | baseRequest.roomId, 120 | baseRequest.toAccount, 121 | baseRequest.fromAccount 122 | ) 123 | ) 124 | MessageManager.send(baseRequest.fromAccount, msgType, joinSuccessResponseMsg)//给被叫方发消息 125 | MessageManager.send(baseRequest.toAccount, msgType, joinSuccessResponseMsg)//给主叫方发消息 126 | } 127 | RequestType.SDP_OFFER -> { 128 | MessageManager.send(baseRequest.toAccount, msgType, message) 129 | } 130 | RequestType.SDP_ANSWER -> { 131 | MessageManager.send(baseRequest.toAccount, msgType, message) 132 | } 133 | RequestType.CANDIDATE -> { 134 | MessageManager.send(baseRequest.toAccount, msgType, message) 135 | } 136 | RequestType.REMOVE_CANDIDATES -> { 137 | MessageManager.send(baseRequest.toAccount, msgType, message) 138 | } 139 | RequestType.LEAVE -> { 140 | RoomManager.removeRoom(baseRequest.roomId) 141 | MessageManager.send(baseRequest.toAccount, msgType, message) 142 | } 143 | } 144 | } 145 | 146 | 147 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/Contact.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean 2 | 3 | data class Contact(val account: String){ 4 | 5 | override fun hashCode(): Int { 6 | return account.hashCode() 7 | } 8 | 9 | override fun equals(other: Any?): Boolean { 10 | if (this === other) return true 11 | if (javaClass != other?.javaClass) return false 12 | 13 | other as Contact 14 | 15 | if (account != other.account) return false 16 | 17 | return true 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/RequestMsgBean.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean 2 | 3 | data class RequestMsgBean(val msgType: String,val fromAccount:String) -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/ResponseMsgBean.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean 2 | 3 | data class ResponseMsgBean( 4 | val msgType: String, 5 | val contact: Contact, 6 | val allContactList: MutableList 7 | ) 8 | 9 | -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/RoomBean.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean 2 | 3 | data class RoomBean(val roomId: String,val creatorAccount:String) { 4 | var roomName: String = "" 5 | var roomSize: Int = 0 6 | val contactList: MutableList = mutableListOf() 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/SdpBean.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean 2 | 3 | data class SdpBean(val description:String) -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/api/AllRoomListResponse.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean.api 2 | 3 | import com.example.learnspring.bean.RoomBean 4 | import com.example.learnspring.bean.api.base.BaseApiResponse 5 | 6 | /** 7 | * @author 崔兴旺 8 | * @description 9 | * @date 2021/6/27 12:16 10 | */ 11 | class AllRoomListResponse(data: MutableList) : BaseApiResponse>(data) { 12 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/api/ApiController.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean.api 2 | 3 | import com.example.learnspring.manager.ContactManager 4 | import com.example.learnspring.manager.RoomManager 5 | import com.example.learnspring.utils.JsonUtils 6 | import org.springframework.web.bind.annotation.RequestMapping 7 | import org.springframework.web.bind.annotation.RestController 8 | 9 | /** 10 | * @author 崔兴旺 11 | * @description 12 | * @date 2021/6/27 12:11 13 | */ 14 | @RestController 15 | @RequestMapping("/api") 16 | class ApiController { 17 | 18 | @RequestMapping(value = ["get-room-list"], produces = ["application/json;charset=UTF-8"]) 19 | fun getRoomList(): String { 20 | return JsonUtils.parseBean2json(AllRoomListResponse(RoomManager.getAllRoomList())) 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/api/base/BaseApiResponse.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean.api.base 2 | 3 | /** 4 | * @author 崔兴旺 5 | * @description 6 | * @date 2021/6/27 12:15 7 | */ 8 | open class BaseApiResponse(val data:Data,val code:Int=0, val msg:String="success") { 9 | 10 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/request/BaseRequest.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean.request 2 | 3 | 4 | open class BaseRequest(val msgType: String="", val roomId:String="",val fromAccount: String,val toAccount: String = "", val data: Data? = null) -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/request/CreateRoomRequest.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean.request 2 | 3 | class CreateRoomRequest(msgType: String = "", roomId: String = "", fromAccount: String, toAccount: String = "", data: Any? = null) : BaseRequest(msgType, roomId, fromAccount, toAccount, data) -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/response/AddContactResponse.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean.response 2 | 3 | import com.example.learnspring.bean.Contact 4 | import com.example.learnspring.constant.ResponseType 5 | 6 | 7 | class AddContactResponse(toAccount:String,contact: Contact) : BaseResponse(ResponseType.ADD_CONTACT,toAccount=toAccount,data = contact) { 8 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/response/AllContactResponse.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean.response 2 | 3 | import com.example.learnspring.bean.Contact 4 | import com.example.learnspring.constant.ResponseType 5 | 6 | class AllContactResponse(toAccount:String, list: MutableList) : BaseResponse(ResponseType.ALL_CONTACT,toAccount=toAccount,data = list) -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/response/BaseResponse.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean.response 2 | 3 | open class BaseResponse(val msgType: String,val roomId:String="", val fromAccount: String = "", val toAccount: String, val data: Any? = null) { 4 | 5 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/response/CreateRoomResponse.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean.response 2 | 3 | import com.example.learnspring.bean.RoomBean 4 | import com.example.learnspring.constant.ResponseType 5 | 6 | class CreateRoomResponse(roomId:String,toAccount:String,roomBean:RoomBean) : BaseResponse(ResponseType.CREATE_SUCCESS,roomId=roomId,toAccount=toAccount,data = roomBean){ 7 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/response/JoinSuccessResponse.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean.response 2 | 3 | import com.example.learnspring.constant.ResponseType 4 | 5 | class JoinSuccessResponse(roomId: String, fromAccount: String, toAccount: String) : 6 | BaseResponse(ResponseType.JOIN_SUCCESS, roomId, fromAccount, toAccount) { 7 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/bean/response/RemoveContactResponse.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.bean.response 2 | 3 | import com.example.learnspring.bean.Contact 4 | import com.example.learnspring.constant.ResponseType 5 | 6 | class RemoveContactResponse(toAccount: String, contact: Contact) : BaseResponse(ResponseType.REMOVE_CONTACT, toAccount = toAccount, data = contact) -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/constant/RRType.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.constant 2 | 3 | class RequestType { 4 | companion object { 5 | const val All_CONTACT: String = "All_CONTACT" 6 | const val SEND_SDP: String = "SEND_SDP" 7 | 8 | const val CREATE: String = "CREATE" 9 | const val INVITE: String = "INVITE" 10 | const val CANCEL: String = "CANCEL" 11 | const val JOIN: String = "JOIN" 12 | const val RING: String = "RING" 13 | const val REJECT: String = "REJECT" 14 | const val SDP_OFFER: String = "SDP_OFFER" 15 | const val SDP_ANSWER: String = "SDP_ANSWER" 16 | const val CANDIDATE: String = "CANDIDATE" 17 | const val REMOVE_CANDIDATES: String = "REMOVE_CANDIDATES" 18 | const val LEAVE: String = "LEAVE" 19 | } 20 | } 21 | 22 | class ResponseType { 23 | companion object { 24 | const val ALL_CONTACT: String = "ALL_CONTACT" 25 | const val ADD_CONTACT: String = "ADD_CONTACT" 26 | const val REMOVE_CONTACT: String = "REMOVE_CONTACT" 27 | const val CREATE_SUCCESS: String = "CREATE_SUCCESS" 28 | const val PEERS: String = "PEERS" 29 | const val INVITE: String = "INVITE"//无需定义此常量,因为服务器不处理业务,而是直接转发 30 | const val CANCEL: String = "CANCEL"//无需定义此常量,因为服务器不处理业务,而是直接转发 31 | const val RING: String = "RING"//无需定义此常量,因为服务器不处理业务,而是直接转发 32 | const val REJECT: String = "REJECT"//无需定义此常量,因为服务器不处理业务,而是直接转发 33 | const val JOIN_SUCCESS: String = "JOIN_SUCCESS" 34 | const val SDP_OFFER: String = "SDP_OFFER"//无需定义此常量,因为服务器不处理业务,而是直接转发 35 | const val SDP_ANSWER: String = "SDP_ANSWER"//无需定义此常量,因为服务器不处理业务,而是直接转发 36 | const val CANDIDATE: String = "CANDIDATE"//无需定义此常量,因为服务器不处理业务,而是直接转发 37 | const val REMOVE_CANDIDATES: String = "REMOVE_CANDIDATES"//无需定义此常量,因为服务器不处理业务,而是直接转发 38 | const val LEAVE: String = "LEAVE"//无需定义此常量,因为服务器不处理业务,而是直接转发 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/controller/TestController.java: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.controller; 2 | 3 | import com.example.learnspring.bean.RoomBean; 4 | import com.example.learnspring.manager.RoomManager; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | import org.springframework.web.servlet.ModelAndView; 9 | 10 | import java.util.List; 11 | 12 | @Controller 13 | @RequestMapping("/api") 14 | public class TestController { 15 | // 通过 http://127.0.0.1:8081/index 访问 16 | @RequestMapping("/index") 17 | public String showIndex() { 18 | return "index"; 19 | } 20 | 21 | // 通过 http://127.0.0.1:8081/ 访问 22 | @RequestMapping("/showIndex") 23 | public ModelAndView indexTwo() { 24 | return new ModelAndView("index"); 25 | } 26 | 27 | // 通过 http://127.0.0.1:8081/ 访问 28 | @RequestMapping("/get-room-list") 29 | @ResponseBody 30 | public List roomList() { 31 | return RoomManager.INSTANCE.getAllRoomList(); 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/manager/ContactManager.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.manager 2 | 3 | import com.example.learnspring.bean.Contact 4 | 5 | object ContactManager { 6 | private val contactMap: MutableMap = mutableMapOf() 7 | 8 | fun addContact(account: String, contact: Contact) { 9 | contactMap[account] = contact 10 | } 11 | 12 | fun removeContact(account: String) { 13 | contactMap.remove(account) 14 | } 15 | 16 | fun getContact(account: String): Contact? { 17 | return contactMap[account] 18 | } 19 | 20 | 21 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/manager/MessageManager.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.manager 2 | 3 | import com.example.learnspring.bean.response.BaseResponse 4 | import com.example.learnspring.utils.JsonUtils 5 | 6 | object MessageManager { 7 | fun send(response: BaseResponse) { 8 | val json = JsonUtils.parseBean2json(response) 9 | println("服务器给${response.toAccount}发送的消息,msgType:${response.msgType},内容:${json}") 10 | SessionManager.getSession(response.toAccount)?.asyncRemote?.sendText(json) 11 | } 12 | fun send(toAccount:String,msgType:String,json: String) { 13 | println("服务器给${toAccount}发送的消息,msgType:${msgType},内容:${json}") 14 | SessionManager.getSession(toAccount)?.asyncRemote?.sendText(json) 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/manager/RoomManager.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.manager 2 | 3 | import com.example.learnspring.bean.RoomBean 4 | 5 | object RoomManager { 6 | private val roomMap = mutableMapOf() 7 | 8 | 9 | fun addRoom(roomBean: RoomBean) { 10 | roomMap[roomBean.roomId] = roomBean 11 | } 12 | 13 | fun removeRoom(roomId: String) { 14 | getRoom(roomId)?.let { 15 | it.contactList.clear() 16 | roomMap.remove(roomId) 17 | } 18 | } 19 | 20 | fun getRoom(roomId: String): RoomBean? { 21 | return roomMap[roomId] 22 | } 23 | 24 | fun getAllRoomList(): MutableList { 25 | return roomMap.map { 26 | it.value 27 | }.toMutableList() 28 | } 29 | 30 | fun getRoomTotalCount():Int{ 31 | return roomMap.size 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/manager/SessionManager.kt: -------------------------------------------------------------------------------- 1 | package com.example.learnspring.manager 2 | 3 | import javax.websocket.Session 4 | 5 | object SessionManager { 6 | 7 | val sessionMap: LinkedHashMap = LinkedHashMap() 8 | 9 | fun addSession(account: String, session: Session) { 10 | sessionMap.put(account, session) 11 | } 12 | 13 | fun removeSession(account: String) { 14 | sessionMap.remove(account) 15 | } 16 | 17 | fun getSession(account: String): Session? { 18 | return sessionMap[account] 19 | } 20 | 21 | 22 | } -------------------------------------------------------------------------------- /src/main/java/com/example/learnspring/utils/JsonUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.example.learnspring.utils; 5 | 6 | 7 | import com.google.gson.Gson; 8 | import com.google.gson.GsonBuilder; 9 | import com.google.gson.JsonArray; 10 | import com.google.gson.JsonDeserializationContext; 11 | import com.google.gson.JsonDeserializer; 12 | import com.google.gson.JsonElement; 13 | import com.google.gson.JsonParseException; 14 | import com.google.gson.JsonParser; 15 | import com.google.gson.JsonPrimitive; 16 | import com.google.gson.JsonSerializationContext; 17 | import com.google.gson.JsonSerializer; 18 | import com.google.gson.JsonSyntaxException; 19 | import com.google.gson.TypeAdapter; 20 | import com.google.gson.stream.JsonReader; 21 | import com.google.gson.stream.JsonToken; 22 | import com.google.gson.stream.JsonWriter; 23 | 24 | import org.json.JSONArray; 25 | import org.json.JSONException; 26 | import org.json.JSONObject; 27 | 28 | import java.io.IOException; 29 | import java.lang.reflect.Type; 30 | import java.util.ArrayList; 31 | import java.util.HashMap; 32 | import java.util.Iterator; 33 | import java.util.List; 34 | import java.util.Map; 35 | 36 | /** 37 | * 功能: json解析类 38 | * 作者: 崔兴旺 39 | * 日期: 2019/4/9 40 | */ 41 | public class JsonUtils { 42 | private static Gson gson; 43 | 44 | static class DoubleDefault0Adapter implements JsonSerializer, JsonDeserializer { 45 | @Override 46 | public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 47 | try { 48 | if (json.getAsString().equals("") || json.getAsString().equals("null")) {//定义为double类型,如果后台返回""或者null,则返回0.00 49 | return 0.00; 50 | } 51 | } catch (Exception ignore) { 52 | } 53 | try { 54 | return json.getAsDouble(); 55 | } catch (NumberFormatException e) { 56 | throw new JsonSyntaxException(e); 57 | } 58 | } 59 | 60 | @Override 61 | public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) { 62 | return new JsonPrimitive(src); 63 | } 64 | } 65 | 66 | static class IntegerDefault0Adapter implements JsonSerializer, JsonDeserializer { 67 | @Override 68 | public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext 69 | context) 70 | throws JsonParseException { 71 | try { 72 | if (json.getAsString().equals("") || json.getAsString().equals("null")) {//定义为int类型,如果后台返回""或者null,则返回0 73 | return 0; 74 | } 75 | } catch (Exception ignore) { 76 | } 77 | try { 78 | return json.getAsInt(); 79 | } catch (NumberFormatException e) { 80 | throw new JsonSyntaxException(e); 81 | } 82 | } 83 | 84 | @Override 85 | public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) { 86 | return new JsonPrimitive(src); 87 | } 88 | } 89 | 90 | 91 | static class LongDefault0Adapter implements JsonSerializer, JsonDeserializer { 92 | @Override 93 | public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 94 | throws JsonParseException { 95 | try { 96 | if (json.getAsString().equals("") || json.getAsString().equals("null")) {//定义为long类型,如果后台返回""或者null,则返回0 97 | return 0L; 98 | } 99 | } catch (Exception ignore) { 100 | } 101 | try { 102 | return json.getAsLong(); 103 | } catch (NumberFormatException e) { 104 | throw new JsonSyntaxException(e); 105 | } 106 | } 107 | 108 | @Override 109 | public JsonElement serialize(Long src, Type typeOfSrc, JsonSerializationContext context) { 110 | return new JsonPrimitive(src); 111 | } 112 | } 113 | 114 | public static Gson getGson() { 115 | if (gson == null) { 116 | GsonBuilder gsonBuilder = new GsonBuilder(); 117 | gsonBuilder.serializeNulls(); 118 | TypeAdapter stringTypeAdapter = new TypeAdapter() { 119 | public String read(JsonReader reader) throws IOException { 120 | if (reader.peek() == JsonToken.NULL) { 121 | reader.nextNull(); 122 | return ""; 123 | } 124 | return reader.nextString(); 125 | } 126 | 127 | public void write(JsonWriter writer, String value) throws IOException { 128 | if (value == null) { 129 | // 在这里处理null改为空字符串 130 | writer.value(""); 131 | return; 132 | } 133 | writer.value(value); 134 | } 135 | }; 136 | //注册自定义String的适配器 137 | gsonBuilder.registerTypeAdapter(String.class, stringTypeAdapter) 138 | .registerTypeAdapter(Double.class, new DoubleDefault0Adapter()) 139 | .registerTypeAdapter(double.class, new DoubleDefault0Adapter()) 140 | .registerTypeAdapter(Integer.class, new IntegerDefault0Adapter()) 141 | .registerTypeAdapter(int.class, new IntegerDefault0Adapter()) 142 | .registerTypeAdapter(Long.class, new LongDefault0Adapter()) 143 | .registerTypeAdapter(long.class, new LongDefault0Adapter()) 144 | ; 145 | gson = gsonBuilder.create(); 146 | } 147 | return gson; 148 | } 149 | 150 | public static Object parseMapIterabletoJSON(Object object) throws JSONException { 151 | if (object instanceof Map) { 152 | JSONObject json = new JSONObject(); 153 | Map map = (Map) object; 154 | for (Object key : map.keySet()) { 155 | json.put(key.toString(), parseMapIterabletoJSON(map.get(key))); 156 | } 157 | return json; 158 | } else if (object instanceof Iterable) { 159 | JSONArray json = new JSONArray(); 160 | for (Object value : ((Iterable) object)) { 161 | json.put(value); 162 | } 163 | return json; 164 | } else { 165 | return object; 166 | } 167 | } 168 | 169 | public static String parseBean2json(Object obj) { 170 | return getGson().toJson(obj); 171 | } 172 | 173 | public static boolean isEmptyObject(JSONObject object) { 174 | return object.names() == null; 175 | } 176 | 177 | public static Map getMap(JSONObject object, String key) throws 178 | JSONException { 179 | return toMap(object.getJSONObject(key)); 180 | } 181 | 182 | public static Map toMap(JSONObject object) 183 | throws JSONException { 184 | 185 | Map map = new HashMap(); 186 | Iterator keys = object.keys(); 187 | while (keys.hasNext()) { 188 | String key = (String) keys.next(); 189 | map.put(key, fromJson(object.get(key))); 190 | } 191 | return map; 192 | } 193 | 194 | public static Map parseMap(JSONObject object) throws JSONException { 195 | Map map = new HashMap(); 196 | Iterator keys = object.keys(); 197 | while (keys.hasNext()) { 198 | String key = (String) keys.next(); 199 | map.put(key, fromJson(object.get(key)).toString()); 200 | } 201 | return map; 202 | } 203 | 204 | public static List toList(JSONArray array) throws JSONException { 205 | List list = new ArrayList(); 206 | for (int i = 0; i < array.length(); i++) { 207 | list.add(fromJson(array.get(i))); 208 | } 209 | return list; 210 | } 211 | 212 | private static Object fromJson(Object json) throws JSONException { 213 | if (json == JSONObject.NULL) { 214 | return null; 215 | } else if (json instanceof JSONObject) { 216 | return toMap((JSONObject) json); 217 | } else if (json instanceof JSONArray) { 218 | return toList((JSONArray) json); 219 | } else { 220 | return json; 221 | } 222 | } 223 | 224 | public static < 225 | T> List parseRootJson2List(String json, Class clazz, String listKey) throws 226 | JSONException { 227 | return parseJson2List(new JSONObject(json).getJSONObject("data").getJSONArray(listKey).toString(), clazz); 228 | } 229 | 230 | public static List parseRootJson2List(String json, Class clazz) throws 231 | JSONException { 232 | return parseJson2List(new JSONObject(json).getJSONArray("data").toString(), clazz); 233 | } 234 | 235 | public static List parseJson2List(String json, Class clazz) throws 236 | JSONException { 237 | List list = null; 238 | try { 239 | list = new ArrayList<>(); 240 | if ("".equals(json)) { 241 | return list; 242 | } 243 | 244 | JsonArray array = new JsonParser().parse(json).getAsJsonArray(); 245 | for (JsonElement element : array) { 246 | list.add(getGson().fromJson(element, clazz)); 247 | } 248 | } catch (JsonSyntaxException e) { 249 | throw new JSONException(e.getMessage()); 250 | } 251 | return list; 252 | } 253 | 254 | public static List parseJson2List(String json, Type type) throws JSONException { 255 | try { 256 | List list = new ArrayList<>(); 257 | if ("".equals(json)) { 258 | return list; 259 | } 260 | 261 | JsonArray array = new JsonParser().parse(json).getAsJsonArray(); 262 | for (JsonElement element : array) { 263 | T t = getGson().fromJson(element, type); 264 | list.add(t); 265 | } 266 | return list; 267 | } catch (JsonSyntaxException e) { 268 | throw new JSONException(e.getMessage()); 269 | } 270 | } 271 | 272 | 273 | public static T parseJson2Bean(String json, Class clazz) throws JSONException { 274 | try { 275 | return getGson().fromJson(json, clazz); 276 | } catch (JsonSyntaxException e) { 277 | throw new JSONException(e.getMessage()); 278 | } 279 | } 280 | 281 | public static T parseRootJson2Bean(String json, Class clazz) throws JSONException { 282 | try { 283 | return getGson().fromJson(new JSONObject(json).getJSONObject("data").toString(), clazz); 284 | } catch (JsonSyntaxException | JSONException e) { 285 | throw new JSONException(e.getMessage()); 286 | } 287 | } 288 | 289 | public static T parseRootJson2Bean(String json, Class clazz, String obj_key) throws 290 | JSONException { 291 | try { 292 | return getGson().fromJson(new JSONObject(json).getJSONObject("data").getJSONObject(obj_key).toString(), clazz); 293 | } catch (JsonSyntaxException | JSONException e) { 294 | throw new JSONException(e.getMessage()); 295 | } 296 | } 297 | 298 | public static T parseJson2Bean(String json, Type type) throws JSONException { 299 | try { 300 | return getGson().fromJson(json, type); 301 | } catch (JsonSyntaxException e) { 302 | throw new JSONException(e.getMessage()); 303 | } 304 | } 305 | 306 | public static String parseMap2String(Map map) throws JSONException { 307 | try { 308 | return getGson().toJson(map); 309 | } catch (Exception e) { 310 | throw new JSONException(e.getMessage()); 311 | } 312 | } 313 | 314 | public static T parseMap2Bean(Map map, Class clazz) throws 315 | JSONException { 316 | try { 317 | return getGson().fromJson(getGson().toJson(map), clazz); 318 | } catch (JsonSyntaxException e) { 319 | throw new JSONException(e.getMessage()); 320 | } 321 | } 322 | 323 | /** 324 | * 用来兼容Android4.4以下版本的remove方法 325 | * 326 | * @param jsonArray 327 | * @param index 328 | * @return 329 | */ 330 | public static JSONArray removeCompatibilityKITKAT(JSONArray jsonArray, int index) throws 331 | JSONException { 332 | JSONArray mJsonArray = null; 333 | try { 334 | mJsonArray = new JSONArray(); 335 | if (index < 0) 336 | return mJsonArray; 337 | if (index > jsonArray.length()) 338 | return mJsonArray; 339 | for (int i = 0; i < jsonArray.length(); i++) { 340 | if (i != index) { 341 | mJsonArray.put(jsonArray.getJSONObject(i)); 342 | } 343 | } 344 | } catch (JSONException e) { 345 | throw new JSONException(e.getMessage()); 346 | } 347 | return mJsonArray; 348 | } 349 | } 350 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # 项目启动端口 2 | server.port=5001 3 | 4 | # 数据库连接参数 5 | spring.datasource.url=jdbc:mysql://lawdb.pyforce.top/lawpopu?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai 6 | # mysql驱动已更新为如下 7 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 8 | spring.datasource.username=xx 9 | spring.datasource.password=xxxx 10 | 11 | # 相对于你刚才设置的web资源目录,这里是webapp 12 | spring.mvc.view.prefix=/ 13 | #返回.jsp格式 14 | spring.mvc.view.suffix=.jsp -------------------------------------------------------------------------------- /src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | Created by IntelliJ IDEA. 3 | User: Administrator 4 | Date: 2021/6/18 0018 5 | Time: 11:59 6 | To change this template use File | Settings | File Templates. 7 | --%> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | 10 | 11 | Title 12 | 13 | 14 | hello spring boot 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/test/java/com/example/learnspring/LearnSpringApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.learnspring; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class LearnSpringApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------