Spring clound+VUE+WebSocket实现消息推送 一(即时通讯)

需求:

  当用户进行某个操作,需要通知其他用户时,其他用户可以实时接收消息。

  工程为 Spring cloud + VUE 。

技术实现:

  Spring Cloud、Spring boot、vue、webSocket等。

流程

用户登录系统→连接到socket服务进行监听→页面用户操作某业务→调用socket服务传递json消息→socket服务推送消息到其他用户页面→收到消息解析json进行其他业务处理

通讯json

目前推送的有:业务的ID、业务的类型、推送的简约内容

============================新建服务====================================================

一:新建socket服务,聚合到父工程里(不会的去复习下spring boot)

1:配置socket属性文件application.yml,兼容后面文章的离线通讯

#eureka注册中心地址
eureka:
  instance:
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://XXX.XXX.XXX.XXX:8060/eureka/
    register-with-eureka: true
    fetch-registry: true
 
server:
  port: 9002
  servlet:
    context-path: /
spring:
  application:
    name: api-webSocket
  datasource:
    driver-class-name: oracle.jdbc.OracleDriver
    url: jdbc:oracle:thin:@XXX.XXX.XXX:8098:XE
    username: XXX
    password: XXX
    type: com.alibaba.druid.pool.DruidDataSource
    #最大活跃数
    maxActive: 20
    #初始化数量
    initialSize: 5
    #最大连接等待超时时间
    maxWait: 60000
  redis:
    host: XXX.XXX.XXX.XXX
    # 端口
    port: 6379
    # 超时时间
    timeout: 5000
    jedis:
      pool:
        #连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: 3000
        #连接池最大连接数(使用负值表示没有限制)
        max-active: 200
        #连接池中的最大空闲连接
        max-idle: 20
        #连接池中最小空闲连接
        min-idle: 2
  # MyBatis
mybatis:
  # 搜索指定包别名
  typeAliasesPackage:  com.fencer.rcdd
  # 配置mapper的扫描,找到所有的mapper.xml映射文件
  mapperLocations: classpath*:mapper/**/*Mapper.xml

# 日志配置
logging:
        level:
          com.fencer: debug
          org.springframework: WARN
          org.spring.springboot.dao: debug

2:父工程添加相关依赖pom.xml

 

	<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-websocket</artifactId>
			<version>2.0.4.RELEASE</version>
		</dependency>

3:新建socket配置类

package com.XXX.io.ws;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
 * 类描述:
 *
 * @author :carry
 * @version: 1.0  CreatedDate in  2019年09月24日
 * <p>
 * 修订历史: 日期			修订者		修订描述
 */
@Configuration
public class WebSocketConfig {

    /** 
    * @方法描述: 注入ServerEndpointExporter,
     *      * 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
    * @return: org.springframework.web.socket.server.standard.ServerEndpointExporter
    * @Author: carry
    */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

 4:新建服务类

package com.fencer.io.ws;

import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 类描述:
 *
 * @author :carry
 * @version: 1.0  CreatedDate in  2019年09月24日
 * <p>
 * 修订历史: 日期			修订者		修订描述
 */
@Component
@ServerEndpoint(value = "/websocket/{userId}")//设置访问URL
public class WebSocket {
    //静态变量,用来记录当前在线连接数。
    private static int onlineCount = 0;

    private Session session;

    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>();
    //与某个客户端的连接会话,需要通过它来给客户端发送数据
    private static Map<String, Session> sessionPool = new HashMap<String, Session>();

    /**
     * @方法描述: 开启socket
     * @return: void
     * @Author: carry
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId) {
        this.session = session;
        webSockets.add(this);//加入set中
        addOnlineCount();           //在线数加1
        sessionPool.put(userId, session);//把对应用户id的session放到sessionPool中,用于单点信息发送
        System.out.println("【websocket消息】 有新连接加入!用户id" + userId + ",当前在线人数为" + getOnlineCount());
    }

    /**
     * @方法描述: 关闭socket
     * @return: void
     * @Author: carry
     */
    @OnClose
    public void onClose() {
        webSockets.remove(this);
        subOnlineCount();           //在线数减1
        System.out.println("【websocket消息】 连接断开!当前在线人数为" + getOnlineCount());
    }

    /**
     * @方法描述: 收到客户端消息
     * @return: void
     * @Author: carry
     */
    @OnMessage
    public void onMessage(String message) {
        System.out.println("【websocket消息】收到客户端消息:" + message);
    }

    /**
     * @方法描述: 广播消息全体发送
     * @return: void
     * @Author: carry
     */
    public void sendAllMessage(String message) {
        for (WebSocket webSocket : webSockets) {
            System.out.println("【websocket消息】广播消息:" + message);
            try {
                webSocket.session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @方法描述: 一对一单点消息
     * @return: void
     * @Author: carry
     */
    public  void  sendOneMessage(String userId, String message) {
        try {
            // 防止推送到客户端的信息太多导致弹窗太快
            Thread.sleep(500);
            System.out.println("用户"+userId+"【websocket消息】单点消息:" + message);
            Session session = sessionPool.get(userId);
            if (session != null) {
                // getAsyncRemote是异步发送,加锁防止上一个消息还未发完下一个消息又进入了此方法
                // 也就是防止多线程中同一个session多次被调用报错,虽然上面睡了0.5秒,为了保险最好加锁
                synchronized (session) {
                    session.getAsyncRemote().sendText(message);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @方法描述: 发生错误时调用
     * @return: void
     * @Author: carry
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("发生错误");
        error.printStackTrace();
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocket.onlineCount--;
    }
}

5:对外暴露接口

package com.XX.io.ws;

import com.XX.common.base.AjaxResult;
import com.XX.common.base.BaseController;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 类描述:
 *
 * @author :carry
 * @version: 1.0  CreatedDate in  2019年09月24日
 * <p>
 * 修订历史: 日期			修订者		修订描述
 */
@RestController
@RequestMapping("/websocket")
public class SocketController extends BaseController {

    @Autowired
    private WebSocket webSocket;

    /** 
    * @方法描述: 向所有用户发送消息(一人对所有人发布同一个消息)
    * @return: com.XX.common.base.AjaxResult
    * @Author: carry
    */
    @PostMapping("/sendAllWebSocket")
    public AjaxResult sendAllWebSocket(@RequestParam String jsonMsg) {
        try {
            webSocket.sendAllMessage(jsonMsg);
        } catch (Exception e) {
            return error(e.getMessage());
        }

        return success();
    }

   /** 
   * @方法描述: 一对一发送消息(一人对一人发布同一个消息)
   * @return: com.XX.common.base.AjaxResult
   * @Author: carry
   */
    @PostMapping("/sendOneWebSocketOneToOne")
    public AjaxResult sendOneWebSocketOneToOne(@RequestParam("userId") String userId, @RequestParam String jsonMsg) {
        try {
            webSocket.sendOneMessage(userId, jsonMsg);
        } catch (Exception e) {
            return error(e.getMessage());
        }

        return success();
    }

    /**
     * @方法描述: 一对一发送多消息(一人对一人发布多个消息)
     *         此方法会出现多线程问题,需要在sendOneMessage进行处理
     * @return: com.XX.common.base.AjaxResult
     * @Author: carry
     */
    @PostMapping("/sendManayWebSocketOneToOne")
    public AjaxResult sendManayWebSocketOneToOne(@RequestParam("userId") String userId, @RequestParam String jsonString) {
        try {
            JSONArray jsonArray = JSONArray.fromObject(jsonString);
            for(int i=0;i<jsonArray.size();i++){
                JSONObject jsonObject= JSONObject.fromObject(jsonArray.get(i));
                webSocket.sendOneMessage(userId, jsonObject.toString());
            }
        } catch (Exception e) {
            return error(e.getMessage());
        }

        return success();
    }

    /** 
    * @方法描述: 一对多发送消息(一人对多人发布同一个消息)
    * @return: com.fencer.common.base.AjaxResult
    * @Author: carry
    */
    @PostMapping("/sendUserListWebSocket")
    public AjaxResult sendUserListWebSocket(@RequestParam List<String> userList, @RequestParam String jsonMsg) {
        try {
            for (String userId : userList) {
                webSocket.sendOneMessage(userId, jsonMsg);
            }

        } catch (Exception e) {
            return error(e.getMessage());
        }

        return success();
    }


}

6:入口类也贴上吧

package XXX.XXX;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.client.RestTemplate;

@EnableEurekaClient
@EnableHystrix
@MapperScan(basePackages = { "com.XX.XX.mapper" })
@ComponentScan(basePackages = "com.XXX.*")
@SpringBootApplication
public class WebSocketApplication implements CommandLineRunner {

	public static void main(String[] args) {
		SpringApplication.run(WebSocketApplication.class, args);
	}

	@Override
	public void run(String... args) throws Exception {
		System.out.println("######################WebSocket服务启动完成!######################");
	}

	@Bean
	@LoadBalanced
	public RestTemplate restTemplate() {
		return new RestTemplate();
	}
}

============================其他服务的调用====================================================

二:其他服务的调用,使用rest+template调用(不会的可以复习一下spring colud 服务之间的调用)

 1:为了方便服务里面其他功能的方便,封装单独的调用公共类

SocketService.java
package com.xxx.rcdd.io.ws;

import com.xxx.common.base.AjaxResult;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import net.sf.json.JSONArray;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.List;

import static com.fencer.common.base.AjaxResult.error;
import static com.fencer.common.base.AjaxResult.success;

/**
 * 类描述:
 *
 * @author :carry
 * @version: 1.0  CreatedDate in  2019年09月26日
 * <p>
 * 修订历史: 日期			修订者		修订描述
 */
@Service
public class SocketService {

    @Autowired
    RestTemplate restTemplate;

    /**
     * @方法描述: 向全部用户广播消息
     * @return: void
     * @Author: carry
     */
    public void sedMsgAll(String jsonMsg) {
        try {
            //发送消息
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    SocketService.this.sendAllWebSocket(jsonMsg);
                }
            });
            thread.start();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }


    /**
     * @方法描述:一对一发送消息(一人对一人发布同一个消息)
     * @return: void
     * @Author: carry
     */
    public void sendOneMsgToOneToOne(String userId, String jsonMsg) {
        try {
            //发送消息
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    SocketService.this.sendOneWebSocketOneToOne(userId, jsonMsg);
                }
            });
            thread.start();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }


    /**
     * @方法描述:一对一发送多消息(一人对一人发布多个消息)
     * @return: void
     * @Author: carry
     */
    public void sendManayToOneToOne(String userId,JSONArray jsonArray) {
        try {
            //发送消息
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    SocketService.this.sendManayWebSocketOneToOne(userId, jsonArray);
                }
            });
            thread.start();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * @方法描述:一对多发送消息(一人对多人发布同一个消息)
     * @return: void
     * @Author: carry
     */
    public void sendUserList(List<String> userList, String jsonMsg) {
        try {
            //发送消息
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    SocketService.this.sendUserListWebSocket(userList, jsonMsg);
                }
            });
            thread.start();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * @方法描述: 消息发送失败回调
     * @return: com.fencer.rcdd.domain.util.SysUser
     * @Author: carry
     */
    private AjaxResult fallbackOfMessage() {
        System.out.println("error fallbackOfMessage.... ");
        return error();
    }

    /**
     * @方法描述: 向全部用户广播消息
     * @return: com.fencer.rcdd.domain.util.SysUser
     * @Author: carry
     */
    @HystrixCommand(fallbackMethod = "fallbackOfMessage")
    private AjaxResult sendAllWebSocket(String jsonMsg) {
        try {
            String url = "http://API-WEBSOCKET/websocket/sendAllWebSocket";
            MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
            map.add("jsonMsg", jsonMsg);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<MultiValueMap<String, Object>>(map, headers);
            restTemplate.postForEntity(url, request, AjaxResult.class);
        } catch (Exception e) {
            e.printStackTrace();
            return error(e.getMessage());
        }

        return success();
    }

    /**
     * @方法描述:一对一发送消息(一人对一人发布同一个消息)
     * @return: com.fencer.rcdd.domain.util.SysUser
     * @Author: carry
     */
    @HystrixCommand(fallbackMethod = "fallbackOfMessage")
    private AjaxResult sendOneWebSocketOneToOne(String userId, String jsonMsg) {
        try {
            String url = "http://API-WEBSOCKET/websocket/sendOneWebSocketOneToOne";
            MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
            map.add("userId", userId);
            map.add("jsonMsg", jsonMsg);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<MultiValueMap<String, Object>>(map, headers);
            restTemplate.postForEntity(url, request, AjaxResult.class);
        } catch (Exception e) {
            e.printStackTrace();
            return error(e.getMessage());
        }

        return success();
    }

    /**
     * @方法描述:一对一发送多消息(一人对一人发布多个消息)
     * @return: com.fencer.rcdd.domain.util.SysUser
     * @Author: carry
     */
    @HystrixCommand(fallbackMethod = "fallbackOfMessage")
    private AjaxResult sendManayWebSocketOneToOne(String userId,JSONArray jsonArray) {
        try {
            String jsonString = jsonArray.toString();
            String url = "http://API-WEBSOCKET/websocket/sendManayWebSocketOneToOne";
            MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
            map.add("userId", userId);
            map.add("jsonString", jsonString);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<MultiValueMap<String, Object>>(map, headers);
            restTemplate.postForEntity(url, request, AjaxResult.class);
        } catch (Exception e) {
            e.printStackTrace();
            return error(e.getMessage());
        }

        return success();
    }

    /**
     * @方法描述:一对多发送消息(一人对多人发布同一个消息)
     * @return: com.fencer.rcdd.domain.util.SysUser
     * @Author: carry
     */
    @HystrixCommand(fallbackMethod = "fallbackOfMessage")
    private AjaxResult sendUserListWebSocket(List<String> userList, String jsonMsg) {
        try {
            String url = "http://API-WEBSOCKET/websocket/sendUserListWebSocket";
            MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
            map.add("userList", userList);
            map.add("jsonMsg", jsonMsg);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<MultiValueMap<String, Object>>(map, headers);
            restTemplate.postForEntity(url, request, AjaxResult.class);
        } catch (Exception e) {
            e.printStackTrace();
            return error(e.getMessage());
        }

        return success();
    }
}

2:具体业务的调用

省略业务代码
            List<Map<String, Object>> infoList = new ArrayList<Map<String, Object>>();
            Map<String, Object> msgMap = new HashMap<String, Object>();
            msgMap.put("id", uuid);
            msgMap.put("type", "shift");
            msgMap.put("title", "通知内容");
            infoList.add(msgMap);
            infoList.add(msgMap);
            JSONArray jsonArray =JSONArray.fromObject(infoList);
            JSONObject  jsonObject=JSONObject.fromObject(msgMap);

            //发送消息
             socketService.sedMsgAll(jsonObject.toString());
            //socketService.sendOneMsgToOneToOne("3001",jsonObject.toString());
            // socketService.sendManayToOneToOne("3001", jsonArray);

=================================前端VUE部分====================================================

因为推送可能是在不同的页面,本人是在不变的页面比如导航组件里链接的socket服务进行监听,然后调用element的notic组件进行前台展示,前台可以根据消息的类型或者id,进行自己的处理,比如进入到业务的具体页面之类。

 mounted() {
    //链接socket
    this.connWebSocket();
  },
  beforeDestroy() {
    // 监听窗口关闭事件,vue生命周期销毁之前关闭socket当窗口关闭时,防止连接还没断开就关闭窗口。
    this.onbeforeunload();
  },
  methods: {
    connWebSocket() {
      let userInfo = JSON.parse(localStorage.getItem("userInfos"));
      let userId = userInfo.userId;
      // WebSocket
      if ("WebSocket" in window) {
        this.websocket = new WebSocket(
          "ws://localhost:9002/websocket/" + userId //userId 传此id主要后端java用来保存session信息,用于给特定的人发送消息,广播类消息可以不用此参数
        );

        //初始化socket
        this.initWebSocket();
      } else {
        ctx.$message.error("次浏览器不支持websocket");
      }
    },
    initWebSocket() {
      // 连接错误
      this.websocket.onerror = this.setErrorMessage;

      // 连接成功
      this.websocket.onopen = this.setOnopenMessage;

      // 收到消息的回调
      this.websocket.onmessage = this.setOnmessageMessage;

      // 连接关闭的回调
      this.websocket.onclose = this.setOncloseMessage;

      // 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
      window.onbeforeunload = this.onbeforeunload;
    },
    setErrorMessage() {
      console.log(
        "WebSocket连接发生错误   状态码:" + this.websocket.readyState
      );
    },
    setOnopenMessage() {
      console.log("WebSocket连接成功    状态码:" + this.websocket.readyState);
    },
   setOnmessageMessage(result) {
      console.log("服务端返回:" + result.data);
      let msgMap = JSON.parse(result.data);
      let id = msgMap.id;
      let title = msgMap.title;
      let type = msgMap.type;
      // 根据服务器推送的消息做自己的业务处理

      this.$notify({
        title: "你有一条新信息",
        type: "info",
        duration: 0,
        dangerouslyUseHTMLString: true,
        message:
          '<div style="height:100px;width:100px">' +
          title,
        position: "bottom-right"
      });
    },
    setOncloseMessage() {
      console.log("WebSocket连接关闭    状态码:" + this.websocket.readyState);
    },
    onbeforeunload() {
      this.closeWebSocket();
    },
    closeWebSocket() {
      this.websocket.close();
    }
  },

基本上面的代码复制到你们自己的工程里就能运行,有些涉及数据库、地址、或者公司隐私之类的,大部分用XXX去掉了,换成你们自己的即可。

 

======================================正式环境配合nginx使用=======================================

因为服务器对外只开通了8077端口,所以只能通过Nginx来反向代理

1:修改前台文件

connWebSocket() {
      let userInfo = JSON.parse(localStorage.getItem("userInfos"));
      let userId = userInfo.userId;
      if ("WebSocket" in window) {
        this.websocket = new WebSocket(
          "ws://xxx.xxx.xxx.xxx:8077/websocket/" + userId
        );

        this.initWebSocket();
      } else {
        ctx.$message.error("次浏览器不支持websocket");
      }
    },

 

2:修改Nginx配置文件

主要的2点

 1: map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
   }

2: websocket 服务的端口是9002,需要代理到此端口

location /websocket {
        proxy_pass http://127.0.0.1:9002;  
        proxy_redirect off; 
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_read_timeout 3600s; #超时时间
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
        proxy_set_header Upgrade $http_upgrade; #开启websocket支持
        proxy_set_header Connection $connection_upgrade; #开启websocket支持
    }

 

完整代码:


#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  65555;
}


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

    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    autoindex       on;
    tcp_nopush      on;
    tcp_nodelay     on; 
    keepalive_timeout 120; 
    
    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;
    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;    
    fastcgi_busy_buffers_size 128k;
    fastcgi_temp_file_write_size 128k;

    client_header_buffer_size 100m; #上传文件大小限制    

    gzip on;
    gzip_min_length   1k;
    gzip_buffers     4 16k;
    gzip_http_version 1.0;
    gzip_comp_level 9;
    gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/javascript image/jpeg image/gif image/png;
    #gzip_types       text/plain application/x-javascript text/css application/xml;
    gzip_vary on;
    server {
        listen       8077;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;


        location / {
            root   D:/dist;  
            index  index.html index.htm;
        }

	location /iserver {
            proxy_pass http://127.0.0.1:8090/iserver;
        }


	location ^~/api {
            proxy_pass http://127.0.0.1:8088;
        }

        location /websocket {
		proxy_pass http://127.0.0.1:9002;  
		proxy_redirect off; 
		proxy_set_header Host $host; 
		proxy_set_header X-Real-IP $remote_addr; 
		proxy_read_timeout 3600s; 
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
		proxy_set_header Upgrade $http_upgrade; 
		proxy_set_header Connection $connection_upgrade; 
        }
	
        error_page  404              /index.html;


	location /index.html {
            root   D:/dist; 
            index  index.html index.htm;
        }
 

}

==============================添加 消息提示音====================================================

1:vue页面修改,添加代码

<!-- 语音播放功能 -->
			<audio ref="audio" controls v-show="false">
				<source id="tts_source_id" src="../assets/mp3/messageToYou.mp3" type="audio/mpeg">
			</audio>

2:添加一个调用的方法

methods: {
    myplay(){
         this.$refs.audio.play();
  	},
}

3:推送完消息后调用

setOnmessageMessage(result) {
      this.myplay();//调用播放方法

      console.log("服务端返回:" + result.data);
      let msgMap = JSON.parse(result.data);
      let id = msgMap.id;
      let business_Id = msgMap.business_Id;
      let title = msgMap.title;
      let type = msgMap.type; //主要
.........省略其他代码
}

 

Guess you like

Origin blog.csdn.net/CarryBest/article/details/101457044