SpringBoot将resources目录资源复制到指定位置

### 需求
在nookblog博客项目开发过程中,有一个初始化博客的功能:其中需要将项目`resources/static/blog`目录下所有资源资源复制到指定目录。
### 思路
根据我的需求,复制的思路大概是,先获取到`resources/static/blog`目录下文件清单,然后通过清单,循环将文件复制到指定位置(相对路径需要确保一致)

因为项目会被打成jar包,所以不能用传统的目录文件复制方式,这里需要用到Spring Resource:
> Resource接口,简单说是整个Spring框架对资源的抽象访问接口。它继承于InputStreamSource接口。后续文章会详细的分析。

Resource接口的方法说明:

|  方法 | 说明  |
| :------------ | :------------ |
| exists()  |  判断资源是否存在,true表示存在。 |
| isReadable()  |  判断资源的内容是否可读。需要注意的是当其结果为true的时候,其内容未必真的可读,但如果返回false,则其内容必定不可读。 |
|  isOpen() | 判断当前Resource代表的底层资源是否已经打开,如果返回true,则只能被读取一次然后关闭以避免资源泄露;该方法主要针对于InputStreamResource,实现类中只有它的返回结果为true,其他都为false。  |
|  getURL() | 返回当前资源对应的URL。如果当前资源不能解析为一个URL则会抛出异常。如ByteArrayResource就不能解析为一个URL。  |
|  getURI() |  返回当前资源对应的URI。如果当前资源不能解析为一个URI则会抛出异常。 |
| getFile()  |  返回当前资源对应的File。 |
| contentLength() |  返回当前资源内容的长度。 |
|  lastModified() |   返回当前Resource代表的底层资源的最后修改时间。 |
|  createRelative() |  根据资源的相对路径创建新资源。[默认不支持创建相对路径资源] |
| getFilename()  | 获取资源的文件名。  |
|  getDescription() |  返回当前资源底层资源的描述符,通常就是资源的全路径(实际文件名或实际URL地址)。 |
|  getInputStream() |  获取当前资源代表的输入流。除了InputStreamResource实现类以外,其它Resource实现类每次调用getInputStream()方法都将返回一个全新的InputStream。 |

获取Resource清单,我需要通过ResourceLoader接口获取资源,在这里我选择了`org.springframework.core.io.support.PathMatchingResourcePatternResolver`

### 实现代码

```java
...
//资源清单获取
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("static/blog/**");
for (Resource resource : resources) {
	FreeMarkerUtil.copyResourceToFile(resource, aPath,"/static/blog/");
}
...
```

```java
/**
 * 复制指定spring资源到指定路径
 *
 * @param resource
 * @param targetPath       目标路径
 * @param relativeRootPath 资源所在相对路径,如果填写了relativeRootPath,会连同相对relativeRootPath路径后的目录一起建立,反之直接在targetPath复制资源
 * @throws IOException
 */
public static void copyResourceToFile(Resource resource, String targetPath, String relativeRootPath) throws IOException {
	InputStream inputStream = null;
	try {
		inputStream = resource.getInputStream();
	} catch (Exception e) {
		log.warn(String.format("[%s]获取输入流发生异常!", resource.getURL()));
		throw new RuntimeException(String.format("[%s]获取输入流发生异常!", resource.getURL()));
	}
	String filename = resource.getFilename();

	//分析相对目录
	String appenPath = "";
	if (!StringX.isEmpty(relativeRootPath)) {
		String sUrl = resource.getURL().toString();
		if (sUrl.startsWith("jar:file:")) {
			String[] tempArr = sUrl.split("!");
			appenPath = tempArr[tempArr.length - 1];
		} else if (sUrl.startsWith("file:")) {
			appenPath = sUrl.substring("file:".length() - 1);
		}
		int rootPathIndex = appenPath.indexOf(relativeRootPath);
		if (rootPathIndex < 0) {
			throw new RuntimeException("relativeRootPath有误:无法分析相对目录");
		}
		appenPath = appenPath.substring(rootPathIndex + relativeRootPath.length(), appenPath.length() - filename.length());
		if (StringX.isEmpty(appenPath)) {
			appenPath = File.separator;
		}
	}
	String filePath = targetPath + File.separator + appenPath;
	checkAndMkdirs(filePath);
	String fileName = filePath + filename;
	File file = new File(fileName);
	FileUtils.copyInputStreamToFile(inputStream, file);
}
```
:smile:

------------
> 本文由 [叶不空](https://yebukong.com "叶不空") 创作,采用 [知识共享署名 4.0 国际许可协议](https://creativecommons.org/licenses/by/4.0/ "知识共享署名 4.0 国际许可协议")进行许可,转载请附上链接!
> 本文链接: [https://yebukong.com/article/1102629952022507521.html](https://yebukong.com/article/1102629952022507521.html "SpringBoot将resources目录资源复制到指定位置")
                        
(°ο°)评论插件未能完成加载!