睿阳知识库 睿阳知识库
首页
  • npm库配置
  • PC端

    • npm常用命令
    • vue问题记录
    • SEO基础知识及优化
    • 禁止别人调试我的前端页面代码
  • 移动端

    • 小程序
    • Risun.js使用说明
  • Java

    • Maven库配置
    • RSP开发框架
    • RSP框架插件
  • .NET

    • Nuget库配置
  • Python

    • Pypi库配置
  • 常见问题

    • Word转Pdf字体错乱
    • 使用Jacob进行Word导出PDF
  • 自动部署
  • 前端带路径
  • Linux

    • 应用部署
  • Windows

    • 应用部署
  • 视频监控
  • MySQL系列~
  • 应用高可用
  • 静态代码扫描
  • OpenSSH版本升级
  • 区块链~
  • 软件过程文档目录
  • 著作权申请须知及申报示例
  • 项目申报技巧
  • 项目竣工资料清单
  • 科技项目申报流程及注意事项
  • 初级职称申报
  • 产品需求文档基础知识
  • 产品经理需了解的技术知识
  • 墨刀原型设计指南
  • 文档规范
  • 文档规范
  • 投标工作总结(一)
  • 科技项目申报心得体会
  • 数字孪生
  • AI
  • RSP基础平台
  • RMCloud
  • 区块链
  • 网络态势感知
  • 国产化
  • 数据湖
  • 贡献度
  • 文档编写说明
  • Markdown教程
工作链接
首页
  • npm库配置
  • PC端

    • npm常用命令
    • vue问题记录
    • SEO基础知识及优化
    • 禁止别人调试我的前端页面代码
  • 移动端

    • 小程序
    • Risun.js使用说明
  • Java

    • Maven库配置
    • RSP开发框架
    • RSP框架插件
  • .NET

    • Nuget库配置
  • Python

    • Pypi库配置
  • 常见问题

    • Word转Pdf字体错乱
    • 使用Jacob进行Word导出PDF
  • 自动部署
  • 前端带路径
  • Linux

    • 应用部署
  • Windows

    • 应用部署
  • 视频监控
  • MySQL系列~
  • 应用高可用
  • 静态代码扫描
  • OpenSSH版本升级
  • 区块链~
  • 软件过程文档目录
  • 著作权申请须知及申报示例
  • 项目申报技巧
  • 项目竣工资料清单
  • 科技项目申报流程及注意事项
  • 初级职称申报
  • 产品需求文档基础知识
  • 产品经理需了解的技术知识
  • 墨刀原型设计指南
  • 文档规范
  • 文档规范
  • 投标工作总结(一)
  • 科技项目申报心得体会
  • 数字孪生
  • AI
  • RSP基础平台
  • RMCloud
  • 区块链
  • 网络态势感知
  • 国产化
  • 数据湖
  • 贡献度
  • 文档编写说明
  • Markdown教程
工作链接
  • Java

    • Maven库配置
    • RSP开发框架
    • RSP框架插件
    • 框架插件

      • 工作流
      • Word、PDF、Excel增强
      • 消息提醒
        • 一. [项目]-framework 模块
          • 1. 修改pom.xml
          • 2. 修改SecurityConfig.java
          • 3. 添加新文件
        • 二. [项目]-ui 模块
          • 1. 修改环境信息
          • 2. 修改 vue.config.js
          • 3. 修改 Navbar.vue
        • 三. 生产环境 Nginx 配置
      • 资源打包成ZIP下载
      • 区分多个项目Redis缓存
      • 留言评论
      • 内部消息队列
      • 文件预览增强
      • 在线Excel报表设计
      • 自定义高级查询
  • .NET

  • Python

  • 常见问题

  • 后端
  • Java
  • 框架插件
孙超
2022-12-12
目录

消息提醒

框架添加了消息提醒的功能,主版本RSP框架已包含此功能,老版本框架若要使用,请进行如下操作,集成功能:

# 一. [项目]-framework 模块

# 1. 修改pom.xml

添加 WebSocket 依赖

<!-- springboot WebSocket -->
<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-websocket</artifactId>  
</dependency>

# 2. 修改SecurityConfig.java

修改 configure(HttpSecurity httpSecurity) 方法,添加匿名访问

  // 对于登录login 注册register 验证码captchaImage 允许匿名访问
-    .antMatchers("/login", "/register", "/captchaImage", "/sendLoginSmsCode/**").permitAll()
+    .antMatchers("/login", "/register", "/captchaImage", "/sendLoginSmsCode/**", "/websocket/**").permitAll()

# 3. 添加新文件

在com.risun.framework下,创建包websocket,在其中添加4个java文件


WebSocketMsg.java
package com.risun.framework.websocket;

import java.io.Serializable;
import java.util.Map;

import com.google.common.collect.Maps;

import cn.hutool.core.collection.CollUtil;
import lombok.Data;

/**
* 消息信息
* 
* @author dante
*
*/
@Data
public class WebSocketMsg implements Serializable {

  private static final long serialVersionUID = 1L;
  
  /** 
  * 消息标题
  */
  private String title;
  
  /**
  * 消息内容 
  */
  private String content;
  
  /**
  * 额外信息
  */
  private Map<String, Object> extra;
  
  public void addExtra(String key, Object val) {
    if(CollUtil.isEmpty(extra)) {
      this.extra = Maps.newHashMap();
    }
    this.extra.put(key, val);
  }
}

WebSocketConfig.java
package com.risun.framework.websocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
* WebSocket 配置
* 
* @author dante
*
*/
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

WebSocketClient.java
package com.risun.framework.websocket;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.Session;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;

/**
* websocket 客户端用户集
* 
* @author sunchao
*/
@Slf4j
public class WebSocketClient {

    /**
    * 用户集
    */
    private static Map<String, Session> USERS = new ConcurrentHashMap<String, Session>();

    /**
    * 存储用户
    *
    * @param userName 用户名
    * @param session 用户信息
    */
    public static void put(String userName, Session session) {
        USERS.put(userName, session);
    }
  
    /**
    * 获取用户名
    * 
    * @param session
    * @return
    */
    public static String getUserName(Session session) {
        String key = null;
        boolean flag = USERS.containsValue(session);
        if (flag) {
            Set<Map.Entry<String, Session>> entries = USERS.entrySet();
            for (Map.Entry<String, Session> entry : entries) {
                Session value = entry.getValue();
                if (value.equals(session)) {
                    key = entry.getKey();
                    break;
                }
            }
        }
        return key;
    }

  /**
  * 移除用户
  *
  * @param session 用户信息
  *
  * @return 移除结果
  */
  public static boolean remove(Session session) {
      String key = null;
      boolean flag = USERS.containsValue(session);
      if (flag) {
          Set<Map.Entry<String, Session>> entries = USERS.entrySet();
          for (Map.Entry<String, Session> entry : entries) {
            Session value = entry.getValue();
            if (value.equals(session)) {
                key = entry.getKey();
                break;
            }
          }
      } else {
          return true;
      }
      return remove(key);
  }

  /**
  * 移出用户
  *
  * @param key 键
  */
  public static boolean remove(String key) {
      Session remove = USERS.remove(key);
      if (remove != null) {
          boolean containsValue = USERS.containsValue(remove);
          return containsValue;
      } else {
          return true;
      }
  }

  /**
  * 获取在线用户列表
  *
  * @return 返回用户集合
  */
  public static Map<String, Session> getUsers() {
      return USERS;
  }

  /**
  * 群发消息文本消息
  *
  * @param message 消息内容
  */
  public static void sendMessageToAll(WebSocketMsg message) {
      Set<String> keys = USERS.keySet();
      for (String userName : keys) {
          sendMessageToUser(userName, message);
      }
  }

  /**
  * 发送文本消息
  *
  * @param userName 用户名
  * @param message  消息内容
  */
  public static void sendMessageToUser(String userName, WebSocketMsg message) {
      Session session = USERS.get(userName);
      if (session != null) {
        try {
            session.getBasicRemote().sendText(JSON.toJSONString(message));
        } catch (Exception e) {
            log.error("[你已离线]", e);
        }
      } else {
          log.info("[{}已离线]", userName);
      }
  }
}

WebSocketServer.java
package com.risun.framework.websocket;

import java.io.IOException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

/**
* WebSocket 消息处理
* 
* @author sunchao
*/
@Slf4j
@Component
@ServerEndpoint("/websocket/message/{userName}")
public class WebSocketServer {

    /**
    * 连接建立成功调用的方法
    * 
    * @param userName 当前登录用户
    */
    @OnOpen
    public void onOpen(Session session, @PathParam("userName") String userName) throws Exception {
      if(StrUtil.isEmpty(userName)) {
          log.info("未登录系统!");
          session.close();
      } else {
          // 添加用户
          WebSocketClient.put(userName, session);
          // 获取当前用户的待办信息,发送消息给用户
          /*
          WebSocketMsg msg = new WebSocketMsg();
          msg.setTitle("待办信息");
          msg.setContent("你有一条待办信息待处理!");
          msg.addExtra("url", "/demo/test");
          WebSocketClient.sendMessageToUser(userName, msg);
          */
      }
    }

    /**
    * 连接关闭时处理
    */
    @OnClose
    public void onClose(Session session) {
        log.info("关闭连接 - {}", session);
        // 移除用户
        WebSocketClient.remove(session);
    }

    /**
    * 抛出异常时处理
    */
    @OnError
    public void onError(Session session, Throwable exception) throws Exception {
        if (session.isOpen()) {
            // 关闭连接
            session.close();
        }
        String sessionId = session.getId();
        log.info("连接异常 - {}", sessionId);
        log.info("异常信息 - {}", exception);
        // 移出用户
        WebSocketClient.remove(session);
    }

    /**
    * 服务器接收到客户端消息时调用的方法
    * 
    * @throws IOException 
    */
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        String userName = WebSocketClient.getUserName(session);
        if(StrUtil.isEmpty(userName)) {
            log.info("未登录系统!");
            session.close();
        } else {
            WebSocketMsg msg = new WebSocketMsg();
            msg.setTitle(message);
            msg.setContent(message);
            WebSocketClient.sendMessageToUser(userName, msg);
        }
    }
}

# 二. [项目]-ui 模块

# 1. 修改环境信息

修改 .env.development、.env.staging、.env.production

  • .env.development

添加配置

VUE_SOCKET_BASE_API = '/dev-socket'
  • .stage.development 添加配置
VUE_SOCKET_BASE_API = '/stage-socket'
  • .prod.development 添加配置
VUE_SOCKET_BASE_API = '/prod-socket'

# 2. 修改 vue.config.js

在 devServer 下,进行如下修改

devServer: {
  ...
  proxy: {
    [process.env.VUE_APP_BASE_API]: {
      target: `http://localhost:9080`,
      changeOrigin: true,
      pathRewrite: {
        ['^' + process.env.VUE_APP_BASE_API]: ''
      }
    },
    [process.env.VUE_SOCKET_BASE_API]: {
      target: 'http://localhost:9080',
      ws: true, // 开启websocket代理
      changeOrigin: true,
      pathRewrite: {
        ['^' + process.env.VUE_SOCKET_BASE_API]: ''
      }
    }
  }
  ...
}

# 3. 修改 Navbar.vue

新增内容如下:

data() {
  return {
    ws: null
  }
},

...

mounted() {
  // 建立WebSocket连接,进行消息提醒(若项目中无需求,可注释或删除该行代码)
  this.connWS()
},

... 

methods: {
  ...

  connWS() {
    const user = this.$store.state.user
    if(user == null) {
      return;
    }
    const { host } = location
    const wsuri = `ws://${host}${process.env.VUE_APP_BASE_API}/websocket/message/${user.name}`;
    this.ws = new WebSocket(wsuri);
    const self = this;
    this.ws.onopen = function (event) {
      console.log('已建立WebSocket连接!')
    };
    this.ws.onmessage = function (event) {
      self.notifyUser(event.data)
    };
    this.ws.onclose = function (event) {
      console.log('已关闭WebSocket连接!')
    };
  },
  notifyUser(msg) {
    const data = JSON.parse(msg)
    const that = this
    this.$notify({
      title: data.title,
      type: 'success',
      iconClass: 'el-icon-info',
      message: data.content,
      onClick() {
        that.handleNotifyClick(data)
      }
    });
  },
  handleNotifyClick(data) {
    // 按项目需求实现相关业务逻辑
    console.log(data)
  }
}

修改内容:

修改 logout() 方法,在 this.$store.dispatch 之前,添加代码

if (this.ws) {
  this.ws.close();
  this.ws = null;
}

# 三. 生产环境 Nginx 配置

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    server {
        ...
        location ^~/socket/ {
            proxy_pass http://x.x.x.x:8080/;
            proxy_http_version 1.1; 
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Upgrade websocket;
            proxy_set_header Connection Upgrade;
        }
        ...
    }
}   
Word、PDF、Excel增强
资源打包成ZIP下载

← Word、PDF、Excel增强 资源打包成ZIP下载→

最近更新
01
vue问题记录
10-11
02
RSP进度
10-09
03
贡献度
09-28
更多文章>
Copyright © 2014-2025 甘肃睿阳科技有限公司 陇ICP备15001783-1号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式