springboot项目读取dll
目录
- 1. 依赖
- 2. 代码
- 3. 坑
- %1 不是有效的 Win32 应用程序。
1. 依赖
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 调用dll --><dependency><groupId>net.java.dev.jna</groupId><artifactId>jna</artifactId><version>5.12.1</version></dependency><!-- json转换 --><dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.35</version></dependency>
2. 代码
读取dll:
/*** @desc 调用 SSSE32.dll* @Date 2025/5/20 15:17*/
@Slf4j
@Service
public class BankTransServiceImpl implements BankTransService {@Resourceprivate YmlConfig ymlConfig;private static final int POINTER_BUFFER_SIZE = 512 * 512;@Overridepublic String callBankTrans(JSONObject params) {// 返参String res;String inputData = JSONObject.toJSONString(params);// 设置JNA编码System.setProperty("jna.encoding", ymlConfig.getDllEncode());// 设置内存保护模式是否开启System.setProperty("jna.protected", ymlConfig.getDllProtected());NativeLibrary nativeLibrary = NativeLibrary.getInstance(ymlConfig.getDllPath());// 声明内存操作相关变量Memory outMemory = null; // 输出数据内存缓冲区Pointer inPointer = null; // 输入数据指针Object[] inputArgs; // 输入参数数组(用于业务调用)try {// 创建输出内存缓冲区(预分配空间)outMemory = createStrOutMemory();// 将输入字符串转换为指针(供DLL读取)inPointer = createStrInPointer(inputData);// 业务调用参数数组(输入指针+输出缓冲区)inputArgs = new Object[]{inPointer, outMemory};// 调用 dll 函数int rpcStatus = nativeLibrary.getFunction(ymlConfig.getFunctionName()).invokeInt(inputArgs);String outputData = readStrMemory(outMemory);BankTransResponse bankTransResponse;try {bankTransResponse = JSON.parseObject(outputData, BankTransResponse.class);} catch (Throwable e) {log.error("解析{}返回报文失败: {}", getFileName(ymlConfig.getDllPath()), e.getMessage());return ResultBean.fail("解析返回报文失败:" + e.getMessage() + ";rpcStatus=" + rpcStatus).toStringJSON();}if (!"00".equals(bankTransResponse.getRespCode())) {return ResultBean.fail("调用 " + ymlConfig.getFunctionName() + " 函数失败: " + bankTransResponse.getRespMsg()).toStringJSON();}res = ResultBean.success(bankTransResponse).toStringJSON();} catch (Exception e) {log.error("调用 {} 函数失败: {}", ymlConfig.getFunctionName(), e.getMessage());return ResultBean.fail("调用" + ymlConfig.getFunctionName() + "失败: " + e.getMessage()).toStringJSON();} finally {// 资源释放块(防止内存泄漏)if (Objects.nonNull(inPointer)) {inPointer = null;// 注:某些环境可能需要显式释放 Native.free()// freeMemory(inPointer);}if (Objects.nonNull(outMemory)) {// 置空输出内存outMemory = null;// freeMemory(outMemory);}if (Objects.nonNull(nativeLibrary)) {// 关闭DLL引用nativeLibrary.close();}}return res;}// region 下列是工具方法private static Memory createStrOutMemory() {Memory memory = new Memory(POINTER_BUFFER_SIZE);memory.clear();memory.setString(0, "");return memory;}private static Pointer createStrInPointer(String str) {Pointer pointer = new Memory(POINTER_BUFFER_SIZE);pointer.setString(0, str, System.getProperty("jna.encoding"));return pointer;}private static String readStrMemory(Memory memory) {String rtn = memory.getString(0, System.getProperty("jna.encoding")).trim();
/* long peer = Pointer.nativeValue(memory);//手动释放内存Native.free(peer);Pointer.nativeValue(memory, 0);*/return rtn;}private static void freeMemory(Pointer pointer) {try {long peer = Pointer.nativeValue(pointer);//避免Memory对象被GC时重复执行Nativ.free()方法Native.free(peer);Pointer.nativeValue(pointer, 0);//手动释放内存} catch (Throwable t) {log.error("清内存失败: {}", t.getMessage())}}private static String getFileName(String path) {if (path == null || path.isEmpty()) {return "";}// 替换路径分隔符,统一为正斜杠path = path.replace("\\", "/");// 获取最后一个斜杠的位置int lastSlashIndex = path.lastIndexOf('/');// 如果路径中没有斜杠,直接返回路径本身if (lastSlashIndex == -1) {return "";}// 返回最后一个斜杠之后的部分,即文件名return path.substring(lastSlashIndex + 1);}// endregion
}
ResultBean:
/*** @desc ResultBean* @Date 2025/5/20 15:59*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class ResultBean<T> {public static final int SUCCESS = 1;public static final int FAIL = -1;private int code = SUCCESS;private String message = "success";private transient T data;public ResultBean(T data){super();this.data = data;}public ResultBean(int code, String message) {this.code = code;this.message = message;}public boolean isSuccess() {return SUCCESS == this.code;}public static <T> ResultBean<T> success(T data) {return new ResultBean<>(data);}public static <T> ResultBean<T> fail(String message) {return new ResultBean<>(FAIL, message);}/*** @desc 存在data的泛型数据类型,无法被 jsonObject 转化成 jsonString* @param* @return java.lang.String* @date 2025/5/20 16:03**/public String toStringJSON() {return "{\"code\":" +code +"," +"\"message\":" +"\"" + message + "\"" +"," +"\"success\":" +"\"" + isSuccess() + "\"" +"," +"\"data\":" +JSONObject.toJSONString(data) +"}";}
}
3. 坑
%1 不是有效的 Win32 应用程序。
NativeLibrary.getInstance(ymlConfig.getDllPath());
报错:
2025-05-20 16:17:08.880 [45249010-d03a-4eeb-b7bf-a18311fdd77a] [http-nio-9091-exec-1] ERROR o.a.c.c.C.[.[.[/fsiutil].[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [/fsiutil] threw exception [Handler dispatch failed; nested exception is java.lang.UnsatisfiedLinkError: Unable to load library 'C:\Users\Lenovo\Desktop\CQSecurityCardDemo\SSSE32.dll':
%1 不是有效的 Win32 应用程序。%1 不是有效的 Win32 应用程序
错因: DLL与JVM位数不一致
32位DLL → 32位JVM
64位DLL → 64位JVM
处理: 下载一个32位的JDK,不配置环境变量,idea直接指定使用该jdk。
-
下载:https://mirrors.tuna.tsinghua.edu.cn/Adoptium/8/jdk/x32/windows/
-
idea指定jdk