• springboot shiro vue使用websocket案例


    今天在springboot 中调试websocket,然后发现被shiro拦截了,具体解决办法如下:

    在shiro 拦截器中配置websoket不需认证:

    1. @Bean("shiroFilter")
    2. public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
    3. ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
    4. shiroFilter.setSecurityManager(securityManager);
    5. //oauth过滤
    6. Map<String, Filter> filters = new HashMap<>();
    7. filters.put("oauth2", new OAuth2Filter());
    8. shiroFilter.setFilters(filters);
    9. Map<String, String> filterMap = new LinkedHashMap<>();
    10. filterMap.put("/sys/login", "anon");
    11. filterMap.put("/swagger/**", "anon");
    12. filterMap.put("/index/**", "anon");
    13. filterMap.put("/libs/**", "anon");
    14. filterMap.put("/home/**", "anon");
    15. filterMap.put("/v2/api-docs", "anon");
    16. filterMap.put("/swagger-ui.html", "anon");
    17. filterMap.put("/swagger-resources/**", "anon");
    18. filterMap.put("/captcha.jpg", "anon");
    19. filterMap.put("/aaa.txt", "anon");
    20. filterMap.put("/webSocket/**", "anon"); //配置websocket不需认证
    21. filterMap.put("/**", "oauth2");
    22. shiroFilter.setFilterChainDefinitionMap(filterMap);
    23. return shiroFilter;
    24. }

    websocket服务器端代码如下:

    pom.xml中引入

    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-websocket</artifactId>
    4. </dependency>

    开启注解

    1. /**
    2. * websocket 配置类
    3. */
    4. @Configuration
    5. public class WebSocketConfig {
    6. /**
    7. * ServerEndpointExporter 作用
    8. *
    9. * 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint
    10. *
    11. * @return
    12. */
    13. @Bean
    14. public ServerEndpointExporter serverEndpointExporter() {
    15. return new ServerEndpointExporter();
    16. }
    17. }

    新建websocket服务类

    1. import lombok.extern.slf4j.Slf4j;
    2. import org.springframework.stereotype.Component;
    3. import javax.websocket.*;
    4. import javax.websocket.server.PathParam;
    5. import javax.websocket.server.ServerEndpoint;
    6. import java.io.IOException;
    7. import java.util.concurrent.ConcurrentHashMap;
    8. import java.util.concurrent.atomic.AtomicInteger;
    9. /**
    10. * websocket 服务类
    11. */
    12. @ServerEndpoint("/webSocket/{token}")
    13. @Component
    14. @Slf4j
    15. public class WebSocketServer {
    16. //静态变量,用来记录当前在线连接数
    17. private static AtomicInteger onlineNum = new AtomicInteger();
    18. //concurrent包的线程安全set,用来存放每个客户端对应的webSocketServer对象;
    19. private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<String, Session>();
    20. //发送消息
    21. public void sendMessage(Session session, String message) throws IOException {
    22. if (session != null) {
    23. synchronized (session) {
    24. session.getBasicRemote().sendText(message);
    25. }
    26. }
    27. }
    28. //给指定的用户发送消息,token为用户登录后的令牌
    29. public void sendInfo(String token, String message) {
    30. Session session = sessionPools.get(token);
    31. try {
    32. sendMessage(session, message);
    33. } catch (Exception e) {
    34. log.error("webSocket发送消息失败:"+token, e);
    35. }
    36. }
    37. //建立连接成功调用
    38. @OnOpen
    39. public void onOpen(Session session, @PathParam(value="token") String token) {
    40. sessionPools.put(token, session);
    41. addOnlineCount();
    42. }
    43. //关闭连接时调用
    44. @OnClose
    45. public void onClose(@PathParam(value="token") String token) {
    46. if (StringUtils.isNotEmpty(token)) {
    47. sessionPools.remove(token);
    48. subOnlineCount();
    49. }
    50. }
    51. //收到客户端消息
    52. @OnMessage
    53. public void onMessage(String message) {
    54. for (Session session : sessionPools.values()) {
    55. try {
    56. sendMessage(session, message);
    57. } catch (Exception e) {
    58. log.error("webSocket 发送消息失败:", e);
    59. continue;
    60. }
    61. }
    62. }
    63. @OnError
    64. public void onError(Throwable error) {
    65. log.error("websocket出错", error.getMessage());
    66. }
    67. public static void addOnlineCount() {
    68. onlineNum.incrementAndGet();
    69. }
    70. public static void subOnlineCount() {
    71. onlineNum.decrementAndGet();
    72. }
    73. }

    服务器调用直接注入服务

    1. @Autowired
    2. private WebSocketServer webSocketServer;
    1. WebSocketInfo info = WebSocketInfo.builder().message("你有一条消息需要处理!").build();
    2. webSocketServer.sendInfo(token, JsonMapper.toJsonString(info));

    前端代码:

    1. mounted() {
    2. this.initWebSocket()
    3. },
    4. methods: {
    5. initWebSocket () {
    6. let host = document.location.host;
    7. let token = this.$cookie.get("token")
    8. let socketUrl = "ws://localhost:8090/jg/webSocket/" + token
    9. this.websock = new WebSocket(socketUrl);//这个连接ws://固定,后面的根据自己的IP和端口进行改变,我设置监听是8090
    10. this.websock.onmessage = this.webSocketOnMessage
    11. this.websock.onerror = this.webSocketOnError
    12. this.websock.onopen = this.webSocketOnOpen
    13. this.websock.onclose = this.webSocketClose
    14. },
    15. webSocketOnOpen () { //打开
    16. this.websock.send("发送数据");
    17. },
    18. webSocketOnError () { //连接错误
    19. console.log( 'WebSocket连接失败')
    20. },
    21. webSocketOnMessage (e) { // 数据接收
    22. let obj = JSON.parse(e.data)
    23. this.$message({
    24. type: 'info',
    25. message: obj.message,
    26. duration: 1000,
    27. })
    28. },
    29. webSocketClose (e) { // 关闭连接
    30. console.log('已关闭连接', e)
    31. }
    32. },
    33. destroyed () {
    34. if (this.websock != null) {
    35. this.websock.close() // 页面销毁后断开websocket连接
    36. }
    37. }

    其中websocket路径配置:ws://localhost:8090/jg/webSocket/ 加了前缀是因为springboot配置了前缀:

    1. server:
    2. tomcat:
    3. uri-encoding: UTF-8
    4. max-threads: 1000
    5. min-spare-threads: 30
    6. port: 8090
    7. connection-timeout: 5000ms
    8. servlet:
    9. context-path: /jg

    《思考中医》​​​​​​​

  • 相关阅读:
    灰度升级 TiDB Operator
    Java内部类有坑,100%内存泄露!
    http进一步认识
    Golang学习笔记01
    声明式事务管理参数配置
    【SpringBoot】还不会SpringBoot项目模块分层?来这手把手教你
    .m3u8.sqlite文件转mp4,m3u8.sqlite文件转视频工具(开源免费)
    【计网】链路层
    MAX98390CEWX D类放大器,集成动态扬声器管理(MAX98390)
    【线性代数基础进阶】向量-补充+练习
  • 原文地址:https://blog.csdn.net/kan_Feng/article/details/127110589