Halo(五)

ApplicationPreparedEvent 监听事件

Event published once the application context has been refreshed but before any
{@link ApplicationRunner application} and {@link CommandLineRunner command line}
runners have been called.

Spring Boot 2.0 版本中所有的事件按执行的先后顺序如下:

    ApplicationStartingEvent

    ApplicationEnvironmentPreparedEvent

    ApplicationPreparedEvent

    ApplicationStartedEvent <= 新增的事件

    ApplicationReadyEvent

    ApplicationFailedEvent


@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)  //最高优先级,最先执行
public class StartedListener implements ApplicationListener<ApplicationStartedEvent> {

    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        //打印博客地址
        this.printStartInfo();
        //初始化主题
        this.initThemes();
    }
}

Path、Paths、Files

Path类可用于在文件系统中定位文件的对象,它通常表示系统相关的文件路径:

    getRoot()   //返回此路径的根组分作为 Path 对象,或 null(如果该路径不具有根组件)

    toAbsolutePath()    //返回表示此路径的绝对路径的 Path 对象

    getNameCount()  //返回路径中的名称元素的数量

    resolve()

        把当前路径当成父目录,而把参数中的路径当成子目录或是其中的文件,进行解析之后得到一个新路径。

    resolveSibling()

        方法的作用与 resolve 方法类似,只不过把当前路径的父目录当成解析时的父目录。

    relativize()

        方法的作用与 resolve 方法正好相反,用来计算当前路径相对于参数中给出的路径的相对路径。

    subpath()

        方法用来获取当前路径的子路径,参数中的序号表示的是路径中名称元素的序号。

    startsWith()和endsWith()

        方法用来判断当前路径是否以参数中的路径开始或结尾。

    在一般的路径中,“.”和“..”分别用来表示当前目录和上一级目录。

    Path path1 = Paths.get("folder1", "sub1");
    Path path2 = Paths.get("folder2", "sub2");
    path1.resolve(path2);       folder1\sub1\folder2\sub2
    path1.resolveSibling(path2);        folder1\folder2\sub2
    path1.relativize(path2);        ..\..\folder2\sub2
    path1.subpath(0, 1);        folder1

    path.normalize()
        normalize()方法可以标准化路径,它会处理路径中的相对路径,去除"."".."
        原:path = c:\ld\.\test
        新:path = c:\ld\test

public final class Paths {

    private Paths() {}

    //将路径字符串或连接到路径字符串的字符串序列转换为 Path
    public static Path get(String first, String... more) {
        return Path.of(first, more);
    }

    //将给定的URI转换为Path对象
    public static Path get(URI uri) {
        return Path.of(uri);
    }
}


Files工具类:
    旧的IO中的操作文件的类是File,但是File类只能操作文件(创建,删除,修改属性等),但是不能修改文件的内容。
    Files工具类可以直接写文件。

File工具类通常需要结合Path对象来使用:

    拷贝文件

        copy(...) 有3个重载方法,通常需要跟Path结合使用

    操作文件

        createDirectories(Path dir, FileAttribute<?>... attrs)  //首先创建所有不存在的父目录来创建目录

        createDirectory(Path dir, FileAttribute<?>... attrs)    //创建一个新的目录

        createFile(Path path, FileAttribute<?>... attrs)    //创建一个新的和空的文件,如果该文件已存在则失败

        delete(Path path)   //删除文件

    判断属性

        isHidden(Path path) //告知文件是否被 隐藏

        isReadable(Path path)   //测试文件是否可读

        isDirectory(Path path, LinkOption... options)   //测试文件是否是目录

复制文件夹及文件(Files)

package java.nio.file.Files:

    public static Path walkFileTree(Path start, FileVisitor<? super Path> visitor)

    1) 在旧版本中遍历文件系统只能通过递归的方法来实现,但是这种方法不仅消耗资源大而且效率低

    2) NIO.2 的 Files 工具类提供了一个静态工具方法 walkFileTree 来高效并优雅地遍历文件系统

    3) walkFileTree:

         i. 表示从start代表的节点开始遍历文件系统;

         ii. 其中visitor是遍历过程中的行为控制器;


public class FileUtils {

    private FileUtils() {
    }

    public static void copyFolder(Path source,Path target) throws IOException {

        Files.walkFileTree(source, new SimpleFileVisitor<Path>() {

            private Path current;

            /**
             * 接口方法的返回值 FileVisitResult 是一个枚举类型,
             * walkFileTree 会根据这个返回值决定是否要继续遍历下去,
             * 如果要继续遍历,它总共有4个枚举值:都是 FileVisitResult 中定义的枚举值
             *
             *      CONTINUE:继续遍历
             *
             *      SKIP_SIBLINGS:继续遍历,但忽略当前节点的所有兄弟节点直接返回上一层继续遍历
             *
             *      SKIP_SUBTREE:继续遍历,但是忽略子目录,但是子文件还是会访问
             *
             *      TERMINATE:终止遍历
             */

            //访问一个目录前(dir:正在访问的绝对路径目录)
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                //截取相对路径( source.relativize(dir) ),拼接到目标目录( target.resolve(dir) )
                current = target.resolve(source.relativize(dir).toString());
                //创建目标文件夹,并继续
                Files.createDirectories(current);
                return FileVisitResult.CONTINUE;
            }

            //正在访问一个文件时(file:正在访问的绝对路径文件)
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                //复制文件
                Files.copy(file, target.resolve(source.relativize(file).toString()), StandardCopyOption.REPLACE_EXISTING);
                return FileVisitResult.CONTINUE;
            }
        });
    }
}

递归删除文件夹

    public static void deleteFolder(Path deletingPath) throws IOException {

        if (Files.notExists(deletingPath)) {
            return;
        }

        org.eclipse.jgit.util.FileUtils.delete(deletingPath.toFile(),
                org.eclipse.jgit.util.FileUtils.RECURSIVE | org.eclipse.jgit.util.FileUtils.RETRY);
    }

FileUtils

创建临时目录:

    public static Path createTempDirectory() throws IOException {
        //创建前缀为"halo"的临时目录
        return Files.createTempDirectory("halo");
    }


检查给定路径是否为空:

    public static boolean isEmpty(Path path) throws IOException {

        //不是目录或者不存在,返回true
        if (!Files.isDirectory(path) || Files.notExists(path)) {
            return true;
        }

        /**
         * Files.list(path)
         *      返回的元素是一个惰性填充的流(非递归)
         *      流的元素是Path对象
         */
        try (Stream<Path> pathStream = Files.list(path)) {
            //判断是否是空目录
            return pathStream.count() == 0;
        }
    }


将ZipInputStream解压缩到目标路径:

    public static void unzip(ZipInputStream zis, Path targetPath) throws IOException {

        //创建目标路径(如果路径不存在)
        if (Files.notExists(targetPath)) {
            Files.createDirectories(targetPath);
        }

        //目标路径必须为空
        mustBeEmpty(targetPath);

        ZipEntry zipEntry = zis.getNextEntry();

        while (zipEntry != null) {
            //合并路径
            Path entryPath = targetPath.resolve(zipEntry.getName());

            //检查目录(判断entryPath是否以targetPath开头)
            FileUtils.checkDirectoryTraversal(targetPath, entryPath);

            if (zipEntry.isDirectory()) {
                //创建目录
                Files.createDirectories(entryPath);
            } else {
                //复制文件
                Files.copy(zis, entryPath);
            }
            zipEntry = zis.getNextEntry();
        }
    }
上一篇:GitHub 标星 1.3w+,这可能是我见过最好的博客系统了....


下一篇:推荐一个超级好用的博客系统Halo