From f7f1a40d566dff79621252e7ad6728a9a060b41a Mon Sep 17 00:00:00 2001 From: wangbing Date: Mon, 26 Apr 2021 16:29:04 +0800 Subject: [PATCH] init --- pom.xml | 73 +++++++++++ .../xyz/wbsite/TestWebsocketApplication.java | 15 +++ .../xyz/wbsite/config/WebSocketConfig.java | 14 +++ .../wbsite/controller/IndexController.java | 20 +++ .../xyz/wbsite/endpoint/WebSocketManager.java | 115 ++++++++++++++++++ src/main/java/xyz/wbsite/test/Test.java | 55 +++++++++ .../java/xyz/wbsite/utils/StringUtils.java | 24 ++++ src/main/resources/application.properties | 18 +++ src/main/resources/templates/index.ftl | 42 +++++++ 9 files changed, 376 insertions(+) create mode 100644 pom.xml create mode 100644 src/main/java/xyz/wbsite/TestWebsocketApplication.java create mode 100644 src/main/java/xyz/wbsite/config/WebSocketConfig.java create mode 100644 src/main/java/xyz/wbsite/controller/IndexController.java create mode 100644 src/main/java/xyz/wbsite/endpoint/WebSocketManager.java create mode 100644 src/main/java/xyz/wbsite/test/Test.java create mode 100644 src/main/java/xyz/wbsite/utils/StringUtils.java create mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/templates/index.ftl diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..119545f --- /dev/null +++ b/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.2.RELEASE + + + xyz.wbsite + test-websocket + 0.0.1-SNAPSHOT + test-websocket + Demo project for Spring Boot + + 1.8 + + + + + central + Central Repository + default + https://maven.aliyun.com/repository/public + + + + + + central + Central Repository + https://maven.aliyun.com/repository/public + default + + + + + org.springframework.boot + spring-boot-starter-freemarker + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-websocket + + + + com.squareup.okhttp3 + okhttp + 3.6.0 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/src/main/java/xyz/wbsite/TestWebsocketApplication.java b/src/main/java/xyz/wbsite/TestWebsocketApplication.java new file mode 100644 index 0000000..bd2ec45 --- /dev/null +++ b/src/main/java/xyz/wbsite/TestWebsocketApplication.java @@ -0,0 +1,15 @@ +package xyz.wbsite; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +@SpringBootApplication +@EnableScheduling +public class TestWebsocketApplication { + + public static void main(String[] args) { + SpringApplication.run(TestWebsocketApplication.class, args); + } + +} diff --git a/src/main/java/xyz/wbsite/config/WebSocketConfig.java b/src/main/java/xyz/wbsite/config/WebSocketConfig.java new file mode 100644 index 0000000..4aa6520 --- /dev/null +++ b/src/main/java/xyz/wbsite/config/WebSocketConfig.java @@ -0,0 +1,14 @@ +package xyz.wbsite.config; + + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +@Configuration +public class WebSocketConfig { + @Bean + public ServerEndpointExporter serverEndpointExporter() { + return new ServerEndpointExporter(); + } +} diff --git a/src/main/java/xyz/wbsite/controller/IndexController.java b/src/main/java/xyz/wbsite/controller/IndexController.java new file mode 100644 index 0000000..bdb329e --- /dev/null +++ b/src/main/java/xyz/wbsite/controller/IndexController.java @@ -0,0 +1,20 @@ +package xyz.wbsite.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@Controller +public class IndexController { + + @RequestMapping("/") + public String text(ModelMap map, HttpServletRequest request, HttpServletResponse response) { + map.put("name","张三"); + return "index"; + } +} diff --git a/src/main/java/xyz/wbsite/endpoint/WebSocketManager.java b/src/main/java/xyz/wbsite/endpoint/WebSocketManager.java new file mode 100644 index 0000000..5478d84 --- /dev/null +++ b/src/main/java/xyz/wbsite/endpoint/WebSocketManager.java @@ -0,0 +1,115 @@ +package xyz.wbsite.endpoint; + +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Controller; + +import javax.websocket.CloseReason; +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.ConcurrentHashMap; + +@ServerEndpoint("/websocket/{userId}") +@Controller +public class WebSocketManager { + + static Log log = LogFactory.getLog(WebSocketManager.class); + + /** + * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 + */ + private static ConcurrentHashMap keySessionMap = new ConcurrentHashMap<>(); + private static ConcurrentHashMap hashKeyMap = new ConcurrentHashMap<>(); + + /** + * 连接建立成功调用的方法 + */ + @OnOpen + public void onOpen(Session session, @PathParam("userId") String userId) { + // 移除并关闭旧会话 + if (keySessionMap.containsKey(userId)) { + Session remove = keySessionMap.remove(userId); + hashKeyMap.remove(remove.hashCode()); + try { + remove.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + keySessionMap.put(userId, session); + hashKeyMap.put(session.hashCode(), userId); + + log.info("用户连接:" + userId + ",当前在线人数为:" + keySessionMap.size()); + + sendMessage(userId, "连接成功"); + } + + /** + * 连接关闭调用的方法 + */ + @OnClose + public void onClose(Session session) { + if (hashKeyMap.containsKey(session.hashCode())) { + String userId = hashKeyMap.remove(session.hashCode()); + keySessionMap.remove(userId); + log.info("用户退出:" + userId); + } + } + + /** + * 收到客户端消息后调用的方法 + * + * @param message 客户端发送过来的消息 + */ + @OnMessage + public void onMessage(String message, Session session) { + log.info("收到客户端消息:" + message); + } + + /** + * 发生错误移除会话 + * + * @param session + * @param error + */ + @OnError + public void onError(Session session, Throwable error) { + error.printStackTrace(); + if (hashKeyMap.containsKey(session.hashCode())) { + String userId = hashKeyMap.remove(session.hashCode()); + keySessionMap.remove(userId); + log.error("用户错误:" + userId + ",原因:" + error.getMessage()); + } + } + + /** + * 实现服务器主动推送 + */ + public void sendMessage(String userId, String message) { + Session session = keySessionMap.get(userId); + if (session == null) { + return; + } + try { + session.getBasicRemote().sendText(message); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Scheduled(fixedDelay = 3 * 1000) + public void sendTask() { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + sendMessage("1", simpleDateFormat.format(new Date())); + } +} diff --git a/src/main/java/xyz/wbsite/test/Test.java b/src/main/java/xyz/wbsite/test/Test.java new file mode 100644 index 0000000..25f4f7d --- /dev/null +++ b/src/main/java/xyz/wbsite/test/Test.java @@ -0,0 +1,55 @@ +package xyz.wbsite.test; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.WebSocket; +import okhttp3.WebSocketListener; +import okio.ByteString; + +public class Test { + public static void main(String[] args) { + final WebSocket[] socket = new WebSocket[1]; + OkHttpClient mOkHttpClient = new OkHttpClient.Builder() + .retryOnConnectionFailure(true) + .build(); + + Request mRequest = new Request.Builder() + .url("ws://127.0.0.1:8080/websocket/1") + .build(); + + mOkHttpClient.newWebSocket(mRequest, new WebSocketListener() { + @Override + public void onOpen(WebSocket webSocket, Response response) { + socket[0] = webSocket; + System.out.println("连接已打开"); + } + + @Override + public void onMessage(WebSocket webSocket, String text) { + System.out.println("接收消息:" + text); + socket[0].send("收到消息"); + } + + @Override + public void onMessage(WebSocket webSocket, ByteString bytes) { + super.onMessage(webSocket, bytes); + } + + @Override + public void onClosing(WebSocket webSocket, int code, String reason) { + System.out.println("连接关闭"); + } + + @Override + public void onClosed(WebSocket webSocket, int code, String reason) { + System.out.println("连接关闭"); + } + + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + System.out.println("连接失败"); + } + }); + } +} diff --git a/src/main/java/xyz/wbsite/utils/StringUtils.java b/src/main/java/xyz/wbsite/utils/StringUtils.java new file mode 100644 index 0000000..0181a77 --- /dev/null +++ b/src/main/java/xyz/wbsite/utils/StringUtils.java @@ -0,0 +1,24 @@ +package xyz.wbsite.utils; + + +public class StringUtils { + + public static boolean isNull(String str) { + return str == null; + } + + public static boolean isNotNull(String str) { + return !isNull(str); + } + + public static boolean isBlank(String str) { + + return str != null && "".equals(str); + } + + + public static boolean isNotBlank(String str) { + return !isBlank(str); + } + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..ea229c3 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,18 @@ +spring.freemarker.suffix=.ftl +spring.freemarker.enabled=true +spring.freemarker.allow-request-override=false +spring.freemarker.cache=true +spring.freemarker.check-template-location=true +spring.freemarker.charset=UTF-8 +spring.freemarker.content-type=text/html +spring.freemarker.expose-request-attributes=false +spring.freemarker.expose-session-attributes=false +spring.freemarker.expose-spring-macro-helpers=false +spring.freemarker.settings.template_update_delay=1 +spring.freemarker.settings.locale=zh_CN +spring.freemarker.settings.datetime_format=yyyy-MM-dd HH:mm:ss +spring.freemarker.settings.date_format=yyyy-MM-dd +spring.freemarker.settings.number_format=#.## +spring.freemarker.settings.classic_compatible=true +spring.freemarker.settings.whitespace_stripping=true +spring.freemarker.settings.url_escaping_charset=utf-8 \ No newline at end of file diff --git a/src/main/resources/templates/index.ftl b/src/main/resources/templates/index.ftl new file mode 100644 index 0000000..30c2aea --- /dev/null +++ b/src/main/resources/templates/index.ftl @@ -0,0 +1,42 @@ + + + + + + + +
+ + +