背景
在集成海康sdk时,需要将一些组件放到项目中作为静态资源,并且海康的sdk初始化也需要加载这些静态资源,在windows下,使用一些File路径的方式是可以正确加载的,但是在linux上就会加载失败。
首先我是将海康的sdk组件放到resource下的,并且按照windows和linux设置了两个文件夹,打成jar包后,在linux上会出现访问不了资源的情况。
项目结构
linux上加载失败原因
打成jar包后,jar包就相当于一个压缩包,此时无法获取resource目录下的文件路径。
解决方案
将lib/linux下整个文件全部复制到当前项目的目录下,就相当于放在了与jar包平级的目录下,例如jar包路径:/opt/a/xx.jar,那复制会组件库的位置就在/opt/a,这时应用只需要读取新的组件库位置,就能正确加载组件库了。
处理
核心处理:
- 使用ResourcePatternResolver类,可以获取resource下符合条件的所有资源名
- 获取的Resource对象,是没有方法可以判断到底是文件夹还是文件的,这里我通过实验发现一个可行办法。。。如果是文件夹,那么resource.getFilename()是一定为空的,因为文件夹其实并不算一个资源,
- 写文件时必须使用流,不能用File对象
结果
以下是处理resource目录下文件夹或文件复制的工具类
package com.lezhi.szxy.hkEducation.util;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import java.io.*;
import java.util.Arrays;
import java.util.stream.Collectors;
/**
* @author:hahaha
* @creattime:2021-12-02 10:33
*/
@Slf4j
public class ResourceFileUtil {
/**
* 复制resource下指定文件夹内所有的文件至目标目录,包括子文件夹
* @param sourcePath classpath文件路径,例如 static/hk
* @param newPath 目标目录
*/
public static void copyFolderFromResource(String sourcePath, String newPath) throws IOException {
log.info("源文件夹:{}, 目标文件夹:{}", sourcePath, newPath);
if (!FileUtil.exist(newPath)) {
FileUtil.mkdir(newPath);
}
// 注意:一定要使用/**,获取所有匹配的文件,包括子文件夹及其下的文件
// /* 只能获取该目录下的一级目录下的文件,无法继续下转获取子文件夹的文件,并且/* 无法获取子文件夹,这里说的是文件夹哈,即连Resource对象都不会存在
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
Resource[] resources = context.getResources(sourcePath + File.separator + "**");
// 在linux下运行时,resource必须是ClassPathResource类型,其打印的Description格式为 class path resource [lib/linux/HCNetSDKCom/],可通过日志查看是否加载正确,如果不正确,说明项目结构有问题,无法识别classpath
// 在windows下运行时,resource有可能是FileSystemResource类型,其打印的Description格式为 file [xxxx]
log.info("sourcePath 下的资源列表:{}", Arrays.stream(resources).map(Resource::getDescription).collect(Collectors.toList()));
Arrays.stream(resources).forEach(resource -> {
try {
// 获取目标文件夹的 下级及子级目录
String filename = getRealPathFromDesc(resource, sourcePath);
if (StrUtil.isBlank(filename) || File.separator.equals(filename)) {
return;
}
String destFilePath = newPath + filename;
// getFilename为空说明是文件夹,ClassPathResource下的文件夹就是空的资源名
// 如果是文件系统,则直接判断文件是否是文件夹
if (StrUtil.isBlank(resource.getFilename()) ||
(resource instanceof FileSystemResource && resource.getFile().isDirectory())
) {
if (!FileUtil.exist(destFilePath)) {
new File(destFilePath).mkdirs();
}
return;
}
// 否则是文件资源,则直接写文件
FileUtil.writeFromStream(resource.getInputStream(), destFilePath);
} catch (Exception e) {
log.