下面分别介绍搭建方法:
一、直接使用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获取

Java搭建WebSocket的两种方式的更多相关文章

  1. java 实现websocket的两种方式

    简单说明 1.两种方式,一种使用tomcat的websocket实现,一种使用spring的websocket 2.tomcat的方式需要tomcat 7.x,JEE7的支持. 3.spring与we ...

  2. WebSocket实践——Java实现WebSocket的两种方式

    什么是 WebSocket? 随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信 ...

  3. java 实现websocket的三种方式

    Java中实现websocket常见有以下三种方式: 使用tomcat的websocket实现,需要tomcat 7.x,JEE7的支持. 使用spring的websocket,spring与webs ...

  4. 对Java代码加密的两种方式,防止反编译

    使用Virbox Protector对Java项目加密有两种方式,一种是对War包加密,一种是对Jar包加密.Virbox Protector支持这两种文件格式加密,可以加密用于解析class文件的j ...

  5. Java新建线程的两种方式

    Java新建线程有两种方式,一种是通过继承Thread类,一种是实现Runnable接口,下面是新建线程的两种方式. 我们假设有个竞赛,有一个选手A做俯卧撑,一个选手B做仰卧起坐.分别为两个线程: p ...

  6. Java实现多线程的两种方式

    实现多线程的两种方式: 方式1: 继承Thread类 A: 自定义MyThread类继承Thread类 B: 在MyThread类中重写run() C: 创建MyThread类的对象 D: 启动线程对 ...

  7. [Java] HashMap遍历的两种方式

    Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml第一种: Map map = new HashMap( ...

  8. Java实现深克隆的两种方式

    序列化和依次克隆各个可变的引用类型都可以实现深克隆,但是序列化的效率并不理想 下面是两种实现深克隆的实例,并且测试类对两种方法进行了对比: 1.重写clone方法使用父类中的clone()方法实现深克 ...

  9. java文件读写的两种方式

    今天搞了下java文件的读写,自己也总结了一下,但是不全,只有两种方式,先直接看代码: public static void main(String[] args) throws IOExceptio ...

随机推荐

  1. 箭头函数this

    箭头函数的this值是由包含它的函数(非箭头函数)来决定的,与包含的函数的this指向一致,如果包裹它的不是函数(直到找到最外层)则this指向全局对象 并且箭头函数的this是固定的,由定义它时所在 ...

  2. ELK 安装Beat

    章节 ELK 介绍 ELK 安装Elasticsearch ELK 安装Kibana ELK 安装Beat ELK 安装Logstash Beat是数据采集工具,安装在服务器上,将采集到的数据发送给E ...

  3. Bean Java配置

    Spring 系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of ...

  4. Bean 注解(Annotation)配置(1)- 通过注解加载Bean

    Spring 系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of ...

  5. ACM-奇特的立方体

    题目描述:奇特的立方体 任意给出8个整数,将这8个整数分别放在一个立方体的八个顶点上,要求检验每个面上的四个数之和相等这个条件能否被满足. 输入 一次输入8个整数 输出 YES或者NO YES表示可能 ...

  6. Origin中使用CopyPage复制图片到Word后比例失调解决办法

    Origin画图的优势很多,其图形美观易于操作.对我而言,Origin最大的优点就是与Word兼容,在Origin操作界面空白处直接使用右键CopyPage命令,然后在Word中使用粘贴命令即可插入图 ...

  7. apicloud - addEventListener 接收不到 sendEvent 的解决方法

    要将 api.addEventListener 放在最前面 , 减少受到其他事件的影响 apiready = function () { api.addEventListener({          ...

  8. s5pc100开发板linux内核移植

    相关软件下载地址:http://pan.baidu.com/s/16yo8Y 应用于FSC100开发板 交叉编译工具:arm-cortex_a8-linux-gnueabi-gcc linux-2.6 ...

  9. mailx发送邮件

    cent6.5自带mailx   这是个第三方的邮件发送 比如用自己的126给其他账户发邮件 cent6.5还自带了postfix 可以停掉  sendmail(cent5才自带6是postfix)也 ...

  10. jQuery选择器全解析

    1. 基本选择器 1.1 id选择器:$(#id) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...