SpringBoot加载dll文件示例
1、将动态库放在resource文件目录下
2、编写相关加载逻辑
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;/*** @Description: 加载动态库 .dll文件* @author: Be.insighted* @create: 2024/4/15 8:51* @since 1.0.0*/
@Slf4j
public class LoadLibraryUtil {public static void addLibrary() {File file = new File("dll");String absolutePath = file.getAbsolutePath();log.info("add lib:{}",absolutePath);if (!file.exists()) {file.mkdirs();}try {addLibDir(absolutePath);} catch (IOException e1) {e1.printStackTrace();}}public static void addLibrary(String path) {File file = new File(path);String absolutePath = file.getAbsolutePath();log.info("add lib path from:{}",absolutePath);if (!file.exists()) {file.mkdirs();}try {addLibDir(absolutePath);} catch (IOException e1) {e1.printStackTrace();}}public static void addLibDir(String s) throws IOException {HashMap<String, String> stringStringHashMap = new HashMap<>();stringStringHashMap.put(null, null);try {Field field = ClassLoader.class.getDeclaredField("usr_paths");field.setAccessible(true);String[] paths = (String[]) field.get(null);for (int i = 0; i < paths.length; i++) {if (s.equals(paths[i])) {return;}}String[] tmp = new String[paths.length + 1];System.arraycopy(paths, 0, tmp, 0, paths.length);tmp[paths.length] = s;field.set(null, tmp);} catch (IllegalAccessException e) {throw new IOException("Failed to get permissions to set library path");} catch (NoSuchFieldException e) {throw new IOException("Failed to get field handle to set library path");}}
}
3、测试
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.zhuao.vo.TTSVo;
import com.jacob.com.Variant;
import lombok.extern.slf4j.Slf4j;import java.io.File;/*** @Description: 使用加载的dll进行相关测试* @author: Be.insighted* @create: 2024/8/8 8:51* @since 1.0.0*/
@Slf4j
public class MsTtsUtil {public static void main(String[] args) {LoadLibraryUtil.addLibrary();String parentPath = "D:/dev_workspace/java/litong-project/litongjava-windows-tts/target/classes/litongjava-windows-tts/file/auido";File file = new File(parentPath);if (!file.exists()) {file.mkdirs();}TTSVo ttsVo = new TTSVo();ttsVo.setType(6);ttsVo.setVolume(100);ttsVo.setRate(0);ttsVo.setText("今天猪肉又涨价了,一下子涨了两块钱");ttsToFile(ttsVo, parentPath);ttsVo.setText("今天羊肉羊肉也涨价了");ttsToFile(ttsVo, parentPath);// String path = "text\\过秦论.txt";// textToFile(path);}/*** 获取当前发音人*/public static String getCurrentVoice() {// 创建与微软应用程序的新连接。传入的参数是注册表中注册的程序的名称。相当实例化Sapi.SpVoice对象,但是ax并不是Sapi.SpVoice,ax是包装信息,ax包含Sapi.SpVoiceActiveXComponent ax = new ActiveXComponent("Sapi.SpVoice");String currentVoice = getCurrentVoice(ax);ax.safeRelease();return currentVoice;}private static String getCurrentVoice(ActiveXComponent ax) {// 获取Sapi.SpVoice对象的voice属性值,voice的属性值是一个voice对象,对象使用Dispatch包装Dispatch dispatch = ax.getProperty("voice").toDispatch();// 执行voice对象的GetDescription方法,返回值可能使用String,使用Variant包装Variant description = Dispatch.call(dispatch, "GetDescription");return description.toString();}/*** 语音转文字音频* * @param ttsVo*/public static String ttsToFile(TTSVo ttsVo, String parentPath) {ActiveXComponent ax = new ActiveXComponent("Sapi.SpVoice");String filePath = getFilePath(ax, ttsVo, parentPath);try {// 运行时输出语音内容Dispatch spVoice = ax.getObject();// 下面是构建文件流到成语音文件ax = new ActiveXComponent("Sapi.SpFileStream");Dispatch spFileStream = ax.getObject();ax = new ActiveXComponent("Sapi.SpAudioFormat");Dispatch spAudioFormat = ax.getObject();// 设置音频流格式Dispatch.put(spAudioFormat, "Type", ttsVo.getType());// 设置文件输出流格式Dispatch.putRef(spFileStream, "Format", spAudioFormat);// 调用输出 文件流打开方法,创建一个.wav文件Dispatch.call(spFileStream, "Open", new Variant(filePath), new Variant(3), new Variant(true));// 设置声音对象的音频输出流为输出文件对象Dispatch.putRef(spVoice, "AudioOutputStream", spFileStream);// 设置音量 0到100Dispatch.put(spVoice, "Volume", new Variant(ttsVo.getVolume()));// 设置朗读速度Dispatch.put(spVoice, "Rate", new Variant(ttsVo.getRate()));// 开始朗读,实际上是合成得到文件Dispatch.call(spVoice, "Speak", new Variant(ttsVo.getText()));// 关闭输出文件Dispatch.call(spFileStream, "Close");Dispatch.putRef(spVoice, "AudioOutputStream", null);spAudioFormat.safeRelease();spFileStream.safeRelease();spVoice.safeRelease();} catch (Exception e) {e.printStackTrace();} finally {ax.safeRelease();}return filePath;}public static String getFilePath(ActiveXComponent ax, TTSVo ttsVo, String parentPath) {// 文件名规则// voice_type_volume_rate_md5String voice = null;if (ttsVo.getVoice() == null) {voice = getCurrentVoice(ax);} else {voice = ttsVo.getVoice();}String filename = append("_", ttsVo.getType(), ttsVo.getVolume(), ttsVo.getRate());// 添加文件名称filename += "_" + HashUtil.md5(ttsVo.getText());// 添加文件后缀if (ttsVo.getType() == 6) {filename += ".wav";}// 发音人和加目录filename = parentPath + File.separator + voice + "_" + filename;return filename;}private static String append(String string, int... ints) {String retval = new String();for (int i : ints) {retval += "_" + i;}return retval;}
}
相关文章:

SpringBoot加载dll文件示例
1、将动态库放在resource文件目录下 2、编写相关加载逻辑 import lombok.extern.slf4j.Slf4j; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.util.HashMap;/*** Description: 加载动态库 .dll文件* author: Be.insighted* c…...

9.C基础_指针与数组
数组指针(一维数组) 数组指针就是" 数组的指针 ",它是一个指向数组首地址的指针变量。 1、数组名的含义 对于一维数组,数组名就是一个指针,指向数组的首地址。 基于如下代码进行分析: int a…...

C语言——结构体与共用体
C语言——结构体与共用体 结构体共用体 结构体 如果将复杂的复杂的数据类型组织成一个组合项,在一个组合项中包含若干个类型不同(当然也可以相同)的数据项。 C语言允许用户自己指定这样一种数据结构,它称为结构体。 结构体的语法…...

vs+qt项目转qt creator
1、转换方法 打开vs工程,右键项目,Qt->Create Base .pro File 后面默认OK 如果工程有include和lib路径需要配置,则转换后的工程,需要修改pro文件 2.修改pro文件 例如转换后的工程如下: 修改后 # ------------…...
微信小程序 checkbox 实现双向绑定以及特殊交互处理
wxml文件代码如下: <!--页面顶部 引入wxs文件--> <wxs module"tools" src"../../filter/tools.wxs"></wxs> ... <checkbox-group bindchange"checkboxChange"><label class"weui-cell weui-check__…...

我在高职教STM32——I2C通信之读写EEPROM(1)
大家好,我是老耿,高职青椒一枚,一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次,同行应该都懂的,老师在课堂上教学几乎是没什么成就感的。正是如此,才有了借助CSDN平台寻求认同感和成就感的想法。在这里,我准备陆续把自己花了很多心思设计的教学课件分…...

【ARM】应用ArmDS移植最小FreeRTOS系统
【更多软件使用问题请点击亿道电子官方网站】 一、文档背景 FreeRTOS(Free Real-Time Operating System)是一个开源的实时操作系统内核,广泛应用于嵌入式系统。它具有小巧、灵活、低功耗等特点,支持多任务调度、信号量、队列等实…...
golang下载、上传文件MD5高效计算方法,利用io.TeeReader函数特性 实时计算文件md5签名
在go语言的开发中,当我们在操作下载或者上传文件对象时, 我们可以利用golang内置的io包中的 TeeReader函数特性,高效实时计算文件的md5值。 方法如下: TeeReader高效计算文件md5示例 保存上传文件,并使用文件的md5签…...
TreeMap实现根据值比较
前言: TreeMap普通的排序方法都是根据键来比较来排序,本篇文章实现两种方式实现值排序 1.使用 SortedSet 和 Stream API 如果你想要一个持久化的排序结果,你可以使用 SortedSet 结构来存储键值对的条目。 TreeSet<Map.Entry<String, …...
2024前端面试(内容持续更新)
Vue篇 data为什么是个函数? 在Vue中,data必须是一个函数,这是因为当data是函数时,每个组件实例化时都会调用该函数,返回一个新的数据对象,从而保证每个组件实例拥有独立的数据,避免数据冲…...

接口基础知识5:详解request headers(一篇讲完常见字段)
课程大纲 一、请求头的定义 HTTP请求头部(HTTP Request Headers):HTTP协议中的一部分,用于在客户端和服务器之间传递附加信息。这些头部字段提供了关于请求、客户端环境、或请求的上下文的信息。 请求头是键值对的形式ÿ…...
mac的node使用
查看当前Node和npm版本 node -v npm -v安装"n"版本管理工具 sudo npm install -g n 更新node版本 sudo n stable // 稳定版本 sudo n lts // 最新稳定版本 sudo n latest // 最新版本 sudo n xx.xx // 更新到指定版本查看node版本安装集合 n ls切换对应node版…...

HTML - 简易版打字练习
1. 赛博朋克风格的视觉设计 颜色与渐变:通过linear-gradient设置了背景的颜色渐变,使用高饱和度的霓虹色彩(如橙色、绿色和蓝色)来营造赛博朋克的视觉效果。这种配色方案是赛博朋克风格的典型元素。 立体感和阴影:使用…...

【生成式人工智能-四-chatgpt的训练过程-pretrain预训练自督导式学习督导式学习】
大模型是怎么被训练出来的具有人类智慧的 阶段一训练-自我学习-具备知识训练资料self-supervised learning(自督导式学习) 阶段二-怎么让模型具备人的智慧supervised learning 督导式学习预训练pretrain为什么要用预训练的模型?Adapter逆向工…...
期权价格的奥秘:深入理解影响因素
在金融市场中,期权作为一种衍生工具,为投资者提供了风险管理和资产增值的多种可能性。期权价格的波动往往令人着迷,但其背后的定价机制却充满了复杂性。本文将带您探索期权价格变化的奥秘,并尝试以浅显易懂的方式,解析…...

STM32-USART时序与寄存器状态分析
一、时序分析 在UART(通用异步收发传输)通信中,信号线上的状态分为两种:逻辑1(高电平)和逻辑0(低电平)。在空闲状态下,数据线应保持逻辑高电平。UART协议中的各个信号位具…...

从零安装pytorch并在pycharm中使用
背景介绍 目前主流使用的工具有Facebook搞的pythorch和谷歌开发的tensorflow两种,二者在实现理念上有一定区别,pytorch和人的思维模式与变成习惯更像,而tensorflow则是先构建整体结构,然后整体运行,开发调试过程较为繁…...

开源AI工具FastGPT和RagFlow对比
FastGPT和RagFlow都是基于大型语言模型(LLM)的先进AI系统,它们在多个方面有着各自的特点和优势。 以下是对两者性能的详细对比: 一、系统架构与功能 FastGPT: 数据收集:通过从互联网上收集大量的文本数…...
第N2周:NLP中的数据集构建
对于初学者,NLP中最烦人的问题之一就数据集的构建问题,处理不好就会引起shape问题(各种由于shape错乱导致的问题)。这里给出一个模版,大家可根据这个模版来构建。 torch.utils.data是PyTorch中用于数据加载和预处理的…...

AI助力浮雕创作!万物皆可浮雕?Stable Diffusion AI绘画【浮雕艺术】之文生浮雕!
前言 对于浮雕艺术,其实并不了解。但有幸能和“细辛”前辈结识,对浮雕有了简单的了解,浮雕图案的传统方式是先由画师画出图,然后由雕刻师雕刻。画师画图归为浮雕的设计阶段,画师会绘制出浮雕的设计图,这为…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...