Springboot与WebSocket整合实现聊天功能

  1. 首先要在pom.xml中导入websocket的依赖
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-websocket</artifactId>
		</dependency>
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>sockjs-client</artifactId>
			<version>1.0.2</version>
		</dependency>
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>stomp-websocket</artifactId>
			<version>2.3.3</version>
		</dependency>
		<!--thymeleaf-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

用到websocket只需要第一个spring-boot-starter-websocket依赖就可以了,因为该项目还实现了和前台的交互,所以导入了sockjs-client和stomp-websocket依赖(如果不想在pom.xml中导入,可以直接引用/sockjs.min.js和stomp.min.js链接:http://www.bootcdn.cn/stomp.js/)
2. 后台新建WebSocketConfig.java

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        //添加服务端点,接收客户端的连接
        //参数/any-socket要和前台对应一致
        registry.addEndpoint("/any-socket")
                //开启SockJS支持
                .withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        //服务端接收地址的前缀
        registry.setApplicationDestinationPrefixes("/app");
        //客户端订阅地址的前缀信息
        registry.enableSimpleBroker("/topic","/user");
    }

    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
        registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {

            @Override
            public WebSocketHandler decorate(WebSocketHandler handler) {
                return new WebSocketHandlerDecorator(handler){
                    /* (non-Javadoc)
                     * 客户端与服务端建立连接后的服务端的操作
                     */
                    @Override
                    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
                        String username = session.getPrincipal().getName();
                        System.out.println("online:"+username);
                        super.afterConnectionEstablished(session);
                    }

                    /* (non-Javadoc)
                     * 客户端与服务端断开连接后服务端的操作
                     */
                    @Override
                    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus)
                            throws Exception {
                        String username = session.getPrincipal().getName();
                        System.out.println("offline:"+username);
                        super.afterConnectionClosed(session, closeStatus);
                    }
                };
            }
        });
    }

}

@Configuration 说明该java类是一个配置类
@EnableWebSocketMessageBroker 用于开始使用STOMP协议来传输基于MessageBroken的消息,这时controller可以使用@MessageMapping来拦截消息
registry.setApplicationDestinationPrefixes()用来设置服务器接收消息的前缀
3.聊天消息的controller

@Controller
public class ChatController {
    private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Autowired
    private SimpMessagingTemplate template;

    /**
     * 群聊模式
     * @param principal 当前用户
     * @param message 接收到的客户端的消息
     * @return 包装后的消息
     */
    @MessageMapping("/all")
    @SendTo("/topic/all")
    public String all(Principal principal,String message){
        BaseMessage baseMessage = new BaseMessage();
        baseMessage.setType("to_all");
        baseMessage.setContent(message);
        baseMessage.setSender(principal.getName());
        System.out.println(principal.getName()+"++++++++++++++++++++++++++++++++++");
        baseMessage.setSendTime(format.format(new Date()));
        System.out.println(JSON.toJSONString(baseMessage));
        return JSON.toJSONString(baseMessage);
    }

    /**
     * 私聊
     *
     */
    @MessageMapping("/chat")//接收发送到/app/chat的消息
    public void chat(Principal principal,String message){
        ChatMessage chatMessage = JSON.parseObject(message,ChatMessage.class);
        BaseMessage baseMessage = new BaseMessage();
        baseMessage.setType("to_one");
        baseMessage.setSender(principal.getName());
        System.out.println(principal.getName()+"++++++++++++++++++++++++++++++++++");
        baseMessage.setContent(chatMessage.getContent());
        baseMessage.setSendTime(format.format(new Date()));

        //转发包装后的消息至用户
        template.convertAndSendToUser(chatMessage.getReceiver(),"/topic/chat",JSON.toJSONString(baseMessage));

    }

}

@MessageMapping("/chat") 拦截发送到"/app/chat"的消息
@SendTo 注解重写了消息代理的目的地,如果不指定@SendTo,帧所发往的目的地会与触发处理器方法的目的地相同,只不过会添加上“/topic”前缀
3.前台js的实现

	var target = "to_all";
    var stompClient = null;

    function connect() {
        var socket = new SockJS('/any-socket');
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function (frame) {
            console.log('Connected: ' + frame);
            stompClient.subscribe('/topic/all', function (message) {
                showMessage(JSON.parse(message.body));
            });
            stompClient.subscribe('/user/topic/chat', function (message) {
                showMessage(JSON.parse(message.body));
            });
        });
    }

stompClient.connect(header,connectionCallback,errorCallback);第一个参数是header,包含客户端的认证信息,可如下所示;connectionCallback是表示连接成功时(服务器响应 CONNECTED 帧)的回调方法
errorCallback是连接失败时的回调方法,非必需

var headers = {
  login: 'mylogin',
  passcode: 'mypasscode',
  // additional header
  'client-id': 'my-client-id'
};

subscribe(destination url, callback[, headers]) 订阅服务器的消息
destination url 为服务器 @SendTo 匹配的 URL,字符串;
callback 为每次收到服务器推送的消息时的回调方法
showMessage为自定义消息用于在客户端展示消息

$(function () {
        connect();
         $("#send").click(function () {
            if (target == "to_all"){
            	if($("#message").val()){
            		stompClient.send("/app/all", {}, $("#message").val());
            	}
            }else{
                var content = "{'type':'to_one','content':'" + $("#message").val() + "','receiver':'"+target+"'}";
                stompClient.send("/app/chat", {}, content);
            }
            $("#message").val("");
        });
         $(".friend").click(function () {
            target = $(this).find("p.f-name").text();
            var username = $(this).find("h4.f-name").text();
            $("#target").text(username);
            $("#groupBtn").attr("class","btn btn-default");
        });
        
        $("#groupBtn").click(function(){
        	$(this).attr("class","btn btn-default disabled");
        	target = "to_all";
        	$("#target").text("所有人");
        });
       }

仅为部分代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值