diff --git a/README.md b/README.md index 27d4fe22a..6bad1dd8f 100644 --- a/README.md +++ b/README.md @@ -1,87 +1,2 @@ -## 平台简介 - -一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适的。于是利用空闲休息时间开始自己写了一套后台系统。如此有了若依。她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。 - -性别男,若依是给还没有出生女儿取的名字(寓意:你若不离不弃,我必生死相依) - -* 感谢 [hplus](https://gitee.com/hplus_admin/hplus) 后台主题 UI 框架。 -* 前后端分离版本,请移步[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud) -* 阿里云优惠券:[点我进入](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)   - -## 内置功能 - -1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 -2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 -3. 岗位管理:配置系统用户所属担任职务。 -4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 -5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 -6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 -7. 参数管理:对系统动态配置常用参数。 -8. 通知公告:系统通知公告信息发布维护。 -9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 -10. 登录日志:系统登录日志记录查询包含登录异常。 -11. 在线用户:当前系统中活跃用户状态监控。 -12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 -13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 -14. 系统接口:根据业务代码自动生成相关的api接口文档。 -15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。 -16. 在线构建器:拖动表单元素生成相应的HTML代码。 -17. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 - -## 在线体验 - -- admin/admin123 -- 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。 - -演示地址:http://ruoyi.vip -文档地址:http://doc.ruoyi.vip - -## 演示图 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -## 若依交流群 - -QQ群: [![加入QQ群](https://img.shields.io/badge/已满-1389287-blue.svg)](https://jq.qq.com/?_wv=1027&k=5HBAaYN) [![加入QQ群](https://img.shields.io/badge/已满-1679294-blue.svg)](https://jq.qq.com/?_wv=1027&k=5cHeRVW) [![加入QQ群](https://img.shields.io/badge/已满-1529866-blue.svg)](https://jq.qq.com/?_wv=1027&k=53R0L5Z) [![加入QQ群](https://img.shields.io/badge/已满-1772718-blue.svg)](https://jq.qq.com/?_wv=1027&k=5g75dCU) [![加入QQ群](https://img.shields.io/badge/已满-1366522-blue.svg)](https://jq.qq.com/?_wv=1027&k=58cPoHA) [![加入QQ群](https://img.shields.io/badge/已满-1382251-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Ofd4Pb) [![加入QQ群](https://img.shields.io/badge/已满-1145125-blue.svg)](https://jq.qq.com/?_wv=1027&k=5yugASz) [![加入QQ群](https://img.shields.io/badge/已满-86752435-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Rf3d2P) [![加入QQ群](https://img.shields.io/badge/已满-134072510-blue.svg)](https://jq.qq.com/?_wv=1027&k=5ZIjaeP) [![加入QQ群](https://img.shields.io/badge/已满-210336300-blue.svg)](https://jq.qq.com/?_wv=1027&k=5CJw1jY) [![加入QQ群](https://img.shields.io/badge/339522636-blue.svg)](https://jq.qq.com/?_wv=1027&k=5omzbKc) \ No newline at end of file +## ruoyi-tts +1. (解压doc文件夹下jacob-1.18-x64.rar)把jacob-1.18-x64.dll文件复制到jdk安装位置的bin目录下。 \ No newline at end of file diff --git a/doc/jacob-1.18-x64.rar b/doc/jacob-1.18-x64.rar new file mode 100644 index 000000000..d8a58b0f4 Binary files /dev/null and b/doc/jacob-1.18-x64.rar differ diff --git a/doc/若依环境使用手册.docx b/doc/若依环境使用手册.docx index c0edbcc48..e69de29bb 100644 --- a/doc/若依环境使用手册.docx +++ b/doc/若依环境使用手册.docx @@ -1,78 +0,0 @@ - 若依系统开发环境搭建手册 -1. 准备工作 -1.1 前置环境准备 -- -- 安装Maven - 若依基于Maven管理项目的构建,需要先安装好相应的版本。 -1.2 开发工具 - 若依系统采用Eclipse作为开发工具。但不局限于Eclipse。此处仅介绍在Eclipse搭建开发环境所需的操作。 -2. 开发环境搭建 -2.1 开发工具的配置 -2.1.1 配置Maven -进入Window->Preferences->Maven->Installations页面,设置已经安装好的Maven - -2.1.2 配置Maven仓库路径 -进入Window->Preferences->Maven->User Settings页面,配置仓库路径 - -2.1.4 关闭校验 -进入Window->Preferences->Validation页面,勾选"Suspend all validators",关闭校验 - -2.2 导入工程 -通过Eclipse导入工程,步骤如下: -(1)点击左侧项目区域 -- >Import... -(2)选择RuoYi -(3)点击Finish(4)RuoYi的代码就被导出到Eclipse中了,此时可以在工程视图中看到。 - -3. 运行若依系统 -3.1 必要的配置 -3.1.1 修改数据库连接 -编辑src/main/ resources目录下的application-druid.yml 文件,修改数据库地址账号信息。 -执行sql/ ry_20180423.sql,quartz.sql 两个文件 日期随版本变化 -3.1.2 开发环境配置 -编辑src/main/ resources目录下的application.yml 文件, -默认端口为80 - -3.1.3 代码生成配置 -编辑src/main/ resources目录下的application.yml 文件, - -默认为module,根据实际情况修改即可。生成的表要有注释注:如对模板有特殊需求,可自行修改。编辑src/main/ resources/templates/vm目录下 - -3.1.4 日志配置 -编辑src/main/ resources目录下的logback.yml 文件 - -改为自己需要的路径 - -3.2 启动及验证 -启动RuoYiApplication.java 出现如下图表示启动成功 -打开浏览器,输入:http://localhost:80/若能正确展示登录页面,并能成功登录,登录后菜单及页面展示正常,则表明环境搭建成功。默认密码为 admin/admin123 - -演示地址:http://www.ruoyi.club - - - -4. 部署若依系统 -4.1 war部署方式 -4.1.1 修改pom.xml文件。将jar修改为war - -如果是分模块需要修改ruoyi-admin - - -4.1.2 在spring-boot-starter依赖中移除tomcat模块 - - - - spring-boot-starter-tomcat - org.springframework.boot - - - -4.1.3 部署到tomcat的webapps目录下面 -默认为RuoYi.war - -4.1.4 启动及验证 -运行startup.bat 出现如下图即部署成功 -4.2 Jar方式部署 -执行命令:java - jar RuoYi.jar -脚本执行:ry.sh start 启动stop 停止 - - -演示地址:ruoyi.vip -文档地址:doc.ruoyi.vip diff --git a/pom.xml b/pom.xml index cc03afb23..45a0efa2d 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ 1.3.3 3.17 1.7 + 1.18.12 @@ -202,6 +203,14 @@ ruoyi-common ${ruoyi.version} + + + + org.projectlombok + lombok + ${lombok.version} + provided + diff --git a/ruoyi-tts/pom.xml b/ruoyi-tts/pom.xml index fa539e5d4..3329f58c8 100644 --- a/ruoyi-tts/pom.xml +++ b/ruoyi-tts/pom.xml @@ -11,5 +11,35 @@ ruoyi-tts + + + + + com.ruoyi + ruoyi-framework + + + + + org.bidib.jbidib.org.qbang.rxtx + rxtxcomm + 2.2 + + + + + com.hynnet + jacob + 1.18 + + + + + org.projectlombok + lombok + provided + + + \ No newline at end of file diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/JacobApp.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/JacobApp.java new file mode 100644 index 000000000..2a78f1784 --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/JacobApp.java @@ -0,0 +1,24 @@ +package com.ruoyi.tts; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +/** + * @author GideonYeung + * @date 2020/6/24 11:44 + */ +@SpringBootApplication(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) +public class JacobApp { + public static void main(String[] args) { + SpringApplication.run(JacobApp.class); + } + + @Bean + public RestTemplate restTemplate(){ + return new RestTemplate(); + } +} diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/config/ScheduleConfig.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/config/ScheduleConfig.java new file mode 100644 index 000000000..4a040f810 --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/config/ScheduleConfig.java @@ -0,0 +1,26 @@ +package com.ruoyi.tts.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; + +/** + * @author GideonYeung + * @date 2020/6/30 11:10 + */ +@Configuration +public class ScheduleConfig implements SchedulingConfigurer { + + @Override + public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { + + // 设置线程池 + ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); + taskScheduler.setThreadNamePrefix("Schedule-Task-"); + taskScheduler.setPoolSize(5); + taskScheduler.initialize(); + + scheduledTaskRegistrar.setTaskScheduler(taskScheduler); + } +} diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/NoSuchPortException.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/NoSuchPortException.java new file mode 100644 index 000000000..340787bb2 --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/NoSuchPortException.java @@ -0,0 +1,19 @@ +package com.ruoyi.tts.exception; + +/** + * @author GideonYeung + * @date 2020/7/7 9:50 + */ +public class NoSuchPortException extends Exception { + /** + * + */ + private static final long serialVersionUID = 1L; + + public NoSuchPortException() { + } + @Override + public String toString() { + return "没有该端口对应的串口设备!"; + } +} diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/NotSerialPortException.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/NotSerialPortException.java new file mode 100644 index 000000000..303550df2 --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/NotSerialPortException.java @@ -0,0 +1,19 @@ +package com.ruoyi.tts.exception; + +/** + * @author GideonYeung + * @date 2020/7/7 9:51 + */ +public class NotSerialPortException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + public NotSerialPortException() { + } + @Override + public String toString() { + return "端口指向设备不是串口类型!"; + } +} diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/PortInUseException.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/PortInUseException.java new file mode 100644 index 000000000..a80080f9d --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/PortInUseException.java @@ -0,0 +1,18 @@ +package com.ruoyi.tts.exception; + +/** + * @author GideonYeung + * @date 2020/7/7 9:52 + */ +public class PortInUseException extends Exception { + /** + * + */ + private static final long serialVersionUID = 1L; + public PortInUseException() { + } + @Override + public String toString() { + return "端口已被占用!"; + } +} diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/ReadDataFromSerialPortFailureException.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/ReadDataFromSerialPortFailureException.java new file mode 100644 index 000000000..1f5b10850 --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/ReadDataFromSerialPortFailureException.java @@ -0,0 +1,21 @@ +package com.ruoyi.tts.exception; + +/** + * @author GideonYeung + * @date 2020/7/7 9:57 + */ +public class ReadDataFromSerialPortFailureException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public ReadDataFromSerialPortFailureException() { + } + + @Override + public String toString() { + return "从串口读取数据时出错"; + } +} diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/SerialPortInputStreamCloseFailureException.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/SerialPortInputStreamCloseFailureException.java new file mode 100644 index 000000000..7fcccb105 --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/SerialPortInputStreamCloseFailureException.java @@ -0,0 +1,20 @@ +package com.ruoyi.tts.exception; + +/** + * @author GideonYeung + * @date 2020/7/7 9:58 + */ +public class SerialPortInputStreamCloseFailureException extends Exception { + /** + * + */ + private static final long serialVersionUID = 1L; + + public SerialPortInputStreamCloseFailureException() { + } + + @Override + public String toString() { + return "关闭串口对象输入流出错"; + } +} diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/SerialPortOutputStreamCloseFailureException.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/SerialPortOutputStreamCloseFailureException.java new file mode 100644 index 000000000..22d44be53 --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/SerialPortOutputStreamCloseFailureException.java @@ -0,0 +1,20 @@ +package com.ruoyi.tts.exception; + +/** + * @author GideonYeung + * @date 2020/7/7 9:55 + */ +public class SerialPortOutputStreamCloseFailureException extends Exception { + /** + * + */ + private static final long serialVersionUID = 1L; + + public SerialPortOutputStreamCloseFailureException() { + } + + @Override + public String toString() { + return "关闭串口对象的输出流出错"; + } +} diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/SerialPortParameterFailureException.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/SerialPortParameterFailureException.java new file mode 100644 index 000000000..cb7f38a85 --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/SerialPortParameterFailureException.java @@ -0,0 +1,20 @@ +package com.ruoyi.tts.exception; + +/** + * @author GideonYeung + * @date 2020/7/7 9:49 + */ +public class SerialPortParameterFailureException extends Exception { + /** + * + */ + private static final long serialVersionUID = 1L; + + public SerialPortParameterFailureException() { + } + + @Override + public String toString() { + return "设置串口参数失败!打开串口操作未完成!"; + } +} diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/TooManyListenersException.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/TooManyListenersException.java new file mode 100644 index 000000000..2fd701777 --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/exception/TooManyListenersException.java @@ -0,0 +1,20 @@ +package com.ruoyi.tts.exception; + +/** + * @author GideonYeung + * @date 2020/7/7 9:59 + */ +public class TooManyListenersException extends Exception{ + /** + * + */ + private static final long serialVersionUID = 1L; + + public TooManyListenersException() { + } + + @Override + public String toString() { + return "监听类对象过多!"; + } +} diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/jacob/VoicePlayback.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/jacob/VoicePlayback.java new file mode 100644 index 000000000..f3ab685cd --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/jacob/VoicePlayback.java @@ -0,0 +1,80 @@ +package com.ruoyi.tts.jacob; + + +import com.jacob.activeX.ActiveXComponent; +import com.jacob.com.Dispatch; +import com.jacob.com.Variant; + +/** + * @author GideonYeung + * @date 2020/6/24 11:39 + */ +public class VoicePlayback { + /** + * 文字转语音播放 + * + * @param text 需要播放的文字 + */ + public static void textToSpeech(String text) { + ActiveXComponent ax; + try { + ax = new ActiveXComponent("Sapi.SpVoice"); + + // 运行时输出语音内容 + Dispatch spVoice = ax.getObject(); + // 音量 0-100 + ax.setProperty("Volume", new Variant(100)); + // 语音朗读速度 -10 到 +10 + ax.setProperty("Rate", new Variant(-2)); + // 执行朗读 + Dispatch.call(spVoice, "Speak", new Variant(text)); + + // Dispatch.put(spVoice, "Volume", new Variant(100)); + // 设置朗读速度 + // Dispatch.put(spVoice, "Rate", new Variant(-2)); + // 构建文件流把生成语音文件 + // makefile(ax, spVoice, text); + + spVoice.safeRelease(); + ax.safeRelease(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + // public static void makefile(Dispatch spVoice, String text) { + // ActiveXComponent ax = new ActiveXComponent("Sapi.SpFileStream"); + // Dispatch spFileStream = ax.getObject(); + + // ax = new ActiveXComponent("Sapi.SpAudioFormat"); + // Dispatch spAudioFormat = ax.getObject(); + + // // 设置音频流格式 + // Dispatch.put(spAudioFormat, "Type", new Variant(22)); + // // 设置文件输出流格式 + // Dispatch.putRef(spFileStream, "Format", spAudioFormat); + // // 调用输出 文件流打开方法,创建一个.wav文件 + // Dispatch.call(spFileStream, "Open", new Variant("./text.wav"), new + // Variant(3), new Variant(true)); + // // 设置声音对象的音频输出流为输出文件对象 + // Dispatch.putRef(spVoice, "AudioOutputStream", spFileStream); + // // 设置音量 0到100 + // Dispatch.put(spVoice, "Volume", new Variant(100)); + // // 设置朗读速度 + // Dispatch.put(spVoice, "Rate", new Variant(-2)); + // // 开始朗读 + // Dispatch.call(spVoice, "Speak", new Variant(text)); + + // // 关闭输出文件 + // Dispatch.call(spFileStream, "Close"); + // Dispatch.putRef(spVoice, "AudioOutputStream", null); + + // spAudioFormat.safeRelease(); + // spFileStream.safeRelease(); + // } + + public static void main(String[] args) { + textToSpeech("B54号机处于生产系统维护计划停机状态,使用模具B54试模模具生产产品31003522蓝色盖子T,耗时1827.5小时。处理方法为, 预计解决时长为0.5小时,负责人为林志峰"); + } +} diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/serial/SerialTool.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/serial/SerialTool.java new file mode 100644 index 000000000..9075afa30 --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/serial/SerialTool.java @@ -0,0 +1,260 @@ +package com.ruoyi.tts.serial; + +import com.ruoyi.tts.exception.*; +import gnu.io.*; +import gnu.io.NoSuchPortException; +import gnu.io.PortInUseException; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.TooManyListenersException; + +/**串口 + * @author GideonYeung + * @date 2020/7/7 9:27 + */ +@Slf4j +public class SerialTool { + /** + * 查找所有可用端口 + * @return 可用端口名称列表 + */ + public static ArrayList findPort() { + + //获得当前所有可用串口 + @SuppressWarnings("unchecked") + Enumeration portList = CommPortIdentifier.getPortIdentifiers(); + ArrayList portNameList = new ArrayList(); + //将可用串口名添加到List并返回该List + while (portList.hasMoreElements()) { + String portName = portList.nextElement().getName(); + portNameList.add(portName); + } + + return portNameList; + + } + + /** + * 打开串口 + * @param portName 端口名称 + * @param baudRate 波特率 + * @return 串口对象 + * @throws SerialPortParameterFailureException 设置串口参数失败 + * @throws NotSerialPortException 端口指向设备不是串口类型 + * @throws NoSuchPortException 没有该端口对应的串口设备 + * @throws PortInUseException 端口已被占用 + */ + public static SerialPort openPort(String portName, int baudRate) throws SerialPortParameterFailureException, NotSerialPortException, NoSuchPortException, PortInUseException { + + try { + + //通过端口名识别端口 + CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); + + //打开端口,并给端口名字和一个timeout(打开操作的超时时间) + CommPort commPort = portIdentifier.open(portName, 2000); + + //判断是不是串口 + if (commPort instanceof SerialPort) { + + SerialPort serialPort = (SerialPort) commPort; + + try { + //设置一下串口的波特率等参数 + serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); + } catch (UnsupportedCommOperationException e) { + throw new SerialPortParameterFailureException(); + } + + log.info("Open " + portName + " successfully !"); + return serialPort; + + } + else { + //不是串口 + throw new NotSerialPortException(); + } + } catch (NoSuchPortException e1) { + throw new NotSerialPortException(); + } catch (PortInUseException e2) { + throw new PortInUseException(); + } + } + + /** + * 关闭串口 + * @param serialPort 待关闭的串口对象 + */ + public static void closePort(SerialPort serialPort) { + if (serialPort != null) { + serialPort.close(); + + } + } + + /** + * 往串口发送数据 + * @param serialPort 串口对象 + * @param order 待发送数据 + * @throws SerialPortParameterFailureException 向串口发送数据失败 + * @throws SerialPortOutputStreamCloseFailureException 关闭串口对象的输出流出错 + */ + public static void sendToPort(SerialPort serialPort, byte[] order) throws SerialPortParameterFailureException, SerialPortOutputStreamCloseFailureException { + + OutputStream out = null; + + try { + + out = serialPort.getOutputStream(); + out.write(order); + out.flush(); + log.info("写入成功"); + + } catch (IOException e) { + throw new SerialPortParameterFailureException(); + } finally { + try { + if (out != null) { + out.close(); + } + } catch (IOException e) { + throw new SerialPortOutputStreamCloseFailureException(); + } + } + + } + + /** + * 从串口读取数据 + * @param serialPort 当前已建立连接的SerialPort对象 + * @return 读取到的数据 + * @throws ReadDataFromSerialPortFailureException 从串口读取数据时出错 + * @throws SerialPortInputStreamCloseFailureException 关闭串口对象输入流出错 + */ + public static byte[] readFromPort(SerialPort serialPort) throws ReadDataFromSerialPortFailureException, SerialPortInputStreamCloseFailureException { + + InputStream in = null; + byte[] bytes = null; + + try { + + in = serialPort.getInputStream(); + //获取buffer里的数据长度 + int bufflenth = in.available(); + + while (bufflenth != 0) { + //初始化byte数组为buffer中数据的长度 + bytes = new byte[bufflenth]; + in.read(bytes); + bufflenth = in.available(); + } + } catch (IOException e) { + throw new ReadDataFromSerialPortFailureException(); + } finally { + try { + if (in != null) { + in.close(); + in = null; + } + } catch(IOException e) { + throw new SerialPortInputStreamCloseFailureException(); + } + + } + log.info("读取成功"); + return bytes; + + } + + /** + * 添加监听器 + * @param port 串口对象 + * @param listener 串口监听器 + * @throws TooManyListenersException 监听类对象过多 + */ + public static void addListener(SerialPort port, DataAvailableListener listener) throws TooManyListenersException { + + try { + + //给串口添加监听器 + port.addEventListener(new SerialPortListener(listener)); + //设置当有数据到达时唤醒监听接收线程 + port.notifyOnDataAvailable(true); + //设置当通信中断时唤醒中断线程 + port.notifyOnBreakInterrupt(true); + + } catch (TooManyListenersException e) { + throw new TooManyListenersException(); + } + } + /** + * 串口监听 + */ + public static class SerialPortListener implements SerialPortEventListener { + + private DataAvailableListener mDataAvailableListener; + + public SerialPortListener(DataAvailableListener mDataAvailableListener) { + this.mDataAvailableListener = mDataAvailableListener; + } + + @Override + public void serialEvent(SerialPortEvent serialPortEvent) { + switch (serialPortEvent.getEventType()) { + // 1.串口存在有效数据 + case SerialPortEvent.DATA_AVAILABLE: + if (mDataAvailableListener != null) { + mDataAvailableListener.dataAvailable(); + } + break; + // 2.输出缓冲区已清空 + case SerialPortEvent.OUTPUT_BUFFER_EMPTY: + break; + // 3.清除待发送数据 + case SerialPortEvent.CTS: + break; + // 4.待发送数据准备好了 + case SerialPortEvent.DSR: + break; + // 5.振铃指示 + case SerialPortEvent.RI: + break; + // 6.载波检测 + case SerialPortEvent.CD: + break; + // 7.溢位(溢出)错误 + case SerialPortEvent.OE: + break; + // 8.奇偶校验错误 + case SerialPortEvent.PE: + break; + // 9.帧错误 + case SerialPortEvent.FE: + break; + // 10.通讯中断 + case SerialPortEvent.BI: + log.error("与串口设备通讯中断"); + break; + + default: + break; + } + } + } + + /** + * 串口存在有效数据监听 + */ + public interface DataAvailableListener { + /** + * 串口存在有效数据 + */ + void dataAvailable(); + } + +} diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/task/VoicePlaybackTask.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/task/VoicePlaybackTask.java new file mode 100644 index 000000000..31ddb5944 --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/task/VoicePlaybackTask.java @@ -0,0 +1,75 @@ +package com.ruoyi.tts.task; + +import com.ruoyi.tts.exception.*; +import com.ruoyi.tts.jacob.VoicePlayback; +import com.ruoyi.tts.serial.SerialTool; +import com.ruoyi.tts.utils.ByteUtils; +import gnu.io.NoSuchPortException; +import gnu.io.PortInUseException; +import gnu.io.SerialPort; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.HashMap; +import java.util.Map; +import java.util.TooManyListenersException; + +/** + * @author GideonYeung + * @date 2020/6/24 11:42 + */ +@Slf4j +@Component +@Configuration +@EnableScheduling +public class VoicePlaybackTask { + + @Autowired + private RestTemplate restTemplate; + + // 串口对象 + private SerialPort mSerialport; + + /** + * 2秒播放一次语音 + */ + @Scheduled(fixedDelay = 3000) + private void configureTasks() throws SerialPortParameterFailureException, SerialPortOutputStreamCloseFailureException, NotSerialPortException, PortInUseException, NoSuchPortException, TooManyListenersException { + Map nodeValueMap = new HashMap<>(); + try { + nodeValueMap = restTemplate.getForObject("http://127.0.0.1/icloud/nodeValue/getWmKey", Map.class); + } catch (HttpClientErrorException e) { + log.error("icloud暂无开启,无法获取数据。"); + } + boolean contains = nodeValueMap.values().contains(true); + byte[] bs; + SerialPort port = null; + if (contains) { + port = SerialTool.openPort("COM1", 9600); + //设定发送字符串 + bs = ByteUtils.hex2Bytes("5501110000000168"); + //打开串口 + SerialTool.sendToPort(port, bs); + } + nodeValueMap.forEach((key, value) -> { + if (value) { + String message = key + "号机按下广播通知,请及时处理。"; + log.info(message); + VoicePlayback.textToSpeech(message); + } + }); + if (contains) { + //设定发送字符串 + bs = ByteUtils.hex2Bytes("5501120000000169"); + //关闭串口 + SerialTool.sendToPort(port, bs); + SerialTool.closePort(port); + } + } +} diff --git a/ruoyi-tts/src/main/java/com.ruoyi.tts/utils/ByteUtils.java b/ruoyi-tts/src/main/java/com.ruoyi.tts/utils/ByteUtils.java new file mode 100644 index 000000000..900773ace --- /dev/null +++ b/ruoyi-tts/src/main/java/com.ruoyi.tts/utils/ByteUtils.java @@ -0,0 +1,57 @@ +package com.ruoyi.tts.utils; + +import java.util.Locale; + +/** + * @author GideonYeung + * @date 2020/7/7 10:04 + */ +public class ByteUtils { + public static byte[] hex2Bytes(String hex) { + if (hex == null || hex.length() == 0) { + return null; + } + + char[] hexChars = hex.toCharArray(); + // 如果 hex 中的字符不是偶数个, 则忽略最后一个 + byte[] bytes = new byte[hexChars.length / 2]; + + for (int i = 0; i < bytes.length; i++) { + bytes[i] = (byte) Integer.parseInt("" + hexChars[i * 2] + hexChars[i * 2 + 1], 16); + } + + return bytes; + } + + /** + * byte[]转十六进制字符串 + * + * @param array byte[] + * @return 十六进制字符串 + */ + public static String byteArrayToHexString(byte[] array) { + if (array == null) { + return ""; + } + StringBuilder buffer = new StringBuilder(); + for (byte b : array) { + buffer.append(byteToHex(b)); + } + return buffer.toString(); + } + + /** + * byte转十六进制字符 + * + * @param b byte + * @return 十六进制字符 + */ + public static String byteToHex(byte b) { + String hex = Integer.toHexString(b & 0xFF); + if (hex.length() == 1) { + hex = '0' + hex; + } + return hex.toUpperCase(Locale.getDefault()); + } + +} diff --git a/ruoyi-tts/src/main/resources/application.yml b/ruoyi-tts/src/main/resources/application.yml new file mode 100644 index 000000000..173c5f573 --- /dev/null +++ b/ruoyi-tts/src/main/resources/application.yml @@ -0,0 +1,14 @@ +# 开发环境配置 +server: + # 服务器的HTTP端口,默认为8881 + port: 8881 + servlet: + # 应用的访问路径 + context-path: / + tomcat: + # tomcat的URI编码 + uri-encoding: UTF-8 + # tomcat最大线程数,默认为200 + max-threads: 800 + # Tomcat启动初始化的线程数,默认值25 + min-spare-threads: 30 \ No newline at end of file