热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

springboot+websocket+语音交互(互相交互使用)

我提倡的是用白话文,和经验去传承分享程序,让程序更加开源话,共享化,让后来者,初学者,遇到此类困

我提倡的是用白话文,和经验去传承分享程序,让程序更加开源话,共享化,让后来者,初学者,遇到此类困难者等,少走弯路,提高效率,不喜勿喷。有更好的建议,可以留言探讨。。。。


首先说下此案例当时做的时候有点复杂,最后还是克服完成。拿出来广大网友分享,但愿能帮助你在java程序的道路上越走越远。。。
背景:
客户通过网页,在通过websocket协议,和Java后端创建连接,在通过Java后端和语音交互接口创建连接,接收到的返回数据,返回给前端在页面展示出来。Java就是做了一个中间件的作用。即是服务端又是客户端。



  1. 说完背景,直接上干货

  • maven依赖

org.java-websocketJava-WebSocket1.4.0org.springframework.bootspring-boot-starter-websocket

  • 代码

  • Java后端接口与前端交互(服务端)

package com.datago.robot.common.utils;import com.datago.robot.entity.DatagoApiWithBLOBs;
import com.datago.robot.service.DatagoApiService;
import org.java_websocket.client.WebSocketClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.concurrent.CopyOnWriteArraySet;/****/
@ServerEndpoint("/serverVue/{apiCode}")
@Component
public class SocketServerUtils {private Logger log = LoggerFactory.getLogger(SocketServerUtils.class);private Session session;private WebSocketClient client;private String apiCode;/*** 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/private static int OnlineCount= 0;/*** concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。* 在外部可以获取此连接的所有websocket对象,并能对其触发消息发送功能,我们的定时发送核心功能的实现在与此变量*/private static CopyOnWriteArraySet webSocketMap = new CopyOnWriteArraySet();private static DatagoApiService datagoApiService;@Autowiredpublic void setDatagoApiService(DatagoApiService datagoApiService) {SocketServerUtils.datagoApiService = datagoApiService;}/*** 建立连接** @param apiCode* @param session*/@OnOpenpublic void onOpen(@PathParam(value = "apiCode") String apiCode, Session session) {this.session = session;addOnlineCount();webSocketMap.add(this);//连接调用第三方服务client = SocketResultUtils.getClient("ws://192.168.0.109:8013/websocket");}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的音频数据*/@OnMessagepublic void onMessage(@PathParam(value = "apiCode") String apiCode, byte[] message) {log.info("音频数据报文:" + message);try {//在线client.send(message);ExceptionLog.isSuccess(apiCode, null,null);} catch (Exception e) {//离线isconnct(apiCode);client.send(message);ExceptionLog.isSuccess(apiCode, null,null);}}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的字符数据*/@OnMessagepublic void onMessage(@PathParam(value = "apiCode") String apiCode, String message) {log.info("字符数据报文:" + message);try {//在线client.send(message);ExceptionLog.isSuccess(apiCode, message,null);} catch (Exception e) {//离线isconnct(apiCode);client.send(message);ExceptionLog.isSuccess(apiCode, message,null);}}/*** 连接关闭调用的方法*/@OnClosepublic void onClose(@PathParam(value = "apiCode") String apiCode) {//请求第三方关闭连接webSocketMap.remove(this);subOnlineCount();log.info("有一连接关闭!当前在线人数为" + getOnlineCount());}/*** @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error, @PathParam(value = "apiCode") String apiCode) {log.error("错误原因:" + error.getMessage());}/*** 新加* 判断连接(在线,离线)** @param apiCode*/private void isconnct(String apiCode) {DatagoApiWithBLOBs datagoApi = datagoApiService.selectByApiCode(apiCode);if (Utils.isNotEmpty(datagoApi)) {//判断在线(true),离线(false)// 在线String apiUrl = datagoApi.getApiUrl();if (apiUrl.startsWith("ws")) {client = SocketResultUtils.getClient(apiUrl);if (Utils.isEmpty(client)) {//离线String apiOffUrl = datagoApi.getApiOffUrl();if (apiOffUrl.startsWith("ws")) {client = SocketResultUtils.getClient(apiOffUrl);if (Utils.isEmpty(client)) {ExceptionLog.isConnect(apiCode, null);}} else {ExceptionLog.isUrl(apiCode, null);}}} else {ExceptionLog.isUrl(apiCode, null);}}}/*** 实现服务器主动推送** @param message*/public void sendMessage(String message) {try {this.session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {SocketServerUtils.onlineCount++;}public static synchronized void subOnlineCount() {SocketServerUtils.onlineCount--;}public static CopyOnWriteArraySet getWebSocketSet() {return webSocketMap;}public static void setWebSocketSet(CopyOnWriteArraySet webSocketSet) {SocketServerUtils.webSocketMap = webSocketSet;}}

  • Java与第三方服务交互代码(客户端),接收第三方服务的返回数据

package com.datago.robot.common.utils;import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;import java.net.*;import java.util.concurrent.CopyOnWriteArraySet;@Slf4j
@Component
public class SocketResultUtils {public static Logger log = LoggerFactory.getLogger(SocketResultUtils.class);/*** 获取客户端连接实例** @param uri* @return*/public static WebSocketClient getClient(String uri) {try {//创建客户端连接对象WebSocketClient client = new WebSocketClient(new URI(uri), new Draft_6455()) {/*** 建立连接调用* @param serverHandshake*/@Overridepublic void onOpen(ServerHandshake serverHandshake) {log.info("建立连接");}/*** 收到服务端消息调用* @param s*/@Overridepublic void onMessage(String s) {log.info("处理结束返回消息:" + s);//接收第三方websocket服务发送数据CopyOnWriteArraySet webSocketSet =SocketServerUtils.getWebSocketSet();if (Utils.isNotEmpty(webSocketSet)) {int i = 0;synchronized (webSocketSet) {webSocketSet.forEach(c -> {//返回前端数据log.info("返回结果数据, data = {}", s);for (int j = 0; j <10; j++) {c.sendMessage(s);}});log.info("收到来自服务端的消息:::" + s);}}}/*** 断开连接调用* @param i* @param s* @param b*/@Overridepublic void onClose(int i, String s, boolean b) {log.info("关闭连接:::" + "i = " + i + ":::s = " + s + ":::b = " + b);}/*** 连接报错调用* @param e*/@Overridepublic void onError(Exception e) {log.error("报错了:::" + e.getMessage());}};//请求与服务端建立连接client.connect();//判断连接状态,0为请求中 1为已建立 其它值都是建立失败while (client.getReadyState().ordinal() == 0) {try {Thread.sleep(200);} catch (Exception e) {log.warn("延迟操作出现问题,但并不影响功能");}log.info("连接中。。。");break;}//连接状态不再是0请求中,判断建立结果是不是1已建立if (client.getReadyState().ordinal() == 1) {return client;}} catch (URISyntaxException e) {log.error(e.getMessage());}return null;}
}

推荐阅读
  • 使用ArcGIS for Java和Flex浏览自定义ArcGIS Server 9.3地图
    本文介绍了如何在Flex应用程序中实现浏览自定义ArcGIS Server 9.3发布的地图。这是一个基本的入门示例,适用于初学者。 ... [详细]
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • 深入解析Android GPS机制:第五部分 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • DAO(Data Access Object)模式是一种用于抽象和封装所有对数据库或其他持久化机制访问的方法,它通过提供一个统一的接口来隐藏底层数据访问的复杂性。 ... [详细]
  • 本文最初发表在Thorben Janssen的Java EE博客上,每周都会分享最新的Java新闻和动态。 ... [详细]
  • 原文网址:https:www.cnblogs.comysoceanp7476379.html目录1、AOP什么?2、需求3、解决办法1:使用静态代理4 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • MySQL的查询执行流程涉及多个关键组件,包括连接器、查询缓存、分析器和优化器。在服务层,连接器负责建立与客户端的连接,查询缓存用于存储和检索常用查询结果,以提高性能。分析器则解析SQL语句,生成语法树,而优化器负责选择最优的查询执行计划。这一流程确保了MySQL能够高效地处理各种复杂的查询请求。 ... [详细]
  • 工作8年后薪资从1万跃升至7万,网友惊叹:本科学历实属难得
    一位本科毕业生在工作8年后,凭借扎实的技术能力和不断的学习提升,成功将月薪从1万元提高到7万元,引发了网友们的广泛赞叹。这一成就不仅体现了个人的努力与坚持,也反映了当前技术领域对高素质人才的迫切需求。 ... [详细]
  • Hyperledger Fabric 1.4 节点 SDK 快速入门指南
    本文将详细介绍如何利用 Hyperledger Fabric 1.4 的 Node.js SDK 开发应用程序。通过最新版本的 Fabric Node.js SDK,开发者可以更高效地构建和部署基于区块链的应用,实现数据的安全共享和交易处理。文章将涵盖环境配置、SDK 安装、示例代码以及常见问题的解决方法,帮助读者快速上手并掌握核心功能。 ... [详细]
  • 全面解析JavaScript代码注释技巧与标准规范
    在Web前端开发中,JavaScript代码的可读性和维护性至关重要。本文将详细介绍如何有效地使用注释来提高代码的可读性,并探讨JavaScript代码注释的最佳实践和标准规范。通过合理的注释,开发者可以更好地理解和维护复杂的代码逻辑,提升团队协作效率。 ... [详细]
  • Java Socket 关键参数详解与优化建议
    Java Socket 的 API 虽然被广泛使用,但其关键参数的用途却鲜为人知。本文详细解析了 Java Socket 中的重要参数,如 backlog 参数,它用于控制服务器等待连接请求的队列长度。此外,还探讨了其他参数如 SO_TIMEOUT、SO_REUSEADDR 等的配置方法及其对性能的影响,并提供了优化建议,帮助开发者提升网络通信的稳定性和效率。 ... [详细]
  • 在Cisco IOS XR系统中,存在提供服务的服务器和使用这些服务的客户端。本文深入探讨了进程与线程状态转换机制,分析了其在系统性能优化中的关键作用,并提出了改进措施,以提高系统的响应速度和资源利用率。通过详细研究状态转换的各个环节,本文为开发人员和系统管理员提供了实用的指导,旨在提升整体系统效率和稳定性。 ... [详细]
  • Python 伦理黑客技术:深入探讨后门攻击(第三部分)
    在《Python 伦理黑客技术:深入探讨后门攻击(第三部分)》中,作者详细分析了后门攻击中的Socket问题。由于TCP协议基于流,难以确定消息批次的结束点,这给后门攻击的实现带来了挑战。为了解决这一问题,文章提出了一系列有效的技术方案,包括使用特定的分隔符和长度前缀,以确保数据包的准确传输和解析。这些方法不仅提高了攻击的隐蔽性和可靠性,还为安全研究人员提供了宝贵的参考。 ... [详细]
author-avatar
o.o
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有