Äú¿ÉÒÔ¾èÖú£¬Ö§³ÖÎÒÃǵĹ«ÒæÊÂÒµ¡£

1Ôª 10Ôª 50Ôª





ÈÏÖ¤Â룺  ÑéÖ¤Âë,¿´²»Çå³þ?Çëµã»÷Ë¢ÐÂÑéÖ¤Âë ±ØÌî



  ÇóÖª ÎÄÕ ÎÄ¿â Lib ÊÓƵ iPerson ¿Î³Ì ÈÏÖ¤ ×Éѯ ¹¤¾ß ½²×ù Model Center   Code  
»áÔ±   
   
 
     
   
 ¶©ÔÄ
  ¾èÖú
ÔÙ̸websocket,Âۼܹ¹Éè¼Æ
 
  3869  次浏览      19
 2017-12-19 
 
±à¼­ÍƼö:
±¾ÎÄÀ´×ÔÓÚlrwinx.github.io,±¾ÆªÎÄÕÂÒÔwebsocketµÄÔ­ÀíºÍÂäµØΪºËÐÄ£¬À´ÐðÊöwebsocketµÄʹÓã¬ÒÔ¼°Ïà¹ØÓ¦Óó¡¾°¡£

websocket¸ÅÊö

httpÓëwebsocket

ÈçÎÒÃÇËùÁ˽⣬httpÁ¬½ÓΪһ´ÎÇëÇóÒ»´ÎÏìÓ¦(request->response)£¬±ØÐëΪͬ²½µ÷Ó÷½Ê½¡£

¶øwebsocketΪһ´ÎÁ¬½ÓÒԺ󣬻ὨÁ¢tcpÁ¬½Ó£¬ºóÐø¿Í»§¶ËÓë·þÎñÆ÷½»»¥ÎªÈ«Ë«¹¤·½Ê½µÄ½»»¥·½Ê½£¬¿Í»§¶Ë¿ÉÒÔ·¢ËÍÏûÏ¢µ½·þÎñ¶Ë£¬·þÎñ¶ËÒ²¿É½«ÏûÏ¢·¢Ë͸ø¿Í»§¶Ë¡£

http,websocket

´ËͼÀ´Ô´ÓÚWebsocketЭÒéµÄѧϰ¡¢µ÷ÑкÍʵÏÖ,ÈçÓÐÇÖȨÎÊÌ⣬¸æÖªºó£¬É¾³ý¡£

¸ù¾ÝÉÏͼ£¬ÎÒÃÇ´óÖ¿ÉÒÔÁ˽⵽httpÓëwebsocketÖ®¼äµÄÇø±ðºÍ²»Í¬¡£

ΪʲôҪʹÓÃwebsocket

ÄÇôÁ˽âhttpÓëwebsocketÖ®¼äµÄ²»Í¬ÒÔºó£¬ÎÒÃÇΪʲôҪʹÓÃwebsocketÄØ£¿ ËûµÄÓ¦Óó¡¾°ÊÇʲôÄØ£¿

ÎÒÕÒµ½ÁËÒ»¸ö±È½Ï·ûºÏwebsocketʹÓó¡¾°µÄÃèÊö

¡°The best fit for WebSocket is in web applications where the client and server need to exchange events at high frequency and with low latency.¡±

·­Òë: ÔÚ¿Í»§¶ËÓë·þÎñÆ÷¶Ë½»»¥µÄwebÓ¦ÓÃÖУ¬websocket×îÊʺÏÔÚ¸ßƵÂʵÍÑӳٵij¡¾°Ï£¬½øÐÐʼþµÄ½»»»ºÍ´¦Àí

´Ë¶ÎÀ´Ô´ÓÚspring websocketµÄ¹Ù·½Îĵµ

Á˽âÒÔÉÏ֪ʶºó£¬ÎÒ¾Ù³ö¼¸¸ö±È½Ï³£¼ûµÄ³¡¾°:

ÓÎÏ·ÖеÄÊý¾Ý´«Êä

¹ÉƱKÏßͼÊý¾Ý

¿Í·þϵͳ

¸ù¾ÝÈçÉÏËùÊö£¬¸÷¸öϵͳ¶¼À´Ê¹ÓÃwebsocket²»ÊǸüºÃÂð£¿

Æäʵ²¢²»ÊÇ£¬websocket½¨Á¢Á¬½ÓÖ®ºó£¬ºó±ß½»»¥¶¼ÓÉtcpЭÒé½øÐн»»¥£¬¹Ê¿ª·¢µÄ¸´ÔӶȻá½Ï¸ß¡£µ±È»websocketͨѶ£¬±¾ÉíÒª¿¼ÂǵÄÊÂÇéÒª±ÈHTTPЭÒéµÄͨѶ¿¼Âǵĸü¶à.

ËùÒÔÈç¹û²»ÊÇÓÐÌØÊâÒªÇó(¼´ Ó¦Óò»ÊÇ¡±¸ßƵÂʵÍÑÓ³Ù¡±µÄÒªÇó),ÐèÒªÓÅÏÈ¿¼ÂÇHTTPЭÒéÊÇ·ñ¿ÉÒÔÂú×ã¡£

±ÈÈçÐÂÎÅϵͳ£¬ÐÂÎŵÄÊý¾ÝÍíÉÏ10·ÖÖÓ-30·ÖÖÓ£¬ÊÇ¿ÉÒÔ½ÓÊܵģ¬ÄÇô¾Í¿ÉÒÔ²ÉÓÃHTTPµÄ·½Ê½½øÐÐÂÖѯ(polling)²Ù×÷µ÷ÓÃREST½Ó¿Ú¡£

µ±È»ÓÐʱÎÒÃǽ¨Á¢ÁËwebsocketͨѶ£¬²¢ÇÒÏ£Íûͨ¹ýHTTPÌṩµÄREST½Ó¿ÚÍÆË͸øij¿Í»§¶Ë£¬´ËʱÐèÒª¿¼ÂÇREST½Ó¿Ú½ÓÊÜÊý¾Ý´«Ë͸øwebsocketÖУ¬½øÐй㲥ʽµÄͨѶ·½Ê½¡£

ÖÁ´Ë£¬ÎÒÒѾ­½²ÊöÁËÈýÖÖ½»»¥·½Ê½µÄʹÓó¡¾°:

websocket¶ÀÁ¢Ê¹Óó¡¾°

HTTP¶ÀÁ¢Ê¹Óó¡¾°

HTTPÖÐתwebsocketʹÓó¡¾°

Ïà¹Ø¼¼Êõ¸ÅÄî

websocket

websocketΪһ´ÎHTTPÎÕÊֺ󣬺óÐøͨѶΪtcpЭÒéµÄͨѶ·½Ê½¡£

µ±È»£¬ºÍHTTPÒ»Ñù£¬websocketÒ²ÓÐһЩԼ¶¨µÄͨѶ·½Ê½£¬httpͨѶ·½Ê½Îªhttp¿ªÍ·µÄ·½Ê½,e.g. http://xxx.com/path ,websocketͨѶ·½Ê½ÔòΪws¿ªÍ·µÄ·½Ê½,e.g. ws://xxx.com/path

SSL:

HTTP: https://xxx.com/path

WEBSOCKET: wss://xxx.com/path

websocketͨѶ

´ËͼÀ´Ô´ÓÚWebSocket ½Ì³Ì,ÈçÓÐÇÖȨÎÊÌ⣬¸æÖªºó£¬É¾³ý¡£

SockJS

ÕýÈçÎÒÃÇËùÖª,websocketЭÒéËäÈ»ÒѾ­±»Öƶ¨£¬µ±Ê±»¹Óкܶà°æ±¾µÄä¯ÀÀÆ÷»òä¯ÀÀÆ÷³§ÉÌ»¹Ã»ÓÐÖ§³ÖµÄºÜºÃ¡£

ËùÒÔ,SockJS,¿ÉÒÔÀí½âΪÊÇwebsocketµÄÒ»¸ö±¸Ñ¡·½°¸¡£

ÄÇËüÈçºÎ¹æ¶¨±¸Ñ¡·½°¸µÄÄØ£¿

Ëü´ó¸ÅÖ§³ÖÕâÑù¼¸¸ö·½°¸:

Websockets

Streaming

Polling

µ±È»£¬¿ªÆô²¢Ê¹ÓÃSockJSºó£¬Ëü»áÓÅÏÈÑ¡ÓÃwebsocketЭÒé×÷Ϊ´«ÊäЭÒ飬Èç¹ûä¯ÀÀÆ÷²»Ö§³ÖwebsocketЭÒ飬Ôò»áÔÚÆäËû·½°¸ÖУ¬Ñ¡ÔñÒ»¸ö½ÏºÃµÄЭÒé½øÐÐͨѶ¡£

¿´Ò»ÏÂÄ¿Ç°ä¯ÀÀÆ÷µÄÖ§³ÖÇé¿ö:

Supported transports, by browser

´ËͼÀ´Ô´ÓÚgithub: sockjs-client

ËùÒÔ£¬Èç¹ûʹÓÃSockJS½øÐÐͨѶ£¬Ëü½«ÔÚʹÓÃÉϱ£³ÖÒ»Ö£¬µ×²ãÓÉËü×Ô¼ºÈ¥Ñ¡ÔñÏàÓ¦µÄЭÒé¡£

¿ÉÒÔÈÏΪSockJSÊÇwebsocketͨѶ²ãÉϵÄÉϲãЭÒé¡£

µ×²ã¶ÔÓÚ¿ª·¢ÕßÀ´ËµÊÇ͸Ã÷µÄ¡£

STOMP

STOMP ÖÐÎÄΪ: ÃæÏòÏûÏ¢µÄ¼òµ¥Îı¾Ð­Òé

websocket¶¨ÒåÁËÁ½ÖÖ´«ÊäÐÅÏ¢ÀàÐÍ: Îı¾ÐÅÏ¢ ºÍ ¶þ½øÖÆÐÅÏ¢ ( text and binary ).

ÀàÐÍËäÈ»±»È·¶¨£¬µ«ÊÇËûÃǵĴ«ÊäÌåÊÇûÓй涨µÄ¡£

µ±È»Äã¿ÉÒÔ×Ô¼ºÀ´Ð´´«ÊäÌ壬À´¹æ¶¨´«ÊäÄÚÈÝ¡£(µ±È»£¬ÕâÑùµÄ¸´ÔÓ¶ÈÊǺܸߵÄ)

ËùÒÔ,ÐèÒªÓÃÒ»ÖÖ¼òµ¥µÄÎı¾´«ÊäÀàÐÍÀ´¹æ¶¨´«ÊäÄÚÈÝ£¬Ëü¿ÉÒÔ×÷ΪͨѶÖеÄÎı¾´«ÊäЭÒé,¼´½»»¥Öеĸ߼¶Ð­ÒéÀ´¶¨Òå½»»¥ÐÅÏ¢¡£

STOMP±¾Éí¿ÉÒÔÖ§³ÖÁ÷ÀàÐ͵ÄÍøÂç´«ÊäЭÒé: websocketЭÒéºÍtcpЭÒé

ËüµÄ¸ñʽΪ:

COMMAND
header1:value1
header2:value2

Body^@


SUBSCRIBE
id:sub-1
destination:/topic/price.stock.*

^@

SEND
destination:/queue/trade
content-type:application/json
content-length:44

{"action":"BUY","ticker":"MMM","shares",44}^@

µ±È»STOMPÒѾ­Ó¦ÓÃÓںܶàÏûÏ¢´úÀíÖУ¬×÷Ϊһ¸ö´«ÊäЭÒéµÄ¹æ¶¨£¬Èç:RabbitMQ, ActiveMQ

ÎÒÃǽԿÉÒÔÓÃSTOMPºÍÕâÀàMQ½øÐÐÏûÏ¢½»»¥.

³ýÁËSTOMPÏà¹ØµÄ´úÀíÍ⣬ʵ¼ÊÉÏ»¹ÌṩÁËÒ»¸östomp.js,ÓÃÓÚä¯ÀÀÆ÷¿Í»§¶ËʹÓÃSTOMPÏûϢЭÒé´«ÊäµÄjs¿â¡£

ÈÃÎÒÃǺܷ½±ãµÄʹÓÃstomp.js½øÐÐÓëSTOMPЭÒéÏà¹ØµÄ´úÀí½øÐн»»¥.

ÕýÈçÎÒÃÇËùÖª£¬Èç¹ûwebsocketÄÚÈÝ´«ÊäÐÅϢʹÓÃSTOMPÀ´½øÐн»»¥£¬websocketÒ²ºÜºÃµÄÓÚÏûÏ¢´úÀíÆ÷½øÐн»»¥(Èç:RabbitMQ, ActiveMQ)

ÕâÑù¾ÍºÜºÃµÄÌṩÁËÏûÏ¢´úÀíµÄ¼¯³É·½°¸¡£

×ܽᣬʹÓÃSTOMPµÄÓŵãÈçÏÂ:

²»ÐèÒª×Ô½¨Ò»Ì××Ô¶¨ÒåµÄÏûÏ¢¸ñʽ

ÏÖÓÐstomp.js¿Í»§¶Ë(ä¯ÀÀÆ÷ÖÐʹÓÃ)¿ÉÒÔÖ±½ÓʹÓÃ

ÄÜ·ÓÉÐÅÏ¢µ½Ö¸¶¨ÏûÏ¢µØµã

¿ÉÒÔÖ±½ÓʹÓóÉÊìµÄSTOMP´úÀí½øÐй㲥 Èç:RabbitMQ, ActiveMQ

¼¼ÊõÂäµØ

ºó¶Ë¼¼Êõ·½°¸Ñ¡ÐÍ

websocket·þÎñ¶ËÑ¡ÐÍ:spring websocket

Ö§³ÖSockJS,¿ªÆôSockJSºó£¬¿ÉÓ¦¶Ô²»Í¬ä¯ÀÀÆ÷µÄͨѶ֧³Ö

Ö§³ÖSTOMP´«ÊäЭÒ飬¿ÉÎÞ·ì¶Ô½ÓSTOMPЭÒéϵÄÏûÏ¢´úÀíÆ÷(Èç:RabbitMQ, ActiveMQ)

Ç°¶Ë¼¼Êõ·½°¸Ñ¡ÐÍ

Ç°¶ËÑ¡ÐÍ: stomp.js,sockjs.js

ºó¶Ë¿ªÆôSOMPºÍSockJSÖ§³Öºó£¬Ç°¶ÔÓ¦ÓжÔÓ¦µÄjs¿â½øÐÐÖ§³Ö.

ËùÒÔÑ¡ÓôËÁ½¸ö¿â.

×ܽá

ÉÏÊöËùÓü¼Êõ£¬ÊÇÕâÑùµÄÂß¼­:

¿ªÆôsocktJS:

Èç¹ûÓÐä¯ÀÀÆ÷²»Ö§³ÖwebsocketЭÒ飬¿ÉÒÔÔÚÆäËûÁ½ÖÖЭÒéÖнøÐÐÑ¡Ôñ£¬µ«ÊǶÔÓÚÓ¦ÓòãÀ´½²£¬Ê¹ÓÃÆðÀ´ÊÇÒ»ÑùµÄ¡£

ÕâÊÇΪÁËÖ§³Öä¯ÀÀÆ÷²»Ö§³ÖwebsocketЭÒéµÄÒ»ÖÖ±¸Ñ¡·½°¸

ʹÓÃSTOMP:

ʹÓÃSTOMP½øÐн»»¥£¬Ç°¶Ë¿ÉÒÔʹÓÃstomp.jsÀà¿â½øÐн»»¥£¬ÏûÏ¢Ò»STOMPЭÒé¸ñʽ½øÐд«Ê䣬ÕâÑù¾Í¹æ¶¨ÁËÏûÏ¢´«Êä¸ñʽ¡£

ÏûÏ¢½øÈëºó¶ËÒԺ󣬿ÉÒÔ½«ÏûÏ¢ÓëʵÏÖSTOMP¸ñʽµÄ´úÀíÆ÷½øÐÐÕûºÏ¡£

ÕâÊÇΪÁËÏûϢͳһ¹ÜÀí£¬½øÐлúÆ÷À©ÈÝʱ£¬¿É½øÐиºÔؾùºâ²¿Êð

ʹÓÃspring websocket:

ʹÓÃspring websocket,ÊÇÒòΪËûÌṩÁËSTOMPµÄ´«Êä×ÔЭÒéµÄͬʱ£¬»¹ÌṩÁËStockJSµÄÖ§³Ö¡£

µ±È»£¬³ý´ËÖ®Í⣬spring websocket»¹ÌṩÁËȨÏÞÕûºÏµÄ¹¦ÄÜ£¬»¹ÓÐ×Ô´øÌìÉúÓëspring¼Ò×åµÈÏà¹Ø¿ò¼Ü½øÐÐÎÞ·ìÕûºÏ¡£

Ó¦Óó¡¾°

Ó¦Óñ³¾°

2016Ä꣬ÔÚ¹«Ë¾ÓëͬÊÂÒ»ÆðÌÖÂۺͿª·¢Á˹«Ë¾ÄÚ²¿µÄ¿Í·þϵͳ£¬ÓÉÓÚÇ°¶Ë¼¼ÄܵIJ»×㣬ºÜ¶àͨѶ·½ÃæµÄÎÊÌ⣬ÎÞ·¨Ç××Ôµ÷ÊÔÇ°¶ËÀ´½â¾öÎÊÌâ¡£

ÒòΪ¹«Ë¾¼¼Êõ¼Ü¹¹ÌåϵÒÔÇ°ºó¶Ë·ÖÀëΪÖ÷£¬¹ÊÇ°¶ËÎÞ·¨Ð­Öúºó¶Ëµ÷ÊÔ£¬ºó¶ËÎÞ·¨Ð­ÖúÇ°¶Ëµ÷ÊÔ

ÔÚ¼ÓÉÏwebsocketΪ¹«Ë¾¸ÕÆôÓõÄЭÒ飬Á˽âµÄÈ˲»¶à£¬µ¼ÖÂÇ°ºó¶Ëµ÷ÊÔÎÊÌâÖØÖØ¡£

Ò»ÄêºóµÄ½ñÌ죬ÎÒ´òË㽫ǰ¶ËÖØΣ¬×Ô¼ºÀ´µ÷ÊÔÒ»ÏÂÇ°ºó¶Ë£¬À´·¢¾òÒ»ÏÂ֮ǰÁªµ÷µÄÎÊÌâ.

µ±È»£¬Ç°¶Ë£¬ÎÒÖ»ÊÇ¿¼ÂÇstomp.jsºÍsockt.jsµÄʹÓá£

´úÂë½×¶ÎÉè¼Æ

½ÇÉ«

¿Í·þ

¿Í»§

µÇ¼Óû§×´Ì¬

ÉÏÏß

ÏÂÏß

·ÖÅä²ßÂÔ

Óû§µÇ½ºó£¬Ó¦¸Ã¸ù¾ÝÓû§½ÇÉ«½øÐзÖÅä

¹Øϵ±£´æ²ßÂÔ

Ó¦¸ÃÌṩ¹ØϵÐͱ£´æ²ßÂÔ: ¿¼ÂÇÄÚ´æʽ²ßÂÔ(¿ÉÓÃÓÚ²âÊÔ)£¬redisʽ²ßÂÔ

±¸×¢:ÓÅÏÈÓ¦¸Ã¿¼ÂÇʵÏÖInmemory²ßÂÔ£¬ÓÃÓÚ²âÊÔ£¬ÈùØϵ±£´æ²ßÂÔÓë´æ´¢Æ½Ì¨ÎÞ¹Ø

ͨѶ²ãÉè¼Æ

¹éÀàtopicµÄ¹ã²¥Éè¼Æ(ͨѶ·½Ê½:1-n)

¹éÀàqueueµÄµ¥µãÉè¼Æ(ͨѶ·½Ê½:1-1)

´úÂëʵÏÖ

½ÇÉ«

import org.springframework.security .core.GrantedAuthority;
import org.springframework.security .core.authority.SimpleGrantedAuthority;
import org.springframework .security.core.userdetails.User;
import java.util.Collection;
public enum Role {
CUSTOMER_SERVICE,
CUSTOMER;


public static boolean isCustomer (User user) {
Collection< GrantedAuthority> authorities = user.getAuthorities();
SimpleGrantedAuthority customerGrantedAuthority = new SimpleGrantedAuthority ("ROLE_" + Role.CUSTOMER.name());
return authorities.contains (customerGrantedAuthority);
}

public static boolean isCustomerService(User user) {
Collection<GrantedAuthority> authorities = user.getAuthorities();
SimpleGrantedAuthority customerServiceGrantedAuthority = new SimpleGrantedAuthority ("ROLE_" + Role.CUSTOMER_SERVICE.name());
return authorities.contains (customerServiceGrantedAuthority);
}
}

´úÂëÖÐUser¶ÔÏó£¬Îª°²È«¶ÔÏ󣬼´ springÖÐorg.springframework. security.core.userdetails.User£¬ÎªUserDetailsµÄʵÏÖÀà¡£

User¶ÔÏóÖУ¬±£´æÁËÓû§ÊÚȨºóµÄºÜ¶à»ù´¡È¨ÏÞÐÅÏ¢£¬ºÍÓû§ÐÅÏ¢¡£

ÈçÏÂ:

public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();

String getPassword();

String getUsername();

boolean isAccountNonExpired();

boolean isAccountNonLocked();

boolean isCredentialsNonExpired();

boolean isEnabled();
}

·½·¨ #isCustomer ºÍ #isCustomerService ÓÃÀ´ÅжÏÓû§µ±Ç°ÊÇ·ñÊǹ˿ͻòÕßÊÇ¿Í·þ¡£

µÇ¼Óû§×´Ì¬

public interface StatesManager {

enum StatesManagerEnum{
ON_LINE,
OFF_LINE
}

void changeState (User user , StatesManagerEnum statesManagerEnum);

StatesManagerEnum currentState(User user);

}

Éè¼ÆµÇ¼״̬ʱ£¬Ó¦´æÔڵǼ״̬¹ÜÀíÏà¹ØµÄ״̬¹ÜÀíÆ÷£¬´Ë¹ÜÀíÆ÷Ö»¸ºÔð¸ü¸ÄÓû§×´Ì¬ºÍ»ñÈ¡Óû§×´Ì¬Ïà¹Ø²Ù×÷¡£

²¢²»Éæ¼°ÆäËû¹ØÁªÂß¼­£¬ÕâÑùµÄ´úÂë»®·Ö£¬¸üÓÐÖúÓÚÃæÏò½Ó¿Ú±à³ÌµÄÀ©Õ¹ÐÔ

·ÖÅä²ßÂÔ

public interface DistributionUsers {
void distribution(User user);
}

·ÖÅä½ÇÉ«½Ó¿ÚÉè¼Æ£¬Ö»¹Ø×¢´«ÈëµÄÓû§£¬²¢²»¹Ø×¢´ËÓû§ÊÇ¿Í·þ»òÕßÓû§£¬¾ßÌåÐèÒªÈçºÎÈ¥×ö£¬ÓɾßÌåµÄ·ÖÅä²ßÂÔÀ´¾ö¶¨¡£

¹Øϵ±£´æ²ßÂÔ

public interface RelationHandler {

void saveRelation(User customerService,User customer);

List<User> listCustomers (User customerService);

void deleteRelation (User customerService,User customer);

void saveCustomerService (User customerService);

List<User> listCustomerService();

User getCustomerService(User customer);

boolean exist(User user);

User availableNextCustomerService();

}

¹Øϵ±£´æ²ßÂÔ£¬ÒàÊÇÖ»¹Ø×¢¹Øϵ±£´æÏà¹Ø£¬²¢²»ÔÚºõÓÚ±£´æµ½Äĸö´æ´¢½éÖÊÖС£

ʵÏÖÀàÓÉInmemory»¹ÊÇredis»¹ÊÇmysql,Ëü²¢²»×¨×¢¡£

µ«ÊÇ£¬´Ë´¦ÐèҪעÒ⣬¶ÔÓÚÕâÖÖ¹Øϵ±£´æ²ßÂÔ£¬¿ª·¢²âÊÔʱ£¬²¢²»Éæ¼°¸ß¿ÉÓ㬿ɽ«InmemoryÏÈ×ö³öÀ´ÓÃÓÚ²âÊÔ¡£

¿ª·¢¹¦ÄÜͬʱ£¬Ïà¹ØͬÊÂÔÙÀ´¿ª·¢ÆäËû½éÖÊ´æ´¢µÄ²ßÂÔ£¬ÐÔÄܲâÊÔÒÔ¼°UATÏà¹Ø²âÊÔʱ£¬Ó¦Çл»Îª´Ë½éÖÊ´æ´¢µÄ²ßÂÔÔÙ½øÐвâÊÔ¡£

Óû§×ۺϹÜÀí

¶ÔÓÚ²»Í¬¹¦ÄܵÄʵÏÖ²ßÂÔ£¬Óɸ÷¸ö¹¦ÄÜ×Ô¼ºÀ´ÊµÏÖ£¬ÔÚʹÓÃÉÏ£¬ÎÒÃǽö½ö¸ù¾Ý½Ó¿Ú±à³Ì¼´¿É¡£

ËùÒÔ£¬Òª½«ÉÏÊöËùÓй¦ÄÜ·â×°³ÉÒ»¸ö¹¤¾ßÀà½øÐÐʹÓã¬Õâ¾ÍÊÇËùνµÄ Éè¼Æģʽ: ÃÅÃæģʽ

@Component
public class UserManagerFacade {
@Autowired
private DistributionUsers distributionUsers;
@Autowired
private StatesManager statesManager;
@Autowired
private RelationHandler relationHandler;


public void login(User user) {
if (roleSemanticsMistiness(user)) {
throw new SessionAuthenticationException ("½ÇÉ«ÓïÒå²»ÇåÎú");
}

distributionUsers.distribution(user);
statesManager.changeState (user, StatesManager .StatesManagerEnum.ON_LINE);
}
private boolean roleSemanticsMistiness(User user) {
Collection<GrantedAuthority> authorities = user.getAuthorities();

SimpleGrantedAuthority customerGrantedAuthority = new SimpleGrantedAuthority ("ROLE_" +Role.CUSTOMER.name());
SimpleGrantedAuthority customerServiceGrantedAuthority = new SimpleGrantedAuthority ("ROLE_" +Role.CUSTOMER_SERVICE.name());

if (authorities.contains(customerGrantedAuthority)
&& authorities.contains(customerServiceGrantedAuthority)) {
return true;
}

return false;
}

public void logout(User user){
statesManager.changeState (user, StatesManager .StatesManagerEnum.OFF_LINE);
}


public User getCustomerService(User user){
return relationHandler.getCustomerService(user);
}

public List<User> listCustomers(User user){
return relationHandler.listCustomers(user);
}

public StatesManager .StatesManagerEnum getStates(User user){
return statesManager.currentState(user);
}

}

UserManagerFacade ÖÐ×¢ÈëÈý¸öÏà¹ØµÄ¹¦ÄܽӿÚ:

@Autowired
private DistributionUsers distributionUsers;
@Autowired
private StatesManager statesManager;
@Autowired
private RelationHandler relationHandler;

¿ÉÌṩ:

怬(#login)

µÇ³ö(#logout)

»ñÈ¡¶ÔÓ¦¿Í·þ(#getCustomerService)

»ñÈ¡¶ÔÓ¦Óû§Áбí(#listCustomers)

µ±Ç°Óû§µÇ¼״̬(#getStates)

ÕâÑùµÄÉè¼Æ£¬¿É±£Ö¤¶ÔÓÚÓû§¹ØϵµÄ¹ÜÀí¶¼ÓÉUserManagerFacadeÀ´¾ö¶¨

ÆäËûÄÚ²¿µÄ²Ù×÷À࣬¶ÔÓÚʹÓÃÕßÀ´Ëµ£¬²¢²»¹ØÐÄ£¬¶Ô¿ª·¢À´½²£¬²»Í¬¹¦ÄܵIJßÂÔ¶¼ÊÇ͸Ã÷µÄ¡£

ͨѶ²ãÉè¼Æ - µÇ¼£¬ÊÚȨ

spring websocketËäÈ»²¢Ã»ÓÐÒªÇóconnectʱ£¬±ØÐëÊÚȨ£¬ÒòΪÁ¬½ÓÒԺ󣬻á·Ö·¢¸ø¿Í»§¶ËwebsocketµÄsession id£¬À´Çø·Ö¿Í»§¶ËµÄ²»Í¬¡£

µ«ÊǶÔÓÚ´ó¶àÊýÓ¦ÓÃÀ´½²£¬µÇ¼ÊÚȨÒԺ󣬽øÐÐwebsocketÁ¬½ÓÊÇ×îºÏÀíµÄ£¬ÎÒÃÇ¿ÉÒÔ½øÐÐȨÏ޵ķÖÅ䣬ºÍȨÏÞÏà¹ØµÄ¹ÜÀí¡£

ÎÒÄ£ÄâÀý×ÓÖУ¬Ê¹ÓõÄÊÇspring securityµÄInmemoryµÄÏà¹ØÅäÖÃ:

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


@Override
protected void configure (AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication() .withUser("admin").password ("admin").roles (Role.CUSTOMER_SERVICE.name());
auth.inMemoryAuthentication() .withUser("admin1").password ("admin").roles (Role.CUSTOMER_SERVICE.name());


auth.inMemoryAuthentication() .withUser("user").password ("user").roles(Role.CUSTOMER.name());
auth.inMemoryAuthentication() .withUser("user1").password ("user").roles(Role.CUSTOMER.name());
auth.inMemoryAuthentication() .withUser("user2").password ("user").roles(Role.CUSTOMER.name());
auth.inMemoryAuthentication() .withUser("user3").password ("user").roles(Role.CUSTOMER.name());
}

@Override
protected void configure (HttpSecurity http) throws Exception {
http.csrf().disable()
.formLogin()
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
}
}

Ïà¶Ô½ÏΪ¼òµ¥£¬´´½¨2¸ö¿Í»§£¬4¸öÆÕͨÓû§¡£

µ±ÈÏÖ¤¹ÜÀíÆ÷ÈÏÖ¤ºó£¬»á½«ÈÏÖ¤ºóµÄºÏ·¨ÈÏÖ¤°²È«¶ÔÏóuser(¼´ ÈÏÖ¤ºóµÄtoken)·ÅÈëSTOMPµÄheaderÖÐ.

´ËÀýÖУ¬ÈÏÖ¤¹ÜÀíÈÏÖ¤Ö®ºó£¬ÈÏÖ¤µÄtokenΪorg.springframework .security.authentication .UsernamePasswordAuthenticationToken,

´ËtokenÈÏÖ¤ºó£¬½«·ÅÈëwebsocketµÄheaderÖС££¨¼´ ºó±ß»á̸µ½µÄ°²È«¶ÔÏó java.security.Principal)

ͨѶ²ãÉè¼Æ - websocketÅäÖÃ

@Order(Ordered.HIGHEST_PRECEDENCE + 99)
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBroker Configurer {

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/portfolio").withSockJS();
}

@Override
public void configureMessageBroker (MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes("/app");
config.enableSimpleBroker("/topic", "/queue");

}
}

´ËÅäÖÃÖУ¬Óм¸µãÐè½øÐн²½â£º

ÆäÖж˵㡱portfolio¡±,ÓÃÓÚsocktJs½øÐÐwebsocketÁ¬½ÓʱʹÓã¬Ö»ÓÃÓÚ½¨Á¢Á¬½Ó¡£

¡°/topic¡±, ¡°/queue¡±,ÔòΪSTOMPµÄÓïÒåÔ¼Êø£¬topicÓïÒåΪ1-n(¹ã²¥»úÖÆ),queueÓïÒåΪ1-1(µ¥µã»úÖÆ)

¡°app¡±,´ËΪӦÓü¶±ðµÄÓ³ÉäÖÕµãǰ׺£¬ÕâÑù˵ÓÐЩ»Þɬ£¬Ò»»á¿´Ò»ÏÂʾÀý½«»áÇåÎúºÜ¶à¡£

ͨѶ²ãÉè¼Æ - ´´½¨Á¬½Ó

ÓÃÓÚÁ¬½Óspring websocketµÄ¶ËµãΪportfolio£¬Ëü¿ÉÓÃÓÚÁ¬½Ó£¬¿´Ò»Ï¾ßÌåʵÏÖ:

<script src= "http://cdn.bootcss.com/sockjs-client/1.1.1/sockjs.min.js"></script>
<script src= "http://cdn.bootcss.com/stomp.js/2.3.3/stomp.js"></script>
<script src= "http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>

var socket = new SockJS("/portfolio");
stompClient = Stomp.over(socket);

stompClient.connect({}, function(frame) {
showGreeting("µÇ¼Óû§: " + frame.headers["user-name"]);
});

ÕâÑù±ã½¨Á¢ÁËÁ¬½Ó¡£ ºóÐøµÄÆäËû²Ù×÷¾Í¿ÉÒÔͨ¹ýstompClient¾ä±ú½øÐÐʹÓÃÁË¡£

ͨѶ²ãÉè¼Æ - spring websocketÏûϢģÐÍ

¼ûÄ£ÐÍͼ:

message-flow-simple-broker

´ËͼÀ´Ô´spring-websocket¹Ù·½Îĵµ

¿ÉÒÔ¿´³ö¶ÔÓÚͬһ¶¨ÓÚÄ¿±ê¶¼Îª:/topic/broadcast,ËüµÄ·¢ËÍÇþµÀΪÁ½ÖÖ:/app/broadcastºÍ/topic/broadcast

Èç¹ûΪ/topic/broadcast,Ö±½Ó¿É½«ÏûÏ¢Ìå·¢Ë͸ø¶¨ÓÚÄ¿±ê£¨/topic/broadcast£©¡£

Èç¹ûÊÇ/app/broadcast£¬Ëü½«ÏûÏ¢¶ÔÓ¦ÔÚMessageHandler·½·¨ÖнøÐд¦Àí£¬´¦ÀíºóµÄ½á¹û·¢·Åµ½broker channelÖУ¬×îºóÔÙ½²ÏûÏ¢Ìå·¢Ë͸øÄ¿±ê(/topic/broadcast)

µ±È»£¬ÕâÀï±ßËù˵µÄappǰ׺¾ÍÊǸղÅÎÒÃÇÔÚwebsocketÅäÖÃÖеÄǰ׺.

¿´Ò»¸öÀý×Ó:

Ç°¶Ë¶©ÔÄ:

stompClient.subscribe ('/topic/broadcast', function(greeting){
showGreeting(greeting.body);
});

ºó¶Ë·þÎñ:

@Controller
public class ChatWebSocket extends AbstractWebSocket{
@MessageMapping("broadcast")
public String broadcast (@Payload @Validated Message message, Principal principal) {
return "·¢ËÍÈË: " + principal.getName() + " ÄÚÈÝ: " + message.toString();
}
}

@Data
public class Message {
@NotNull(message = "±êÌâ²»ÄÜΪ¿Õ")
private String title;
private String content;
}

Ç°¶Ë·¢ËÍ:

function sendBroadcast() {
stompClient.send ("/app/broadcast",{},JSON.stringify({'content':'message content'}));
}

ÕâÖÖ·¢Ëͽ«ÏûÏ¢·¢Ë͸øºó¶Ë´øÓÐ@MessageMapping×¢½âµÄ·½·¨£¬È»ºó×éºÏÍêÊý¾ÝÒÔºó£¬ÔÚÍÆË͸ø¶©ÔÄ/topic/broadcastµÄÇ°¶Ë

function sendBroadcast() {
stompClient.send ("/topic/broadcast",{},JSON.stringify({'content':'message content'}));
}

ÕâÖÖ·¢ËÍÖ±½Ó½«ÏûÏ¢·¢Ë͸ø¶©ÔÄ/topic/broadcastµÄÇ°¶Ë£¬²¢²»Í¨¹ý×¢½â·½·¨½øÐÐÁ÷ת¡£

ÎÒÏàÐÅÉÏÊöÕâ¸öÀí½âÒѾ­½âÊÍÇå³þÁËspring websocketµÄÏûϢģÐÍͼ

ͨѶ²ãÉè¼Æ - @MessageMapping

´øÓÐÕâ¸ö×¢½âµÄ@Controllerϵķ½·¨£¬ÕýÊǶÔÓ¦websocketÖеÄÖÐתÊý¾ÝµÄ´¦Àí·½·¨¡£

ÄÇôÕâ¸ö×¢½âϵķ½·¨¾¿¾¹¿ÉÒÔ»ñÈ¡ÄÄЩÊý¾Ý£¬ÆäÖÐÓÐʲôԭÀíÄØ£¿

·½·¨ËµÃ÷

ÎÒ´ó¸Å˵һÏ£º

Message£¬@Payload£¬@Header£¬@Headers £¬MessageHeaders£¬ MessageHeaderAccessor, SimpMessageHeaderAccessor£¬StompHeaderAccessor

ÒÔÉÏÕâЩ¶¼ÊÇ»ñÈ¡ÏûϢͷ£¬ÏûÏ¢Ì壬»òÕû¸öÏûÏ¢µÄ»ù±¾¶ÔÏóÄ£ÐÍ¡£

@DestinationVariable

Õâ¸ö×¢½âÓÃÓÚ¶¯Ì¬¼àÌý·¾¶£¬ºÜÏërestÖеÄ@PathVariable:

e.g.:

@MessageMapping("/queue/chat/{uid}")
public void chat (@Payload @Validated Message message, @DestinationVariable("uid") String uid, Principal principal) {
String msg = "·¢ËÍÈË: " + principal.getName() + " chat ";
simpMessagingTemplate .convertAndSendToUser (uid,"/queue/chat",msg);
}

java.security.Principal

Õâ¸ö¶ÔÏóÎÒÐèÒªÖصã˵һÏ¡£

ËûÔòÊÇspring securityÈÏÖ¤Ö®ºó£¬²úÉúµÄToken¶ÔÏó,¼´±¾ÀýÖеÄUsernamePasswordAuthenticationToken.

UsernamePasswordAuthenticationTokenÀàͼ

²»ÄÑ·¢ÏÖUsernamePasswordAuthenticationTokenÊÇPrincipalµÄÒ»¸öʵÏÖ.

¿ÉÒÔ½«PrincipalÖ±½Óת³ÉÊÚȨºóµÄtoken,½øÐвÙ×÷:

UsernamePasswordAuthenticationToken user = (UsernamePasswordAuthenticationToken) principal;

ÕýÈçÇ°±ßÉè¼ÆÕ½ÚËù˵£¬Õû¸öÓû§Éè¼Æ¶¼ÊǶÔorg.springframework.security.core.userdetails.User½øÐвÙ×÷£¬ÄÇÈçºÎÄõ½User¶ÔÏóÄØ¡£

ºÜ¼òµ¥,ÈçÏÂ:

UsernamePasswordAuthenticationToken user = (UsernamePasswordAuthenticationToken) principal;
User user = (User) user.getPrincipal()

ͨѶ²ãÉè¼Æ - 1-1 && 1-n

1-n topic:

´Ë·½Ê½£¬ÉÏÊöÏûϢģÐÍÕ½ÚÒѾ­½²¹ý£¬´Ë´¦²»ÔÙ׸Êö

1-1 queue:

¿Í·þ-Óû§¹µÍ¨Îª1-1Óû§½»»¥µÄ°¸Àý

Ç°¶Ë:

stompClient.subscribe ('/user/queue/chat',function(greeting){
showGreeting(greeting.body);
});

ºó¶Ë:

@MessageMapping("/queue/chat/{uid}")
public void chat (@Payload @Validated Message message, @DestinationVariable ("uid") String uid, Principal principal) {
String msg = "·¢ËÍÈË: " + principal.getName() + " chat ";
simpMessagingTemplate. convertAndSendToUser (uid,"/queue/chat",msg);
};

·¢ËͶË:

function chat(uid) {
stompClient.send ("/app/queue/chat/" +uid, {},JSON.stringify ({'title': 'hello','content' :'message content'}));
}

ÉÏÊöµÄת»¯£¬¿´ÉÏȥûÓÐtopicÄÇÑù1-nµÄ¹ã²¥ÒªÁ÷³©£¬ÒòΪ´úÂëÖвÉÓÃÔ¼¶¨µÄ·½Ê½½øÐпª·¢£¬µ±È»ÕâÊÇÓÉspringÔ¼¶¨µÄ¡£

Ô¼¶¨×ª»¯µÄ´¦ÀíÆ÷ΪUserDestinationMessageHandler¡£

´ó¸ÅµÄÓïÒåÂß¼­ÈçÏÂ:

¡°An application can send messages targeting a specific user, and Spring¡¯s STOMP support recognizes destinations prefixed with ¡°/user/¡° for this purpose. For example, a client might subscribe to the destination ¡°/user/queue/position-updates¡±. This destination will be handled by the UserDestinationMessageHandler and transformed into a destination unique to the user session, e.g. ¡°/queue/position-updates-user123¡±. This provides the convenience of subscribing to a generically named destination while at the same time ensuring no collisions with other users subscribing to the same destination so that each user can receive unique stock position updates.¡±

´óÖµÄÒâ˼ÊÇ˵:Èç¹ûÊÇ¿Í»§¶Ë¶©ÔÄÁË/user/queue/position-updates, ½«ÓÉUserDestinationMessageHandlerת»¯ÎªÒ»¸ö»ùÓÚÓû§»á»°µÄ¶©ÔĵØÖ·,±ÈÈç/queue/position-updates-user123£¬È»ºó¿ÉÒÔ½øÐÐͨѶ¡£

Àý×ÓÖУ¬ÎÒÃÇ¿ÉÒÔ°Ñuidµ±³ÉÓû§µÄ»á»°£¬ÒòΪÓû§1-1ͨѶÊÇͨ¹ýspring securityÊÚȨµÄ£¬ËùÒÔÎÒÃÇ¿ÉÒ԰ѻỰµ±×öÊÚȨºóµÄtoken.

ÈçµÇ¼Óû§tokenΪ: UsernamePassword AuthenticationToken newToken = new UsernamePassword AuthenticationToken (¡°admin¡±,¡±user¡±);

ÇÒÕâ¸ötokenÊǺϷ¨µÄ£¬ÄÇô/user/queue/chat¶©ÔÄÔòΪ/queue/chat-admin

·¢ËÍʱ£¬Èç¹ûͨ¹ý/user/admin/queue/chat,Ôò²»Í¨¹ý@MessageMappingÖ±½Ó½øÐÐÍÆËÍ¡£

Èç¹ûͨ¹ý/app/queue/chat/admin,Ôò½«ÏûÏ¢ÓÉ@MessageMapping×¢½â´¦Àí£¬×îÖÕ·¢Ë͸ø/user/admin/queue/chatÖÕµã

×·×Ù´úÂësimpMessaging Templat e.convertAndSendToUser:

@Override
public void convertAndSendToUser(String user, String destination, Object payload, Map<String, Object> headers,
MessagePostProcessor postProcessor) throws MessagingException {

Assert.notNull(user, "User must not be null");
user = StringUtils.replace (user, "/", "%2F");
super.convertAndSend (this.destinationPrefix + user + destination, payload, headers, postProcessor);
}

˵Ã÷×îºóµÄ·¾¶ÒÀÈ»ÊÇ/user/admin/queue/chatÖÕµã.

ͨѶ²ãÉè¼Æ - @SubscribeMapping

@SubscribeMapping×¢½â¿ÉÒÔÍê³É¶©Ôļ´·µ»ØµÄ¹¦ÄÜ¡£

Õâ¸öºÜÏñHTTPµÄrequest-response£¬µ«²»Í¬µÄÊÇHTTPµÄÇëÇóºÍÏìÓ¦ÊÇͬ²½µÄ£¬Ã¿´ÎÇëÇó±ØÐëµÃµ½ÏìÓ¦¡£

¶ø@SubscribeMappingÔòÊÇÒì²½µÄ¡£Òâ˼ÊÇ˵£ºµ±¶©ÔÄʱ£¬Ö±µ½»ØÓ¦¿ÉÏìӦʱÔÚ½øÐд¦Àí¡£

ͨѶ²ãÉè¼Æ - Òì³£´¦Àí

@MessageMappingÊÇÖ§³Öjsr 303УÑéµÄ£¬ËüÖ§³Ö@Validated×¢½â£¬¿ÉÅ׳ö´íÎóÒì³£,ÈçÏÂ:

@MessageMapping ("broadcast")
public String broadcast (@Payload @Validated Message message, Principal principal) {
return "·¢ËÍÈË: " + principal.getName() + " ÄÚÈÝ: " + message.toString();
}

ÄÇÒì³£ÈçºÎ´¦ÀíÄØ

@MessageExceptionHandler,Ëü¿ÉÒÔ½øÐÐÏûÏ¢²ãµÄÒì³£´¦Àí

@MessageExceptionHandler
@SendToUser (value = "/queue/error",broadcast = false)
public String handleException (MethodArgumentNotValidException methodArgumentNotValidException) {
BindingResult bindingResult = methodArgumentNotValidException .getBindingResult();
if (!bindingResult.hasErrors()) {
return "δ֪´íÎó";
}
List<FieldError> allErrors = bindingResult.getFieldErrors();
return "jsr 303 ´íÎó: " + allErrors.iterator().next() .getDefaultMessage();
}

ÆäÖÐ@SendToUser£¬ÊÇÖ¸Ö»½«ÏûÏ¢·¢Ë͸øµ±Ç°Óû§£¬µ±È»£¬µ±Ç°Óû§ÐèÒª¶©ÔÄ/user/queue/errorµØÖ·¡£

×¢½âÖÐbroadcast,Ôò±íÃ÷ÏûÏ¢²»½øÐжà»á»°µÄ´«²¥(ÓпÉÄÜÒ»¸öÓû§µÇ¼3¸öä¯ÀÀÆ÷£¬ÓÐÈý¸ö»á»°)£¬Èç¹û´Ëbroadcast=false£¬ÔòÖ»´«¸øµ±Ç°»á»°£¬²»½øÐÐÆäËû»á»°´«²¥

×ܽá

±¾ÎÄ´ÓwebsocketµÄÔ­ÀíºÍЭÒ飬ÒÔ¼°ÄÚÈÝÏà¹ØЭÒéµÈ²»Í¬Î¬¶È½øÐÐÁËÏêϸ½éÉÜ¡£

×îÖÕÒÔÒ»¸öÓ¦Ó󡾰ΪÀý£¬´ÓÏîÄ¿µÄ½á¹¹Éè¼Æ£¬ÒÔ¼°´úÂë²ßÂÔÉè¼Æ£¬Éè¼ÆģʽµÈ²»Í¬·½ÃæչʾÁËwebsocketµÄͨѶ¹¦ÄÜÔÚÏîÄ¿ÖеÄʹÓá£

ÈçºÎʵÏÖijһ¹¦ÄÜÆäʵ²¢²»ÖØÒª£¬ÖØÒªµÄÊǵÃÁ˽âÀíÂÛ£¬ÉîÈëÀíÂÛÖ®ºó£¬ÔÙ½øÐпª·¢¡£

 

   
3869 ´Îä¯ÀÀ       19
Ïà¹ØÎÄÕÂ

Éî¶È½âÎö£ºÇåÀíÀôúÂë
ÈçºÎ±àд³öÓµ±§±ä»¯µÄ´úÂë
Öع¹-ʹ´úÂë¸ü¼ò½àÓÅÃÀ
ÍŶÓÏîÄ¿¿ª·¢"±àÂë¹æ·¶"ϵÁÐÎÄÕÂ
Ïà¹ØÎĵµ

Öع¹-¸ÄÉƼÈÓдúÂëµÄÉè¼Æ
Èí¼þÖع¹v2
´úÂëÕû½àÖ®µÀ
¸ßÖÊÁ¿±à³Ì¹æ·¶
Ïà¹Ø¿Î³Ì

»ùÓÚHTML5¿Í»§¶Ë¡¢Web¶ËµÄÓ¦Óÿª·¢
HTML 5+CSS ¿ª·¢
ǶÈëʽC¸ßÖÊÁ¿±à³Ì
C++¸ß¼¶±à³Ì