背景
在集成海康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.