當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
SpringBoot 集成WebSocket
生活随笔
收集整理的這篇文章主要介紹了
SpringBoot 集成WebSocket
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
什么是WebSocket
WebSocket 是一種網絡通信協議,很多高級功能都需要它。
我們已經有了 HTTP 協議,為什么還需要另一個協議?它能帶來什么好處?
因為 HTTP 協議有一個缺陷:通信只能由客戶端發起。
如果我們想要服務器給客戶端發信息,只能由客戶端建立長連接這種消耗性能的操作。
WebSocket 協議在2008年誕生,2011年成為國際標準。所有瀏覽器都已經支持了。
它的最大特點就是,服務器可以主動向客戶端推送信息,客戶端也可以主動向服務器發送信息,是真正的雙向平等對話,屬于服務器推送技術的一種。
詳細的WebSocket可以參考阮一峰的博客 :http://www.ruanyifeng.com/blog/2017/05/websocket.html
Maven 依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency>SpringBoot配置
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** Created with IntelliJ IDEA.** @Auther: zlf* @Date: 2021/04/30/16:58* @Description:*/ @Configuration //@EnableWebSocketMessageBroker public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}}WebSokect 通信
import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component;import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet;/*** Created with IntelliJ IDEA.** @Auther: zlf* @Date: 2021/04/30/17:48* @Description:*/ @Slf4j @ServerEndpoint("/webSocket/{code}") @Component public class WebSocketServer {/*** concurrent包的線程安全Set,用來存放每個客戶端對應的WebSocket對象。*/private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();/*** 與客戶端的連接會話,需要通過它來給客戶端發送數據*/private Session session;/*** 接收識別碼*/private String code = "";/*** 連接建立成功調用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("code") String code) {this.session = session;//如果存在就先刪除一個,防止重復推送消息,實際這里實現了set,不刪除問題也不大webSocketSet.removeIf(webSocket -> webSocket.code.equals(code));webSocketSet.add(this);this.code = code;log.info("建立WebSocket連接,code:" + code+",當前連接數:"+webSocketSet.size());}/*** 連接關閉調用的方法*/@OnClosepublic void onClose() {webSocketSet.remove(this);log.info("關閉WebSocket連接,code:" + this.code+",當前連接數:"+webSocketSet.size());}/*** 收到客戶端消息后調用的方法** @param message 客戶端發送過來的消息*/@OnMessagepublic void onMessage(String message, Session session) {log.info("收到來[" + code + "]的信息:" + message);}@OnErrorpublic void onError(Session session, Throwable error) {log.error("websocket發生錯誤");error.printStackTrace();}/*** 實現服務器主動推送*/private void sendMessage(String message) throws IOException {this.session.getBasicRemote().sendText(message);}/*** 群發自定義消息*/public void sendAll(String message) {log.info("推送消息到" + code + ",推送內容:" + message);for (WebSocketServer item : webSocketSet) {try {item.sendMessage(message);} catch (IOException e) {e.printStackTrace();}}}/*** 定點推送*/public void sendTo(String message, @PathParam("code") String code) {for (WebSocketServer item : webSocketSet) {try {if (item.code.equals(code)) {log.info("推送消息到[" + code + "],推送內容:" + message);item.sendMessage(message);}} catch (IOException e) {e.printStackTrace();}}}@Overridepublic boolean equals(Object o) {if (this == o) {return true;}if (o == null || getClass() != o.getClass()) {return false;}WebSocketServer that = (WebSocketServer) o;return Objects.equals(session, that.session) &&Objects.equals(code, that.code);}@Overridepublic int hashCode() {return Objects.hash(session, code);} }這樣前端發起相應的請求就可以建立雙向的通信。
#前端Vue代碼
<template><div>websocket</div> </template><script> export default {data(){return{user : JSON.parse(localStorage.getItem("user"))?JSON.parse(localStorage.getItem("user")):null}},created(){this.initWebSocket();},methods: {initWebSocket(){ //初始化weosocket// 建立連接 在請求中帶上token 由SpringSecurity進行權限認證const wsuri = "ws://localhost:8001/webSocket/"+this.user.id+'?Authorization='+localStorage.getItem("token");this.websock = new WebSocket(wsuri);this.websock.onmessage = this.websocketonmessage;this.websock.onopen = this.websocketonopen;this.websock.onerror = this.websocketonerror;this.websock.onclose = this.websocketclose;},websocketonopen(){ //連接建立之后執行send方法發送數據let actions = {"test":"12345"};this.websocketsend(JSON.stringify(actions));},websocketonerror(){//連接建立失敗重連console.log("----連接失敗,,重連")this.initWebSocket();},websocketonmessage(e){ //數據接收//const redata = JSON.parse(e.data);console.log(e.data);},websocketsend(Data){//數據發送this.websock.send(Data);},websocketclose(e){ //關閉console.log('斷開連接',e);},}, } </script><style></style>關于權限認證
import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.youshe.mcp.utils.JwtTokenUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.List;/*** @Description: JWT登錄授權過濾器* @Author: zlf* @Date: 2021/3/30*/ @Component @Slf4j public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Autowiredprivate JwtTokenUtil jwtTokenUtil;@Value("${jwt.tokenHeader}")private String tokenHeader;@Value("${jwt.tokenHead}")private String tokenHead;@Autowiredprivate MyUserDetailsService userDetailsService;@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain) throws ServletException, IOException {String authHeader = request.getHeader(this.tokenHeader);if(StringUtils.isBlank(authHeader)){// 由于webSocket 沒有設置token在請求頭里,而在url中// websocket連接時,令牌放在url參數上,authHeader = request.getParameter(this.tokenHeader);}if (authHeader != null && authHeader.startsWith(this.tokenHead)) {String authToken = authHeader.substring(this.tokenHead.length());// The part after "Bearer "String username = jwtTokenUtil.getUserNameFromToken(authToken);//log.info("checking username:{}", username);if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {UserDetails userDetails = userDetailsService.loadUserByUsername(username);if (jwtTokenUtil.validateToken(authToken, userDetails)) {UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, new BCryptPasswordEncoder().encode(userDetails.getPassword()), userDetails.getAuthorities());authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));//log.info("authenticated user:{}", username);SecurityContextHolder.getContext().setAuthentication(authentication);}}}chain.doFilter(request, response);}}測試
import com.youshe.commonutils.vo.ResultVo; import com.youshe.mcp.entity.User; import com.youshe.mcp.service.UserService; import com.youshe.mcp.service.WebSocketServer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import springfox.documentation.annotations.ApiIgnore; import sun.plugin.liveconnect.SecurityContextHelper;import javax.xml.transform.Result; import java.security.Security;/*** Created with IntelliJ IDEA.** @Auther: zlf* @Date: 2021/04/30/18:03* @Description:*/ @RestController @RequestMapping("/test") public class testController {@AutowiredUserService userService;@AutowiredWebSocketServer webSocketServer;// 向請求的用戶 推送消息@GetMapping("test")public ResultVo test(){UserDetails userDetails = (UserDetails) org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication().getPrincipal();String username = userDetails.getUsername();User user = userService.getUserByName(username);webSocketServer.sendTo("向客戶端推送實時消息",user.getId());return ResultVo.ok();} }效果
總結
以上是生活随笔為你收集整理的SpringBoot 集成WebSocket的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CentOS 7 搭建RAP2r Api
- 下一篇: Git报错: OpenSSL SSL_c