使用gitee自动备份文件

news2025/1/11 5:36:55

需求

舍友磁盘前两天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的功能,进行文件的覆盖
  • 实现事件监听功能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1524553.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C到C++的敲门砖-1

文章目录 关键字命名空间输入和输出缺省参数函数重载 关键字 相较于C语言32个关键字&#xff1a; autodoubleintstructbreakelselongswitchcaseenumregistertypedefcharexternreturnunionconstfloatshortunsignedcontinueforsignedvoiddefaultgotosizeofvolatiledoifwhilesta…

配置阿里云加速器

国内镜像中心常用阿里云或者网易云。在本地docker中指定要使用国内加速器的地址后&#xff0c;就可以直接从阿里云镜像中心下载镜像。 2024阿里云-上云采购季-阿里云 [rootlocalhost /]# mkdir -p /etc/docker [rootlocalhost /]# tee /etc/docker/daemon.json <<-EOF &…

ThreadLocal-阿里规范对ThreadLocal要求

package com.nanjing.gulimall.zhouyimo.test;import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;/*** @author zhou* @version 1.0* @date 2024/3/17 11:05 下午*/ class MyData{ThreadLocal<Integer> threadLocal = ThreadLocal.wi…

C语言 求方程ax^2+bx+c=0的根

一、求方程ax^2bxc0的根&#xff0c;用三个函数分别求当&#xff1a;b^2-4ac大于0&#xff0c;等于0&#xff0c;和小于0时的根并输出结果。从主函数输入a&#xff0c;b&#xff0c;c的值。 #include <stdio.h> #include<math.h> float x,x1,x2,disc; int main() …

ChatGPT编程实现简易聊天工具

ChatGPT编程实现简易聊天工具 今天借助[[小蜜蜂]][https://zglg.work]网站的ChatGPT练习socket编程&#xff0c;实现一个简易聊天工具软件。 环境&#xff1a;Pycharm 2021 系统&#xff1a;Mac OS 向ChatGPT输入如下内容&#xff1a; ChatGPT收到后&#xff0c;根据返回结…

【CSP试题回顾】201509-1-数列分段

CSP-201509-1-数列分段 解题代码 #include <iostream> #include <vector> #include <algorithm> using namespace std;int n;int main() { cin >> n;vector<int>arr(n);for(auto & it:arr) {cin >> it;}auto last unique(arr.be…

DevOps 环境预测测试中的机器学习

在当今快节奏的技术世界中&#xff0c;DevOps 已成为软件开发不可或缺的一部分。它强调协作、自动化、持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;&#xff0c;以提高软件部署的速度和质量。预测测试是这一领域的关键组成部分&#xff0c;其中机器…

生成式AI竞赛:开源还是闭源,谁将主宰未来?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

2024抖音矩阵云混剪系统源码 短视频矩阵营销系统

2024抖音矩阵云混剪系统源码 短视频矩阵营销系统 矩阵营销系统多平台多账号一站式管理&#xff0c;一键发布作品。智能标题&#xff0c;关键词优化&#xff0c;排名查询&#xff0c;混剪生成原创视频&#xff0c;账号分组&#xff0c;意向客户自动采集&#xff0c;智能回复&am…

Python基础(七)之数值类型集合

Python基础&#xff08;七&#xff09;之数值类型集合 1、简介 集合&#xff0c;英文set。 集合&#xff08;set&#xff09;是由一个或多个元素组成&#xff0c;是一个无序且不可重复的序列。 集合&#xff08;set&#xff09;只存储不可变的数据类型&#xff0c;如Number、…

uwsgi+nginx+django 部署学习

收集静态文件及部署配置 DEBUG False STATICFILES_DIRS [os.path.join(BASE_DIR, "static"), ] STATIC_ROOT /data/static python3 manage.py collectstatic 收集静态文件&#xff0c;成功后可在STATIC_ROOT目录查看 安装依赖 pip3 install uwsgi django项目结…

docker基础用法-2

文章目录 什么是dockerOCI&OCFOCIOCF docker架构docker镜像与镜像仓库docker对象安装及使用dockerdocker安装docker加速docker常用操作docker event state防火墙状态及规则 什么是docker docker中的容器&#xff1a; lxc --> libcontainer --> runC docker最开始是…

嵌入式学习之Linux系统编程篇笔记——系统编程初探

配套视频学习链接&#xff1a;https://www.bilibili.com/video/BV1zV411e7Cy?p2&vd_sourced488bc722b90657aaa06a1e8647eddfc 目录 Linux系统编程的基本认识 什么是Linux系统编程? 什么是系统编程 系统编程的作用 怎么学习Linux系统编程? Linux系统编程基本程序框…

数据可视化学习:Matplotlib概述

一、图表的常用设置 1.基本绘图主要函数 (1).matplotlib.pyplot.plot(x,y,format_string,**kwargs) 2.参数说明 (1).x:x轴数据 (2).y:y轴数据 (3).format_string:控制曲线格式的字符串&#xff0c;包括颜色、线条样式和标记样式 (4)**kwargs:键值参数&#xff0c;相当于…

IDEA : 已经有一个永久破解版的IDEA2019版本,现在又想安装最新版本的,俩版本共存,发现新版本打不开的解决方案

在新文件的目录下&#xff0c;注释掉一行19版本的地址 地址&#xff1a;C:\Users\23999\AppData\Roaming\JetBrains\IntelliJIdea2023.2 (不同电脑Users后边的一个地址的注释会不一样) 然后找到该目录下的indea64.exe.vmoptions 用 记事本 打开 在-javaagent 那一栏里会自动给…

如何学习一个大型分布式Java项目

前言 很多同学在没有实习经验的时候看到一个多模块分布式项目总是有一种老虎吃天的无力感&#xff0c;就像我刚毕业去到公司接触项目的时候一样&#xff0c;模块多的夸张&#xff0c;想学都不知道从哪开始学&#xff0c;那么我们拿到一份代码后如何从头开始学习一个新项目呢。…

ThingsBoard Edge 设备控制

文章目录 一、RPC 功能1.服务端 RPC2.客户端 RPC3.MQTT RPC API3.1.服务端RPC3.2.客户端RPC 二、设备控制1.环境准备2.创建设备3.服务端PRC3.1.RPC消息主题3.2.程序源码3.3.创建仪表板3.4.边缘分配仪表板3.5.测试 4.客户端RPC4.1.RPC消息主题4.2.程序源码4.3.规则链4.4.测试 Th…

Selenium-webdriver_manager判断是否已经下载过驱动(复用缓存驱动)

1,谷歌浏览器默认位置 2&#xff0c;ChromeDriverManager 下载的驱动位置 其中admin为机器的用户名 def installDriver(self):"""判断是否需要下载driver""""""找到本机谷歌浏览器版本""""""C:\P…

软考81-上午题-【面向对象技术3-设计模式】-行为型设计模式01

一、行为型设计模式一览 二、责任链模式 2-1、意图 使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链&#xff0c;并沿着这条链传递该请求&#xff0c;直到有一个对象处理它为止。 1-2、结构 1-3、代码实现 1-4、适…

Kubectl常用命令

管理资源&#xff08;查看、创建、更新、删除&#xff09; 查看node资源 kubectl get nodes查看命名空间 kubectl get ns查看service资源 -n 指明所属的命名空间&#xff0c;不写默认看命名空间为default下的所有service kubectl get svc -n default查看pod资源 -n 指明所…