1. 程式人生 > >Springboot與WebSocket整合實現聊天功能

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("所有人");
        });
       }

僅為部分程式碼。