下面分别介绍搭建方法:
一、直接使用Java EE的api进行搭建。
一共3个步骤:
1、添加依赖
<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>7.0</version>
    <scope>provided</scope>
</dependency>
2、使用注解@ServerEndpoint
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

/**
* WebSocket连接 sessionKey是url中的参数
*/
@ServerEndpoint("/websocket/{sessionKey}")
public class WebSocket {

private static final Logger log = Logger.getLogger(WebSocket.class.getName());

//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;

//concurrent包的线程安全,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
    private static Map<String, WebSocket> webSockets = new ConcurrentHashMap<>();

//与某个客户端的连接会话,需要通过它来给客户端发送数据
    private Session session;

/**
     * 连接建立成功调用的方法
     *
     * @param session    可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
     * @param sessionKey url地址参数
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sessionKey") String sessionKey) {

if (!webSockets.containsKey(sessionKey)) {
            this.session = session;
            webSockets.put(sessionKey, this);
            addOnlineCount();
            log.info("当前websocket连接数:" + onlineCount);
        }
    }

/**
     * 连接关闭调用的方法
     *
     * @param sessionKey url地址参数
     */
    @OnClose
    public void onClose(@PathParam("sessionKey") String sessionKey) {

if (webSockets.containsKey(sessionKey)) {
            webSockets.remove(sessionKey);
            subOnlineCount();
            log.info("当前websocket连接数:" + onlineCount);
        }
    }

/**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("来自客户端的消息:" + message);
    }

/**
     * 发生错误时调用
     *
     * @param session 可选的参数
     * @param error   错误消息
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.info("websocket发生错误:" + error);
    }

/**
     * 该方法没有用注解,是根据自己需要添加的方法。在自己的业务中调用,发送消息给前端。
     *
     * @param sessionKey
     * @param message    返回的结果
     * @throws IOException
     */
    public static void sendMessage(String sessionKey, String message) throws IOException {

WebSocket webSocket = webSockets.get(sessionKey);

if (null != webSocket) {

log.info("websocket发送消息:" + message);

//同步发送 发送第二条时,必须等第一条发送完成
            webSocket.session.getBasicRemote().sendText(message);

//异步发送
            //webSocket.session.getAsyncRemote().sendText(message);
        }
    }

public static synchronized int getOnlineCount() {
        return onlineCount;
    }

public static synchronized void addOnlineCount() {
        onlineCount++;
    }

public static synchronized void subOnlineCount() {
        onlineCount--;
    }

}
3、测试
在线WebSocket测试:http://coolaf.com/tool/chattest
输入地址进行测试即可,举例:ws://localhost:8080/websocket/sessionKey
补充:也可以使用java搭建客户端程序测试,测试的例程放到后面去了~~
二、和springboot整合的WebSocket服务(功能更加强大)
看下效果:<ignore_js_op>
<ignore_js_op>

http://localhost:8080/websocket/sendToUser?username=river&info=你找我干嘛?

maven依赖如下:

maven依赖如下:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-websocket</artifactId>

<version>2.0.4.RELEASE</version>

</dependency>

1、控制类

package com.boot.river.websocket;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.socket.TextMessage;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;

@Controller

@RequestMapping(value = "/websocket", method = {RequestMethod.POST, RequestMethod.GET})/*GET请求开放用于测试,最好只允许POST请求*/

public class WebSocketController {

@Autowired

SpringWebSocketHandler springWebSocketHandler;

/**

* 登录将username放入session中,然后在拦截器HandshakeInterceptor中取出

*/

@ResponseBody

@RequestMapping("/login")

public String login(HttpServletRequest request, @RequestParam(value = "username") String username, @RequestParam(value = "password") String password) {

System.out.println("登录:" + username + ":" + password);

HttpSession session = request.getSession();

if (null != session) {

session.setAttribute("SESSION_USERNAME", username);

return "success";

} else {

return "fail";

}

}

/**

* 指定发送

*/

@ResponseBody

@RequestMapping("/sendToUser")

public String send(@RequestParam(value = "username") String username, @RequestParam(value = "info") String info) {

springWebSocketHandler.sendMessageToUser(username, new TextMessage(info));

System.out.println("发送至:" + username);

return "success";

}

/**

* 广播

*/

@ResponseBody

@RequestMapping("/broadcast")

public String broadcast(@RequestParam(value = "info") String info) {

springWebSocketHandler.sendMessageToUsers(new TextMessage("广播消息:" + info));

System.out.println("广播成功");

return "success";

}

}

2、配置类(实现WebSocketConfigurer接口 )

@Configuration

@EnableWebSocket

public class SpringWebSocketConfig implements WebSocketConfigurer {

public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

registry.addHandler(getSpringWebSocketHandler(), "/websocket/server")

.addInterceptors(getInterceptor()).setAllowedOrigins("*");

registry.addHandler(getSpringWebSocketHandler(), "/sockjs/server").setAllowedOrigins("*")

.addInterceptors(getInterceptor()).withSockJS();

}

@Bean

public SpringWebSocketHandler getSpringWebSocketHandler() {

return new SpringWebSocketHandler();

}

@Bean

public SpringWebSocketHandlerInterceptor getInterceptor() {

return new SpringWebSocketHandlerInterceptor();

}

}

3、处理类(实现了WebSocketHandler接口)

package com.boot.river.websocket;

import org.springframework.web.socket.CloseStatus;

import org.springframework.web.socket.TextMessage;

import org.springframework.web.socket.WebSocketSession;

import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

import java.util.HashMap;

import java.util.Map;

public class SpringWebSocketHandler extends TextWebSocketHandler {

/**

* 存储用户id和其对应的session

*/

private static final Map<String, WebSocketSession> users = new HashMap<>();

/**

* 用户名key值

*/

private static final String USER_ID = "WEBSOCKET_USERID";

/**

* 连接建立后触发

*/

@Override

public void afterConnectionEstablished(WebSocketSession session) {

System.out.println("成功建立websocket连接!");

String userId = (String) session.getAttributes().get(USER_ID);//取出在拦截器中存储的username

users.put(userId, session);

System.out.println("当前线上用户数量:" + users.size());

}

/**

* 关闭连接时触发

*/

@Override

public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) {

String userId = (String) session.getAttributes().get(USER_ID);

System.out.println("用户" + userId + "已退出!");

users.remove(userId);

System.out.println("剩余在线用户" + users.size());

}

/**

* 接收消息

*/

@Override

protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

super.handleTextMessage(session, message);

System.out.println("收到消息:" + message);

if (message.getPayload().contains("在吗")) {

session.sendMessage(new TextMessage("对方不在线!"));

}

}

public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {

if (session.isOpen()) {

session.close();

}

System.out.println("传输出现异常,关闭websocket连接... ");

String userId = (String) session.getAttributes().get(USER_ID);

users.remove(userId);

}

public boolean supportsPartialMessages() {

return false;

}

/**

* 给某个用户发送消息

*/

public void sendMessageToUser(String userId, TextMessage message) {

for (String id : users.keySet()) {

if (id.equals(userId)) {

try {

if (users.get(id).isOpen()) {

users.get(id).sendMessage(message);

}

} catch (IOException e) {

e.printStackTrace();

}

break;

}

}

}

/**

* 给所有在线用户发送消息

*/

public void sendMessageToUsers(TextMessage message) {

for (String userId : users.keySet()) {

try {

if (users.get(userId).isOpen()) {

users.get(userId).sendMessage(message);

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

4、拦截器(实现HandshakeInterceptor接口)

package com.boot.river.websocket;

import org.springframework.http.server.ServerHttpRequest;

import org.springframework.http.server.ServerHttpResponse;

import org.springframework.http.server.ServletServerHttpRequest;

import org.springframework.web.socket.WebSocketHandler;

import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

import javax.servlet.http.HttpSession;

import java.util.Map;

public class SpringWebSocketHandlerInterceptor extends HttpSessionHandshakeInterceptor {

@Override

public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,

Map<String, Object> attributes) throws Exception {

System.out.println("Before Handshake");

if (request instanceof ServletServerHttpRequest) {

ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;

HttpSession session = servletRequest.getServletRequest().getSession(false);//获取session时,如果没有则返回null

if (session != null) {

String userName = (String) session.getAttribute("SESSION_USERNAME");//在登录时保存的用户名

if (userName != null) {

attributes.put("WEBSOCKET_USERID", userName);//放入attributes中,可以在处理器的WebSocketSession中取出

}

}

}

return super.beforeHandshake(request, response, wsHandler, attributes);

}

@Override

public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,

Exception ex) {

super.afterHandshake(request, response, wsHandler, ex);

System.out.println("after Handshake");

}

}

参考:

https://my.oschina.net/u/3445245/blog/3003208

https://blog.csdn.net/runbat/article/details/80985944

https://docs.spring.io/spring/docs/5.0.0.BUILD-SNAPSHOT/spring-framework-reference/html/websocket.html

下面分别介绍websocket的java客户端请求和js客户端请求

1、java客户端

添加依赖:

<dependency>

<groupId>org.java-websocket</groupId>

<artifactId>Java-WebSocket</artifactId>

<version>1.4.0</version>

</dependency>

package com.river.websocket;

import org.java_websocket.enums.ReadyState;

import java.net.URISyntaxException;

/**

* @author river

* @date 2019-12-6

*/

public class Client {

public static void main(String[] args) throws URISyntaxException, InterruptedException {

MyWebSocketClient client = new MyWebSocketClient("ws://localhost:8080/websocket/server");

client.connect();

while (client.getReadyState() != ReadyState.OPEN) {

System.out.println("连接状态:" + client.getReadyState());

Thread.sleep(100);

}

client.send("测试数据!");

client.close();

}

}

继承WebsocketClient

package com.river.websocket;

import org.java_websocket.client.WebSocketClient;

import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;

import java.net.URISyntaxException;

public class MyWebSocketClient extends WebSocketClient {

MyWebSocketClient(String url) throws URISyntaxException {

super(new URI(url));

}

@Override

public void onOpen(ServerHandshake shake) {

System.out.println(shake.getHttpStatusMessage());

}

@Override

public void onMessage(String paramString) {

System.out.println(paramString);

}

@Override

public void onClose(int paramInt, String paramString, boolean paramBoolean) {

System.out.println("关闭");

}

@Override

public void onError(Exception e) {

System.out.println("发生错误");

}

}

2、js客户端

<!DOCTYPE html>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>

<title>websocket</title>

<script type="text/javascript" src="http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script>

<script type="text/javascript" src="http://cdn.bootcss.com/sockjs-client/1.1.1/sockjs.js"></script>

<script type="text/javascript">

var websocket = null;

if ('WebSocket' in window) {

websocket = new WebSocket("ws://localhost:8080/websocket/server");

} else if ('MozWebSocket' in window) {

websocket = new MozWebSocket("ws://localhost:8080/websocket/server");

} else {

websocket = new SockJS("http://localhost:8080/sockjs/server");

}

websocket.onopen = onOpen;

websocket.onmessage = onMessage;

websocket.onerror = onError;

websocket.onclose = onClose;

function onOpen(event) {

alert(event.type);

}

function onMessage(messageEvent) {

alert(messageEvent.data);

}

function onError(event) {

}

function onClose(closeEvent) {

alert(closeEvent.reason);

}

function doSendUser() {

if (websocket.readyState === websocket.OPEN) {

var msg = document.getElementById("inputMsg").value;

websocket.send(msg);//发送消息

alert("发送成功!");

} else {

alert("连接失败!");

}

}

window.close = function () {

websocket.onclose();

};

function websocketClose() {

websocket.close();

alert("连接关闭");

}

</script>

</head>

<body>

请输入:<input id="inputMsg" name="inputMsg"/>

<button οnclick="doSendUser();">发送</button>

<button οnclick="websocketClose();">关闭连接</button>

</body>

</html>

补充:登录方式除了在Controller中处理,还可以在Websocket中接收到的消息进行登录处理。

更多java学习资料可关注:itheimaGZ获取

最新文章

  1. Struts2初始(一)
  2. FusionChart 水印破解方法(代码版)
  3. webapi filter过滤器中获得请求的方法详情(方法名,Attributes)
  4. 亿级 Web 系统的容错性建设实践
  5. centos7 hostname
  6. 去除手机端a标签等按下去背景色
  7. [转]Session服务器配置指南与使用经验
  8. NSData
  9. 【poj2891-Strange Way to Express Integers】拓展欧几里得-同余方程组
  10. eclipse 对齐行号在括号中显示和字体调整
  11. C# linq创建嵌套组
  12. mooc-python语言语法week3-6
  13. Swing中经常会遇到的若干问题——JTable(持续更新)
  14. mybatis通用mapper源码解析(二)
  15. Android接入微信SDK之一:发起微信授权登录
  16. android管理SD卡 mksdcard
  17. [net]netcat 做网络端口监听
  18. I.MX6 计算iomux Pin配置
  19. mac下git安装和使用
  20. sql 一些题目

热门文章

  1. 【转】在C#中?,?:和??
  2. Docker NGINX 例子
  3. WIN10怎么查看端口,并杀死进程
  4. HDU 5430:Reflect 欧拉函数
  5. monkey命令详解《转载》
  6. s5pc100开发板linux内核移植
  7. Caused by: com.mysql.cj.exceptions.DataReadException: Zero date value prohibited
  8. CountUp.js 数字跳转效果小插件
  9. mysql查询用if控制显示列
  10. Mysql数据库忘记密码找回方法