使用gitee自动备份文件

需求

舍友磁盘前两天gg了,里面的论文没有本地备份,最后费劲巴拉的在坚果云上找到了很早前的版本。我说可以上传到github,建一个私人仓库就行了,安全性应该有保证,毕竟不是啥学术大亨,不会有人偷你论文。但是他嫌每次写完还得手动操作,能不能写一个自动检测修改的软件,然后修改后就自动上传到github上。

第一反应是,需要word提供的接口,使用观察者模式,从而检测修改,然后通过github的API,开发一个上传文件的软件。但是通过word开发实在是太难了。

然后今天想了想,完全不需要,直接写个定时任务,10分钟检查下是否有文件进行修改就行了。本来就不要求较高的实时性,所以根本用不到观察者模式。

这样的话就有两种选择了,第一通过Java调用git然后进行文件的提交和上传,第二就是自己开发一个类似于git的工具,针对文件的创建,修改和删除进行对应的github仓库修改。

今天的话,是想着使用第二种方式的,确实有点难,用了一下午时间,才完成了文件的上传功能。

使用第二种方式,需要分析:

  • git add .和git commit实现的功能
  • git pull和push实现的功能

使用第一种方式,就简单许多

  • 监听时间
  • 使用jgit进行上传文件

简单设计

  • 监听类 Listenner :负责监听目录/文件等的变化。
  • 上传类 UpLoader : 负责将文件上传到github或者gitee或者其他云盘上
    • GiteeUpLoader
    • GithubUpLoader
    • GitUploader
  • 主类 Main
  • utils类
  • 常量(使用接口),异常,还有配置文件,工具文件等

差不多类似于这样吧,忽略chapter1,这个是之前的项目。

image-20240317212206535

事件监听

Gitee文件上传类

package autoSendFiles.uploaders;

import autoSendFiles.constants.UploadConstants;
import autoSendFiles.exception.NullPropertiesException;

import java.io.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import autoSendFiles.interfaces.Uploader;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;

/**
 * @author: Zekun Fu
 * @date: 2024/3/17 12:12
 * @Description: 通过调用git的方式,将文件上传到Gited中
 */
public class GiteeUploader implements Uploader {

    private String accessToken;
    private String username;
    private String repository;
    private String branch;


    public GiteeUploader() throws NullPropertiesException {
        // 读取参数,如果没有配置,抛出异常
        try (InputStream input = new FileInputStream(UploadConstants.APP_PROPERTIES_PATH)) {
            Properties properties = new Properties();

            // 加载 properties 文件
            properties.load(input);

            // 获取属性值
            this.accessToken = properties.getProperty("gitee.accessToken");
            this.username = properties.getProperty("gitee.username");
            this.repository = properties.getProperty("gitee.repository");
            this.branch = properties.getProperty("gitee.branch");
            if (StringUtils.isAnyEmpty(accessToken, username, repository, branch))
                throw new NullPropertiesException("未配置Gitee属性,请先配置!");
        } catch (IOException e) {
            System.out.println("系统异常!请联系管理员");
            e.printStackTrace();
        }
    }

    public List<File> upload(List<File> files) {
        return uploadHelper(files);
    }

    private List<File> uploadHelper(List<File>files) {
        List<File>failUploadFiles = new ArrayList<>();
        for (File file : files) {
            // 如果没有上传成功,需要放入到传输失败列表中
            try {
                if (!upload(file))
                    failUploadFiles.add(file);
            } catch (IOException e) {
                failUploadFiles.addAll(files);
                e.printStackTrace();
            }
        }
        return failUploadFiles;
    }
    private boolean upload(File file) throws IOException {
        // 生成路径,提交信息,以及提交文件的base64编码
        String savePath = getSavePath(file);
        String message = generatorSendMessage();
        String content = this.fileBase64(file);

        // 创建 http 客户端
        String apiUrl = String.format(UploadConstants.UPLOAT_URL, this.username, this.repository, savePath);
        OkHttpClient client = new OkHttpClient();

        // 创建请求体
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart(UploadConstants.ACCESS_TOKEN, this.accessToken)
                .addFormDataPart(UploadConstants.CONTENT, content)
                .addFormDataPart(UploadConstants.MESSAGE, message)
                .addFormDataPart(UploadConstants.BRANCH, this.branch)
                .build();

        // 创建 http 请求
        Request request = new Request.Builder()
                .url(apiUrl)
                .post(requestBody)
                .build();

        // 接收响应
        Response response = client.newCall(request).execute();

        // 上传
        if (response.isSuccessful()) {
            System.out.println("文件上传成功!");
            return true;
        } else {
            System.out.println("文件上传失败:" + response.code() + " " + response.message());
            return false;
        }
    }

    private String generatorSendMessage() {
        LocalDateTime currentDateTime = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm");
        String formattedDateTime = currentDateTime.format(formatter);
        String msg = formattedDateTime + "提交";
        return msg;
    }

    private String fileBase64(File file) throws IOException {
        return Base64.getEncoder().encodeToString(fileToByteArray(file));
    }
    private byte[] fileToByteArray(File file) throws IOException {
        byte[] data = new byte[(int) file.length()];
        try (FileInputStream fis = new FileInputStream(file)) {
            fis.read(data);
        }
        return data;
    }
    /**
     * @return 生成路径, 如果为空,说明生成错了,没有.git文件夹
     * */
    private String getSavePath(File file) {
        StringBuffer savePath = new StringBuffer();
        return UploadConstants.DIR_SPLIT + findGitDirectory(file, savePath);
    }
    /**
     * @return 递归获取路径,直到碰到.git为止
     * */
    private String findGitDirectory(File directory, StringBuffer savePath) {
        StringBuffer curPath = new StringBuffer(directory.getName());
        if (!StringUtils.isEmpty(savePath)) curPath.append(UploadConstants.DIR_SPLIT).append(savePath);
        File gitDirectory = new File(directory, UploadConstants.ROOT_DIR);
        if (gitDirectory.exists() && gitDirectory.isDirectory()) {
            return savePath.toString();
        } else {
            File parentDirectory = directory.getParentFile();
            if (parentDirectory != null) {
                return findGitDirectory(parentDirectory, curPath);
            } else {
                return null;
            }
        }
    }

    public static void testGenerateSendMesage(GiteeUploader uploader) {
        System.out.println("提交msg为:" + uploader.generatorSendMessage());
    }

    public static void testGetPath(GiteeUploader uploader, File file) {
        // 1. 如果不包含.git文件
        // 2. Linux的和windows的分隔符不一样
        // 3. 其他特殊情况
        String filePath = uploader.getSavePath(file);
        if (!StringUtils.isEmpty(filePath)) {
            System.out.println("当前的保存路径为:" + filePath);
        }
        else System.out.println("测试失败,无法获取当前文件的路径");
    }

    public static GiteeUploader testCreateUploader() throws IOException, NullPropertiesException{
        GiteeUploader uploader = new GiteeUploader();
        return uploader;
    }

    public static void testBase64(GiteeUploader uploader, File file) throws IOException {
        String content = uploader.fileBase64(file);
        if (StringUtils.isEmpty(content)) {
            System.out.println("base64编码后的内容为空!");
            return ;
        }
        System.out.println("base64编码后的内容为:" + content);
    }

    public static void testUpLoad() throws IOException, NullPropertiesException {
        String FilePath = "D:\\learning\\论文\\毕业论文\\毕业论文备份\\test.txt";
        GiteeUploader uploader = new GiteeUploader();
        File file = new File(FilePath);
        uploader.upload(new File(FilePath));
    }

    public static void test() throws NullPropertiesException, IOException {
        System.out.println("测试开始...");
        String FilePath = "D:\\learning\\论文\\毕业论文\\毕业论文备份\\test.txt";
        GiteeUploader uploader = testCreateUploader();
        testGenerateSendMesage(uploader);
        File file = new File(FilePath);
        testGetPath(uploader, file);
        testBase64(uploader, file);
        testUpLoad();
        System.out.println("测试完成...");
    }


    public static void main(String[] args) throws NullPropertiesException, IOException{
        test();
    }
}

定时监听

项目架构

image-20240317234653713

运行效果

image-20240317234741826

运行结果:固定时间进行扫描提交

image-20240317235255019

时间监听器

package autoSendFiles.Listener;

import autoSendFiles.constants.ApplicationConstants;
import autoSendFiles.constants.PropertyConstants;
import autoSendFiles.interfaces.Listenner;
import autoSendFiles.interfaces.Uploader;
import autoSendFiles.utils.AppPropertiesUtils;

/**
 * @author: Zekun Fu
 * @date: 2024/3/17 23:02
 * @Description:
 */
public class TimeListenner implements Listenner, Runnable{
    private Thread thread;
    private Uploader uploader;
    private int listenTime;
    public TimeListenner(Uploader uploader) {
        this.uploader = uploader;
        this.listenTime = Integer.parseInt(AppPropertiesUtils.getProperty(PropertyConstants.LISTEN_TIME));
    }

    @Override
    public void run() {
        System.out.println("线程监听开始...");
        while (true) {
            if (this.thread.isInterrupted()) {
                // 实际结束线程的地方
                break;
            }
            try {

                // 上传修改的文件
                System.out.println("同步中...");
                this.uploader.uploadAllChanges();
                System.out.println("同步完成...");

                // 睡眠
                Thread.sleep(ApplicationConstants.TO_SECONDS * this.listenTime);

            } catch (InterruptedException e) {
                // 这里处理善后工作

                // 重新进行标记,从而可以结束线程
                this.thread.interrupt();
            }
        }
    }

    @Override
    public void listen() {
        // 开启线程进行监听
        System.out.println("开启新线程,启动监听...");
        this.thread = new Thread(this);
        thread.start();
    }

    public void stop() {
        this.thread.interrupt();
    }
}

主线程

package autoSendFiles;

import autoSendFiles.Listener.TimeListenner;
import autoSendFiles.constants.ApplicationConstants;
import autoSendFiles.constants.PropertyConstants;
import autoSendFiles.exception.NullPropertiesException;
import autoSendFiles.interfaces.Uploader;
import autoSendFiles.uploaders.GitUploader;
import autoSendFiles.utils.AppPropertiesUtils;

import javax.imageio.IIOException;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * @author: Zekun Fu
 * @date: 2024/3/17 12:12
 * @Description:
 */
public class Main {

    public static void main(String[] args) throws NullPropertiesException, IIOException {
        Uploader uploader = new GitUploader();
        TimeListenner listenner = new TimeListenner(uploader);
        listenner.listen();
        try {
            int times = Integer.parseInt(AppPropertiesUtils.getProperty(PropertyConstants.RUN_TIME));
            Thread.sleep(times * ApplicationConstants.TEN_MINUTES);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 100min后结束
        listenner.stop();
    }
}

Git上传器

package autoSendFiles.uploaders;

import autoSendFiles.constants.ApplicationConstants;
import autoSendFiles.constants.PropertyConstants;
import autoSendFiles.constants.UploadConstants;
import autoSendFiles.exception.NullPropertiesException;
import autoSendFiles.interfaces.Uploader;
import autoSendFiles.utils.AppPropertiesUtils;
import autoSendFiles.utils.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.AddCommand;
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.eclipse.jgit.util.IO;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author: Zekun Fu
 * @date: 2024/3/17 22:20
 * @Description: 静态常量设计的不行! gitee和github的不分了。
 * 重新开启一个文件叫做参数常量文件就行了。
 */
public class GitUploader implements Uploader {
    private String workDir;
    private String remoteName;
    private String branch;
    private String password;
    private String username;
    public GitUploader() throws NullPropertiesException {
        workDir = AppPropertiesUtils.getProperty(PropertyConstants.WORK_DIR);
        remoteName = AppPropertiesUtils.getProperty(PropertyConstants.GITEE_REMOTE_NAME);
        branch = AppPropertiesUtils.getProperty(PropertyConstants.GITEE_BRANCH);
        password = AppPropertiesUtils.getProperty(PropertyConstants.GITEE_PASSWORD);
        username =AppPropertiesUtils.getProperty(PropertyConstants.GITEE_USERNAME);
        if (StringUtils.isAnyEmpty(workDir, remoteName, branch, password)) {
            throw new NullPropertiesException("没有配置工作文件夹,检查配置文件!");
        }
    }

    @Override
    public List<File> upload(List<File> files) {
        List<File>failList = this.uploadHelper(files);
        this.commit();
        this.push();
        return failList;
    }

    @Override
    public void uploadAllChanges() {
        this.pushAllChanges();
    }

    /**
     * 完成所有修改文件的同步
     * */
    private void pushAllChanges() {
        this.addAll();
        this.commit();
        this.push();
    }

    public boolean add(String filePath) {
        try (Git git = Git.open(new File(this.workDir))) {
            AddCommand addCommand = git.add();
            addCommand.addFilepattern(filePath);
            addCommand.call();
            System.out.println(filePath + " 添加完成。");
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public void addAll() {
        try (Git git = Git.open(new File(this.workDir))) {
            AddCommand addCommand = git.add();
            addCommand.addFilepattern(".");
            addCommand.call();

            System.out.println("Git add . 操作完成。");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void commit() {
        try (Git git = Git.open(new File(this.workDir))) {
            CommitCommand commitCommand = git.commit();
            commitCommand.setMessage(this.getCommitMessage());
            commitCommand.call();
            System.out.println("Git commit 操作完成。");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void commit(String msg) {
        try (Git git = Git.open(new File(this.workDir))) {
            CommitCommand commitCommand = git.commit();
            commitCommand.setMessage(msg);
            commitCommand.call();
            System.out.println("Git commit 操作完成。");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void push() {
        try (Git git = Git.open(new File(this.workDir))) {
            PushCommand pushCommand = git.push();
            pushCommand.setRemote(remoteName);
            pushCommand.setRefSpecs(new RefSpec(this.branch));
            // 用户密码验证
            CredentialsProvider credentialsProvider = new UsernamePasswordCredentialsProvider(this.username, this.password);
            pushCommand.setCredentialsProvider(credentialsProvider);
            pushCommand.call();

            System.out.println("Git push 操作完成。");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private List<File>uploadHelper(List<File> files) {
        List<File>failedFile = new ArrayList<>();
        for (File f : files) {
            if (!this.add(f.getName()))
                failedFile.add(f);
        }
        return failedFile;
    }
    private String getCommitMessage() {
        return DateUtils.getCurTime(ApplicationConstants.MIN_PATTERN) + "提交";
    }

    public static void testGitUploader() throws IOException, NullPropertiesException {
        Uploader uploader = new GitUploader();
        List<File> fileList = new ArrayList<>();
        String[] filePathList = {"D:\\projects\\java\\projects\\autoCommit\\test3.txt", "D:\\projects\\java\\projects\\autoCommit\\test4.txt"};
        for (String filePath : filePathList) {
            fileList.add(new File(filePath));
        }
        List<File>failedFiles = uploader.upload(fileList);
        if (failedFiles.size() != 0) {
            System.out.println("上传失败的文件有:");
            for (File file : failedFiles) {
                System.out.println(file.getName());
            }
        }
    }

    public static void main(String[] args) throws NullPropertiesException , IOException{
//        new GitUploader().push();
        GitUploader uploader = new GitUploader();
        uploader.add("test3.txt");
    }
}

工具文件

package autoSendFiles.utils;

import autoSendFiles.constants.UploadConstants;
import autoSendFiles.exception.NullPropertiesException;
import org.apache.commons.lang3.StringUtils;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * @author: Zekun Fu
 * @date: 2024/3/17 21:50
 * @Description:
 */
public class AppPropertiesUtils {
    private static Properties properties = new Properties();
    static {
        // 读取参数,如果没有配置,抛出异常
        try (InputStream input = new FileInputStream(UploadConstants.APP_PROPERTIES_PATH)) {
            // 加载 properties 文件
            properties.load(input);
        } catch (IOException e) {
            System.out.println("系统异常!请联系管理员");
            e.printStackTrace();
        }
    }
    public static String getProperty(String key) {
        return properties.getProperty(key);
    }
}

package autoSendFiles.utils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @author: Zekun Fu
 * @date: 2024/3/17 21:43
 * @Description:
 */
public class DateUtils {
    public static String getCurTime(String pattern) {
        LocalDateTime currentDateTime = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return currentDateTime.format(formatter);
    }
}

配置文件

# gitee配置
gitee.accessToken=你的口令
gitee.branch=本地分支
gitee.username=用户名
gitee.password=密码
gitee.repository=仓库
gitee.remoteName=远程分成

# 监听的git路径
work.dir=D:/projects/java/projects/autoCommit

# 监听的时间间隔10min
listen.time=10

# 程序运行时间100min
run.time=100

常量文件

package autoSendFiles.constants;

/**
 * @author: Zekun Fu
 * @date: 2024/3/17 21:45
 * @Description:
 */
public interface ApplicationConstants {
    String MIN_PATTERN = "yyyy/MM/dd HH:mm";
    int TEN_MINUTES = 1000 * 60 * 10;
    int TWENTY_MINUTES = 1000 * 60 * 20;
    int TO_SECONDS = 1000;
    int TO_MIMUTES = 1000 * 60;
}

package autoSendFiles.constants;

/**
 * @author: Zekun Fu
 * @date: 2024/3/17 22:39
 * @Description: 配置Key的常量
 */
public interface PropertyConstants {
    String GITEE_BRANCH = "gitee.branch";
    String GITEE_REMOTE_NAME="gitee.remoteName";
    String WORK_DIR = "work.dir";
    String GITEE_PASSWORD = "gitee.password";
    String GITEE_USERNAME = "gitee.username";
    String LISTEN_TIME = "listen.time";
    String RUN_TIME = "run.time";
}

package autoSendFiles.constants;

/**
 * @author: Zekun Fu
 * @date: 2024/3/17 20:01
 * @Description:
 */
public interface UploadConstants {
    String UPLOAT_URL = "https://gitee.com/api/v5/repos/%s/%s/contents/%s";
    String ACCESS_TOKEN = "access_token";
    String CONTENT = "content";
    String MESSAGE = "message";
    String BRANCH = "branch";
    String ROOT_DIR = ".git";
    String DIR_SPLIT = "/";
    String APP_PROPERTIES_PATH = "src/main/resources/application.properties";
}

异常类

package autoSendFiles.exception;

/**
 * @author: Zekun Fu
 * @date: 2024/3/17 18:18
 * @Description:
 */
public class NullPropertiesException extends Exception{
    public NullPropertiesException(String msg) {
        super(msg);
    }
}

maven依赖

  <dependencies>
        <!-- Apache HttpClient Core -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>

        <!-- Apache HttpClient Mime -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpmime</artifactId>
            <version>4.5.13</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>

        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.9.3</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jgit</groupId>
            <artifactId>org.eclipse.jgit</artifactId>
            <version>5.13.0.202109080827-r</version>
        </dependency>
    </dependencies>

总结

  • 没有实现事件监听器,可以通过listenner进行扩展
  • 文件上传器,接口设计的不好,应该单一职责,这里两个职责了。一个是上传文件,一个是上传所有变化的文件
  • 没有实现图像化结面

下一步

  • 实现git pull的功能,进行文件的覆盖
  • 实现事件监听功能
  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值