├── .gitignore ├── README.md ├── deploy.bat ├── deploy.sh ├── pom.xml └── src └── main ├── java └── com │ └── javashitang │ ├── WebSocketApplication.java │ ├── config │ └── WebSocketConfig.java │ └── controller │ ├── GroupChatController.java │ ├── ShowTopController.java │ ├── ViewController.java │ └── WebSocketServerController.java └── resources ├── application.yml ├── log4j2.xml └── templates ├── demo.html └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | /*.iml 2 | /target 3 | /.idea 4 | /.mvn 5 | /server_log 6 | /mvnw 7 | /mvnw.cmd 8 | /logs -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## WebSocket 使用指南 2 | 3 | 介绍博客:https://blog.csdn.net/zzti_erlie/article/details/101060892 4 | 5 | 在线开房:http://www.javashitang.com:8090/ 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /deploy.bat: -------------------------------------------------------------------------------- 1 | call clean package -DskipTests 2 | cd ./target 3 | scp spring-boot-websocket-1.0.jar root@www.javashitang.com:/opt/application/group-chat 4 | cd .. 5 | @pause 6 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | mvn clean package -DskipTests 2 | cd ./target 3 | scp spring-boot-websocket-1.0.jar root@www.javashitang.com:/opt/application/group-chat 4 | cd .. 5 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.1.RELEASE 9 | 10 | 11 | 12 | com.javashitang 13 | spring-boot-websocket 14 | 1.0 15 | jar 16 | spring-boot-websocket 17 | spring-boot-websocket 18 | 19 | 20 | 1.8 21 | 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-logging 32 | 33 | 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-log4j2 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-websocket 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-thymeleaf 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-test 54 | test 55 | 56 | 57 | 58 | org.projectlombok 59 | lombok 60 | 1.16.18 61 | 62 | 63 | 64 | 65 | org.apache.commons 66 | commons-lang3 67 | 3.8.1 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | org.springframework.boot 76 | spring-boot-maven-plugin 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/main/java/com/javashitang/WebSocketApplication.java: -------------------------------------------------------------------------------- 1 | package com.javashitang; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class WebSocketApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(WebSocketApplication.class, args); 11 | } 12 | 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/main/java/com/javashitang/config/WebSocketConfig.java: -------------------------------------------------------------------------------- 1 | package com.javashitang.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 | @Configuration 8 | public class WebSocketConfig { 9 | 10 | @Bean 11 | public ServerEndpointExporter serverEndpointExporter() { 12 | return new ServerEndpointExporter(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/javashitang/controller/GroupChatController.java: -------------------------------------------------------------------------------- 1 | package com.javashitang.controller; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.stereotype.Component; 5 | 6 | import javax.websocket.OnClose; 7 | import javax.websocket.OnError; 8 | import javax.websocket.OnMessage; 9 | import javax.websocket.OnOpen; 10 | import javax.websocket.Session; 11 | import javax.websocket.server.PathParam; 12 | import javax.websocket.server.ServerEndpoint; 13 | import java.io.IOException; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.concurrent.ConcurrentHashMap; 17 | 18 | @Slf4j 19 | @Component 20 | @ServerEndpoint("/groupChat/{sid}/{username}") 21 | public class GroupChatController { 22 | 23 | // 保存 组id->组成员 的映射关系 24 | private static ConcurrentHashMap> groupMemberInfoMap = new ConcurrentHashMap<>(); 25 | 26 | // 收到消息调用的方法,群成员发送消息 27 | @OnMessage 28 | public void onMessage(@PathParam("sid") String sid, 29 | @PathParam("username") String username, String message) { 30 | List sessionList = groupMemberInfoMap.get(sid); 31 | // 先一个群组内的成员发送消息 32 | sessionList.forEach(item -> { 33 | try { 34 | String text = username + ": " + message; 35 | item.getBasicRemote().sendText(text); 36 | } catch (IOException e) { 37 | e.printStackTrace(); 38 | } 39 | }); 40 | } 41 | 42 | // 建立连接调用的方法,群成员加入 43 | @OnOpen 44 | public void onOpen(Session session, @PathParam("sid") String sid) { 45 | List sessionList = groupMemberInfoMap.get(sid); 46 | if (sessionList == null) { 47 | sessionList = new ArrayList<>(); 48 | groupMemberInfoMap.put(sid,sessionList); 49 | } 50 | sessionList.add(session); 51 | log.info("Connection connected"); 52 | log.info("sid: {}, sessionList size: {}", sid, sessionList.size()); 53 | } 54 | 55 | // 关闭连接调用的方法,群成员退出 56 | @OnClose 57 | public void onClose(Session session, @PathParam("sid") String sid) { 58 | List sessionList = groupMemberInfoMap.get(sid); 59 | sessionList.remove(session); 60 | log.info("Connection closed"); 61 | log.info("sid: {}, sessionList size: {}", sid, sessionList.size()); 62 | } 63 | 64 | // 传输消息错误调用的方法 65 | @OnError 66 | public void OnError(Throwable error) { 67 | log.info("Connection error"); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/javashitang/controller/ShowTopController.java: -------------------------------------------------------------------------------- 1 | package com.javashitang.controller; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | import java.util.concurrent.TimeUnit; 7 | 8 | /** 9 | * @author lilimin 10 | * @since 2021-03-06 11 | */ 12 | @RestController 13 | @RequestMapping("top") 14 | public class ShowTopController { 15 | 16 | private Object lock1 = new Object(); 17 | private Object lock2 = new Object(); 18 | 19 | @RequestMapping("test") 20 | public String test() { 21 | return "success"; 22 | } 23 | 24 | @RequestMapping("loop") 25 | public String loop() { 26 | System.out.println("start"); 27 | while (true) {} 28 | } 29 | 30 | @RequestMapping("deadlock") 31 | public String deadlock() { 32 | new Thread(() -> { 33 | synchronized (lock1) { 34 | try{ 35 | TimeUnit.SECONDS.sleep(1); 36 | } catch (Exception e) {} 37 | synchronized (lock2) { 38 | System.out.println("thread1 over"); 39 | } 40 | } 41 | }).start(); 42 | new Thread(() -> { 43 | synchronized (lock2) { 44 | try{ 45 | TimeUnit.SECONDS.sleep(1); 46 | } catch (Exception e) {} 47 | synchronized (lock1) { 48 | System.out.println("thread2 over"); 49 | } 50 | } 51 | }).start(); 52 | return "success"; 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/main/java/com/javashitang/controller/ViewController.java: -------------------------------------------------------------------------------- 1 | package com.javashitang.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | 6 | @Controller 7 | public class ViewController { 8 | 9 | @GetMapping("index") 10 | public String index() { 11 | return "index"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/javashitang/controller/WebSocketServerController.java: -------------------------------------------------------------------------------- 1 | package com.javashitang.controller; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import javax.websocket.OnClose; 6 | import javax.websocket.OnError; 7 | import javax.websocket.OnMessage; 8 | import javax.websocket.OnOpen; 9 | import javax.websocket.Session; 10 | import javax.websocket.server.PathParam; 11 | import javax.websocket.server.ServerEndpoint; 12 | import java.io.IOException; 13 | 14 | @Component 15 | @ServerEndpoint("/forshow/websocket/{sid}") 16 | public class WebSocketServerController { 17 | 18 | // 收到消息调用的方法 19 | @OnMessage 20 | public void onMessage(Session session, String message) { 21 | try { 22 | session.getBasicRemote().sendText(message); 23 | } catch (IOException e) { 24 | e.printStackTrace(); 25 | } 26 | } 27 | 28 | // 建立连接调用的方法 29 | @OnOpen 30 | public void onOpen(@PathParam("sid") String sid) { 31 | System.out.println("Client connected"); 32 | } 33 | 34 | // 关闭连接调用的方法 35 | @OnClose 36 | public void onClose() { 37 | System.out.println("Connection closed"); 38 | } 39 | 40 | // 传输消息错误调用的方法 41 | @OnError 42 | public void OnError(Throwable error) { 43 | System.out.println("Connection error"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8090 -------------------------------------------------------------------------------- /src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %d{HH:mm:ss.SSS} |-%5level %logger{20} [%t] |%X{ip} - %msg%n 8 | %d{yyyy-MM-dd HH:mm:ss.SSS} |-%5level %logger{20} [%t] %X{ip} - %msg%n 9 | %msg%n 10 | ./logs 11 | info 12 | 13 | 14 | 15 | 16 | 17 | ${stdoutPattern} 18 | 19 | 20 | 21 | 22 | ${filePattern} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/resources/templates/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Testing websockets 5 | 6 | 7 |
8 | 9 |
10 | 11 |
12 |
13 | 57 | 58 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Testing websockets 5 | 6 | 7 |
8 |
9 |
10 |
11 |
12 | 13 |
14 |
15 |
16 | 76 | 77 | --------------------------------------------------------------------------------