使用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));}@Overridepublic 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();}}}@Overridepublic 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("没有配置工作文件夹,检查配置文件!");}}@Overridepublic List<File> upload(List<File> files) {List<File>failList = this.uploadHelper(files);this.commit();this.push();return failList;}@Overridepublic 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.mzph.cn/news/752014.shtml

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

相关文章

R语言:microeco:一个用于微生物群落生态学数据挖掘的R包,第四:trans_beta class

trans_beta class&#xff1a;利用trans_beta类可以变换和绘制beta分集的距离矩阵。该类中涉及到beta多样性的分析主要包括排序、群距、聚类和方差分析。我们首先使用PCoA显示排序。 > dataset$cal_betadiv() The result is stored in object$beta_diversity ... > t1 &…

ClickHouse中的设置的分类

ClickHouse中的各种设置 ClickHouse中的设置有几百个&#xff0c;下面对这些设置做了一个简单的分类。

游戏引擎中网络游戏的基础

一、前言 网络游戏所面临的挑战&#xff1a; 一致性&#xff1a;如何在所有的主机内都保持一样的表现可靠性&#xff1a;网络传输有可能出现丢包安全性&#xff1a;反作弊&#xff0c;反信息泄漏。多样性&#xff1a;不同设备之间链接&#xff0c;比如手机&#xff0c;ipad&a…

C到C++的敲门砖-2

文章目录 引用内联函数auto关键字基于范围的for循环指针空值nullptr后记 引用 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空 间&#xff0c;它和它引用的变量共用同一块内存空间。 所谓引用就是给变量起别名&am…

RUST egui体验

egui官方提供了web版的demo&#xff0c;效果还是很不错的&#xff0c;就是用的时候有点一头雾水&#xff0c;没有找到明确的指导怎么把这些组件插入到自己的application或者web。花了一天时间撸了一遍流程&#xff0c;记录一下&#xff0c;说不定以后能用到呢 >_< efram…

asp.net 作业星软件系统

asp.net 作业星软件系统 用户功能:分教师和家长&#xff08;学生) 注册登录:登录部分是用户名密码&#xff0c;以及教师和家长&#xff08;学生&#xff09;的勾选; 注册包括用户名密码确认密码再次确认密码(与上方输入的密码比对&#xff09;身份班级设置找回账号的问题和答案…

【人工智能】英文学习材料01(每日一句)

&#x1f33b;个人主页&#xff1a;相洋同学 &#x1f947;学习在于行动、总结和坚持&#xff0c;共勉&#xff01; 目录 1.Natural Language Processing&#xff0c;NLP&#xff08;自然语言处理&#xff09; 2.Machine Learing&#xff0c;ML&#xff08;机器学习&#xf…

FFplay使用滤镜添加字幕到现有视频显示

1.创建字幕文件4k.srt 4k.srt内容: 1 00:00:01.000 --> 00:00:30.000 日照香炉生紫烟2 00:00:31.000 --> 00:00:60.000 遥看瀑布挂前川3 00:01:01.000 --> 00:01:30.000 飞流直下三千尺4 00:01:31.000 --> 00:02:00.000 疑是银河落九天2.通过使用滤镜显示字幕在视…

【GPT-SOVITS-03】SOVITS 模块-生成模型解析

说明&#xff1a;该系列文章从本人知乎账号迁入&#xff0c;主要原因是知乎图片附件过于模糊。 知乎专栏地址&#xff1a; 语音生成专栏 系列文章地址&#xff1a; 【GPT-SOVITS-01】源码梳理 【GPT-SOVITS-02】GPT模块解析 【GPT-SOVITS-03】SOVITS 模块-生成模型解析 【G…

llama笔记:官方示例解析 example_chat_completion.py

1 导入库 from typing import List, Optional从typing模块中导入List和Optional。typing模块用于提供类型注解的支持&#xff0c;以帮助明确函数预期接收和返回的数据类型。List用于指定列表类型Optional用于指定一个变量可能是某个类型&#xff0c;也可能是None。 import fir…

Linux 下使用 socket 实现 TCP 客户端

目录 示例代码板级验证更多内容 套接字&#xff08;socket&#xff09;是 Linux 下的一种进程间通信机制&#xff08;socket IPC&#xff09;&#xff0c;它不仅支持同一主机的不同进程间通信&#xff0c;还支持跨网络的不同主机的进程间通信。 socket 允许通过标准的文件描述…

十四、GPT

在GPT-1之前&#xff0c;传统的 NLP 模型往往使用大量的数据对有监督的模型进行任务相关的模型训练&#xff0c;但是这种有监督学习的任务存在两个缺点&#xff1a;预训练语言模型之GPT 需要大量的标注数据&#xff0c;高质量的标注数据往往很难获得&#xff0c;因为在很多任务…

Android学习使用GitLab(保姆级)

实习生入职第一课 学习使用GitLab&#xff0c;熟悉Git版本控制工具 下面是我的学习笔记&#xff0c;希望能帮助到需要的人&#xff01; 目录 一、注册你的GitLab账号 二、安装Git 三、在Android studio中配置Git 四、GitLab账户配置SSH Keys 五、GitLab账号创建项目 六…

深度学习-基于机器学习的垃圾邮件过滤系统

概要 当今社会发展迅速&#xff0c;网络邮件也愈加普及。但是随之产生的垃圾邮件问题&#xff0c;也是的我们的邮件用户不堪其扰。对企业的工作以及个人用户的生活也造成了很大的影响。针对一些由于垃圾邮件导致的网络吞吐量异常和邮件系统无法正常使用的情况。建立一个机器学习…

html5黑色大气的个人博客全屏滚动个人主页源码HTML+JS+CSS

html5黑色大气的个人博客全屏滚动个人主页源码HTMLJSCSS

基于背景差法的运动目标检测(车辆检测),Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

【计算机视觉】二、图像形成——实验:2D变换编辑器2.0(Pygame)

文章目录 一、向量和矩阵的基本运算二、几何基元和变换1、几何基元(Geometric Primitives)2、几何变换(Geometric Transformations)2D变换编辑器0. 项目结构1. Package: guibutton.pywindow.py1. __init__(self, width, height, title)2. add_buttons(self)3. clear(self)4. dr…

Docker 安装 Skywalking以及UI界面

关于Skywalking 在现代分布式系统架构中&#xff0c;应用性能监控&#xff08;Application Performance Monitoring, APM&#xff09;扮演着至关重要的角色。本文将聚焦于一款备受瞩目的开源APM工具——Apache Skywalking&#xff0c;通过对其功能特性和工作原理的详细介绍&am…

【C++ leetcode 】双指针问题

1. 183. 移动零 题目 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 题目链接 . - 力扣&#xff08;LeetCode&#xff09; 画图 和 文字 分…

基于深度学习LSTM+NLP情感分析电影数据爬虫可视化分析推荐系统(深度学习LSTM+机器学习双推荐算法+scrapy爬虫+NLP情感分析+数据分析可视化)

文章目录 基于深度学习LSTMNLP情感分析电影数据爬虫可视化分析推荐系统&#xff08;深度学习LSTM机器学习双推荐算法scrapy爬虫NLP情感分析数据分析可视化&#xff09;项目概述深度学习长短时记忆网络&#xff08;Long Short-Term Memory&#xff0c;LSTM&#xff09;机器学习协…