我的Hexo自动Webhook部署方案

news2025/7/19 7:09:16

前言

最近我也是重新开始管理我的博客网站了,之前大概有了半年的时间没有写文章了。也是经过这半年的学习,我了解的知识更多,更广了。
当我开始写 Hexo 博客的时候,首先我得把 Markdown 文件内容拷贝到服务器上,然后写文章属性(front-matter)。

---
title: HTML笔记
date: 2025-04-09 09:27:32
categories:
    - HTML
tags:
  - HTML
cover: https://lsky.happyladysauce.cn/i/1/0.webp
ai: true
---

最后 hexo 三板斧,清理、编译、运行。

hexo clean && hexo g && hexo s

这是不是有些太麻烦了?可能一两个 Markdown 文件还好说,但经过半年的学习沉淀,我的笔记文件还是有那么十多个的。我需要一个可以批量部署文章的解决方案,但是网上 Hexo 博客自动部署方案基本都是清一色的 Github Action ,还有少数是使用的 Github Webhook
我的博客自动部署方案使用 Github Webhook

为什么不使用 Github Action

物理原因

这算是一次尝试吧,Github Action 不可否认的是确实好用,但是我的博客没有放到 Github 上,所以我是使用腾讯云的云服务器部署的 Hexo。这就导致我用不了 Github Action ,但是我可以使用 Github Webhook 来完成自动化触发工作。

功能原因

网上的 Github ActionGithub Webhook 自动部署方案基本都只实现自动部署功能就完了,但是我还想要自动拷贝 Markdown 文件到服务器上去并添加文章属性(fornt-matter,这些功能是目前网上的项目没有的。虽然这些功能理论上 Github Action 也可以实现,但是我发现没有人去做。

Github Webhook 是什么

GitHub Webhook 是一种强大的工具,允许你在 GitHub 仓库发生特定事件时(pushpullissues 等),自动触发外部应用程序或服务的操作。它通过 HTTP POST 请求将事件数据发送到指定的 URL,从而实现自动化工作流和集成。GitHub Webhook 是一个非常灵活的工具,能够帮助你构建高效的自动化工作流。


我的 Hexo 自动部署方案

我的这一套 Hexo 自动部署方案,其实相对 Github Action 来说比较复杂。但是搭建完成后的用户体验一定是比 Github Action 要好的。
如果说 Github Action 是可以让用户更加注重于 Markdown 的编写,那么我的 Hexo-Autocd 项目方案就是让用户只注重于 Markdown 的编写,甚至不需要手动推送。

可以想象一下:你正 Windows 上的图形化编辑器中写 Markdown 笔记,当你写完的时候打开你的网站发现你的博客上已经有了你才写完的 Markdown 笔记文章,并且做好了分类和标签,简直是太爽了!

简单来说我的 Hexo-Autocd 相比 Github Action 增加了这些功能:

  • 不需要拷贝 Markdown 文件到服务器中
  • 不需要写文章属性(front-matter
  • 不需要手动 github 推送(也可以手动推送)
  • 实时文章更新(这是可以做到的,但是一般设置2-3分钟的延迟)
  • 并且整个自动化部署项目通过 systemd 支持开机自启(Linux服务器)包括 Hexo 也是开机自启。不用担心项目的稳定性问题,我自己使用这一套自动化部署方案测试了很久。
    通过这些功能的集成,我们可以做到本地 Windows 图形化管理博客文章,而完全不需要考虑部署到服务器上的事情。

Markdown 仓库

首先 Hexo-Autocd 使用一个 Github 仓库单独来存放 Markdown 笔记相关的内容。并且这个 Github 仓库中存放笔记的方式有特殊要求:Hexo-Autocd 的部署脚本会根据目录名对笔记进行自动分类,并根据笔记命名第一个 _ 之后的内容进行标签分割,多个标签之间使用 _ 分割。

Markdown仓库

Github Webhook

Markdown 仓库建好了以后,我们还需要开启仓库的 Webhooks 功能。Payload URL 填你自己服务器的主机地址或者域名,端口号和路径可以直接使用 Hexo-Autocd 项目默认的 8080/webhook 也可是其他的,当然这得去修改 Hexo-Autocd 的配置文件。 Hexo-Autocd 支持 SSL verification ,但是你得上传自己的域名证书,并在 Hexo-Autocd 中配置使用。

Github_Webhooks

# Hexo-Autocd 配置文件
webhook:
    port: 8080
    path: /webhook
    secret: your_secret
logs:
    path: /etc/hexo-autocd/logs/webhooks.log
    level: trace # 日志级别,可选值:trace、debug、info、warn、error、fatal、panic
    format: text # 日志格式,可选值:json、text
    max_size: 100 # 日志文件最大大小(MB)
    max_backups: 5 # 日志文件最大备份数
    max_age: 30 # 日志文件最大保存时间(天)
scripts:
    path: /etc/hexo-autocd/scripts
    push: deploy.sh
    timeout: 5m # 脚本执行超时时间
    max_concurrent: 5 # 最大并发执行数
ssl:
    enabled: true
    cert_file: /etc/hexo-autocd/cert/fullchain.pem
    key_file: /etc/hexo-autocd/cert/privkey.pem

Hexo Systemd

Systemd 是一个系统和服务管理器,它在Linux操作系统中用于初始化系统和管理系统服务。它在系统启动时运行,负责启动和管理各种系统服务、守护进程、设备驱动程序等。
Hexo-AutcdHexo 都使用 Systemd 进行管理。
HexoSystemd 配置,放在 /etc/systemd/system/hexo.service 中。

sudo vim /etc/systemd/system/hexo.service
[Unit]
Description=Hexo Blog Server
After=network.target

[Service]
Type=simple
User=root
# 修改为你的 hexo 目录
WorkingDirectory=/path/to/hexo
ExecStart=/usr/bin/hexo serve
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

添加完 HexoSystemd 之后需要重载一下 Systemd 的配置。

sudo systemctl daemon-reload

Hexo 通过 Systemd 集成我们可以做到:

  • 启动 hexo 服务:systemctl start hexo

  • 停止 hexo 服务:systemctl stop hexo

  • 重启 hexo 服务:systemctl restart hexo

  • 查询 hexo 状态:systemctl status hexo

  • 开机自启 hexo:systemctl enable hexo

Hexo-Autocd(必看)

Hexo-Autocd 项目由两个核心组成,一个是由 golang 编写的 Webhook 服务器,用于监听 Github Webhook 。另一个是文章部署脚本,脚本使用 shell 语言编写,这是自动部署文章的核心逻辑,如果你有自定义的部署需求都可以在里面进行修改,不用去学习其他的 golang 文件。

Markdown 仓库和 Github Webhook 都配置完成后,我们登录自己的服务器。并通过项目中的安装步骤安装 Hexo-Autocd。这里说一下服务器上需要有 golang 环境但是其实不需要也是可以的,但是我懒,要是不想安装 golang 环境 的话根据 Makefile 文件中的安装方式拷贝文件到相应的目录下就可以了,Hexo-Autocd 的二进制程序在仓库中已经编译好的,可以直接使用。
HappyLadySauce/Hexo-Webhooks-AutoCD: 这是一个全自动部署Hexo文章的项目,采用Github Webhook当GitHub仓库收到push事件时,会自动触发博客的更新和部署。

Hexo-Autocd 的工作逻辑

Hexo-Autocd 的主体是使用 golang 编写的一个 Webhook 服务器,用于监听 Github Webhook 的推送(push)请求,然后会提取 Github Webhook 的这些消息内容。

logger.WithFields(logrus.Fields{
	"提交ID":  shortCommitID,
	"提交信息":  pushEvent.HeadCommit.Message,
	"提交时间":  pushEvent.HeadCommit.Timestamp,
	"新增文件数": len(pushEvent.HeadCommit.Added),
	"修改文件数": len(pushEvent.HeadCommit.Modified),
	"删除文件数": len(pushEvent.HeadCommit.Removed),
}).Info("收到Git推送事件")

的到这些信息之后,Hexo-Autocd 会去调用 deploy.sh 部署脚本,并将 git 信息作为环境变量传递给 deploy.sh ,最后 Hexo-Autocd 接受 deploy.sh 的日志输出结束这次推送(push)工作流,并继续监听 Github Webhook

deploy.sh 自定义部署部署脚本
自动部署主逻辑

deploy.sh 会使用 Markdown 文章仓库Hexo 博客,确保在你的服务器上存在这两个目录。

root@www:/home/hexo# ls
blog markdown

脚本首先会进入 Markdown 仓库目录,执行 pull 操作,获取最新的文章目录。然后根据 Github Webhook 的消息内容,在 Hexo 的 source/_posts 文章目录下进行增加删除修改操作,并且自动添加文章属性(fornt-matter

自动添加文章属性(fornt-matter 的逻辑如下,根据当前主机(Linux服务器)时间确定 date,根据笔记文件在哪个目录下确定 categories,并根据笔记文件名第一个 _ 之前的内容确定 title,第一个 _ 之后的内容确定 tags,使用随机的图片链接确定文章封面,最后加上 ai: true 这是 TianliGPT 插件的内容。

完成之后自动 hexo clean && hexo g && systemctl start hexo && hexo d 完成文章的部署。

额外脚本操作

脚本做一些忽略文件操作,使用 .gitignore 作为注释文件,在 .gitignore 里的文件不做处理,并且只处理以 .md 结尾的文件,防止其他文件被处理为文章。

由于使用 hexo clean 所以 public 里的文件都会被清空,为了保证百度认证文件一直存在,脚本会把 blog 根目录下的百度认证文件重新拷贝到 public 中。当然也可以是其他的文件操作,这都是可以高度自定义的。

#!/bin/bash

#======================================================
# 配置部分 - 可根据需要调整下面的配置项
#======================================================

#---------- 工作目录设置 ----------#
# 博客主目录
BLOG_DIR="/home/hexo/blog"
# Markdown文章源文件目录
POSTS_DIR="/home/hexo/markdown"
# 博客文章目标目录
BLOG_POSTS_DIR="$BLOG_DIR/source/_posts"

#---------- Git配置 ----------#
# Git用户名
GIT_USER_NAME="HappyLadySauce"
# Git邮箱
GIT_USER_EMAIL="13452552349@163.com"

#---------- 忽略文件设置 ----------#
# 使用.gitignore作为注释文件
IGNORED_FILE="$POSTS_DIR/.gitignore"

#---------- 随机封面设置 ----------#
# 封面图片基础URL
COVER_BASE_URL="https://lsky.happyladysauce.cn/i/1/"
# 封面图片最大随机索引(0-9)
COVER_MAX_INDEX=9

#---------- 服务控制设置 ----------#
# Hexo服务名称
HEXO_SERVICE_NAME="hexo"
# 服务启动/停止超时时间(秒)
SERVICE_TIMEOUT=10
# 服务停止后的等待时间(秒)
SERVICE_WAIT_TIME=3

#---------- 百度SEO文件 ----------#
# 百度验证文件
BAIDU_VERIFY_FILE="baidu_verify_codeva-Xj2KiKq7pj.html"

#======================================================
# 函数定义
#======================================================

# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

# 配置Git的函数
setup_git() {
    log "配置Git环境..."
    # 配置Git安全目录
    git config --global --add safe.directory "$POSTS_DIR"
    # 配置Git用户信息
    git config --global user.name "$GIT_USER_NAME"
    git config --global user.email "$GIT_USER_EMAIL"
}

# 停止hexo进程的函数
stop_hexo() {
    log "正在停止hexo服务..."
    if systemctl is-active $HEXO_SERVICE_NAME >/dev/null 2>&1; then
        if ! sudo systemctl stop $HEXO_SERVICE_NAME; then
            log "警告:停止hexo服务失败"
            return 1
        fi
        # 等待服务完全停止
        local count=0
        while systemctl is-active $HEXO_SERVICE_NAME >/dev/null 2>&1; do
            sleep 1
            count=$((count + 1))
            if [ $count -ge $SERVICE_TIMEOUT ]; then
                log "错误:hexo服务停止超时"
                return 1
            fi
        done
        log "hexo服务已停止"
    else
        log "hexo服务未运行"
    fi
    # 等待指定秒数
    sleep $SERVICE_WAIT_TIME
    return 0
}

# 启动hexo服务的函数
start_hexo() {
    log "正在启动hexo服务..."
    if ! sudo systemctl start $HEXO_SERVICE_NAME; then
        log "错误:启动hexo服务失败"
        return 1
    fi
    
    # 等待服务启动并检查状态
    local count=0
    while ! systemctl is-active $HEXO_SERVICE_NAME >/dev/null 2>&1; do
        sleep 1
        count=$((count + 1))
        if [ $count -ge $SERVICE_TIMEOUT ]; then
            log "错误:hexo服务启动超时"
            return 1
        fi
    done
    
    log "hexo服务已成功启动"
    return 0
}

# 检查路径是否被注释的函数
is_path_ignored() {
    local check_path="$1"
    
    # 使用git check-ignore命令检查路径是否被忽略
    if git -C "$POSTS_DIR" check-ignore -q "$check_path"; then
        return 0  # 路径被忽略
    fi
    
    # 遍历.gitignore中的每一行进行手动检查(备用方法)
    while IFS= read -r pattern; do
        # 跳过空行和注释行
        [[ -z "$pattern" || "$pattern" == \#* ]] && continue
        
        # 检查是否是通配符模式
        if [[ "$pattern" == *"*"* ]]; then
            # 将gitignore通配符转换为bash通配符
            local bash_pattern=$(echo "$pattern" | sed 's|/\*$|/*|g')
            
            # 检查路径是否匹配通配符
            if [[ "$check_path" == $bash_pattern ]]; then
                return 0  # 路径被忽略
            fi
        # 检查是否是目录模式
        elif [[ "$pattern" == */ ]]; then
            local dir_pattern="${pattern%/}"
            if [[ "$check_path" == "$dir_pattern"* ]]; then
                return 0  # 路径被忽略
            fi
        # 检查是否是普通模式
        elif [[ "$check_path" == "$pattern" || "$check_path" == *"/$pattern" ]]; then
            return 0  # 路径被忽略
        fi
    done < "$IGNORED_FILE"
    
    return 1  # 路径未被忽略
}

# 检查文件是否应该被忽略(基于文件路径和内容类型)
should_ignore_file() {
    local file_path="$1"
    local rel_path="${file_path#$POSTS_DIR/}"
    
    # 检查文件本身是否被忽略
    if is_path_ignored "$rel_path"; then
        return 0  # 文件被忽略
    fi
    
    # 检查文件所在目录是否被忽略
    local dir_path=$(dirname "$rel_path")
    if [ "$dir_path" != "." ] && is_path_ignored "$dir_path"; then
        return 0  # 文件所在目录被忽略
    fi
    
    # 检查文件扩展名是否被忽略
    local ext="${rel_path##*.}"
    if is_path_ignored "*.$ext"; then
        return 0  # 文件扩展名被忽略
    fi
    
    return 1  # 文件未被忽略
}

# 处理单个文件的函数
process_file() {
    local src_file="$1"
    local rel_path="${src_file#$POSTS_DIR/}"  # 获取相对路径
    local dir_path=$(dirname "$rel_path")
    
    # 检查文件是否为Markdown文件
    if [[ "$src_file" != *.md ]]; then
        log "跳过非Markdown文件: $rel_path"
        return 0
    fi
    
    # 检查文件是否在根目录(非子目录中)
    if [ "$dir_path" = "." ]; then
        log "跳过根目录文件: $(basename "$src_file")"
        return 0
    fi
    
    # 检查文件是否应该被忽略
    if should_ignore_file "$src_file"; then
        log "跳过被忽略的文件: $rel_path"
        return 0
    fi
    
    local filename=$(basename "$src_file")
    local dest_file="$BLOG_POSTS_DIR/$(basename "$src_file")"
    
    # 获取分类(目录路径)
    local categories=""
    if [ "$dir_path" != "." ]; then
        categories=$(echo "$dir_path" | tr '/' '\n' | sed 's/^/    - /')
    fi
    
    # 获取标签(从文件名中提取)
    local tags=""
    if [[ "$filename" == *"_"* ]]; then
        # 提取_后面的部分(不包括.md)
        local tag_part="${filename#*_}"
        tag_part="${tag_part%.md}"
        # 将_分隔的标签转换为yaml格式
        tags=$(echo "$tag_part" | tr '_' '\n' | sed 's/^/- /')
    fi
    
    # 生成随机封面URL
    cover_url="$COVER_BASE_URL$(($RANDOM % $COVER_MAX_INDEX)).webp"

    # 创建临时文件
    local temp_file=$(mktemp)
    
    # 先写入新的front-matter
    {
        echo "---"
        echo "title: ${filename%%_*}"  # 使用_之前的部分作为标题
        echo "date: $(date '+%Y-%m-%d %H:%M:%S')"
        echo "categories:"
        if [ -n "$categories" ]; then
            echo "$categories"
        fi
        echo "tags:"
        if [ -n "$tags" ]; then
            # 确保tags缩进正确
            echo "$tags" | sed 's/^-/  -/'
        fi
        echo "cover: $cover_url"
        echo "ai: true"
        echo "---"
        echo ""  # 添加空行
    } > "$temp_file"
    
    # 检查文件是否已存在front-matter,如果存在则跳过它
    if head -n 1 "$src_file" | grep -q "^---$"; then
        # 找到第二个 "---" 的行号
        local end_line=$(awk '/^---$/ {count++; if (count==2) {print NR; exit}}' "$src_file")
        if [ -n "$end_line" ]; then
            # 只添加front-matter之后的内容
            tail -n +$((end_line + 1)) "$src_file" >> "$temp_file"
        else
            # 如果没找到第二个 "---",添加整个文件内容
            cat "$src_file" >> "$temp_file"
        fi
    else
        # 如果不存在front-matter,直接添加文件内容
        cat "$src_file" >> "$temp_file"
    fi
    
    # 移动临时文件到目标位置
    mv "$temp_file" "$src_file"
    cp "$src_file" "$dest_file"
    
    log "处理文件: $filename (目录: $dir_path)"
}

# 注释/取消注释路径函数
toggle_path_ignore() {
    local path="$1"
    local action="$2"  # "add" 或 "remove"
    
    if [ "$action" = "add" ]; then
        # 检查路径是否已经在.gitignore中
        if grep -q "^$path$" "$IGNORED_FILE"; then
            log "路径 '$path' 已经在忽略列表中"
        else
            echo "$path" >> "$IGNORED_FILE"
            log "路径 '$path' 已添加到忽略列表"
        fi
    elif [ "$action" = "remove" ]; then
        # 从.gitignore中移除路径
        sed -i "/^$path$/d" "$IGNORED_FILE"
        log "路径 '$path' 已从忽略列表中移除"
    fi
    
    return 0
}

#======================================================
# 主执行流程
#======================================================

# 创建.gitignore文件(如果不存在)
if [ ! -f "$IGNORED_FILE" ]; then
    touch "$IGNORED_FILE"
fi

# 输出提交信息
log "收到新的提交:"
log "提交ID: $COMMIT_ID"
log "提交信息: $COMMIT_MESSAGE"
log "提交时间: $COMMIT_TIMESTAMP"
log "新增文件: $COMMIT_ADDED"
log "删除文件: $COMMIT_REMOVED"
log "修改文件: $COMMIT_MODIFIED"

# 检查提交信息是否包含注释/取消注释命令
if [[ "$COMMIT_MESSAGE" == *"[ignore:"* ]]; then
    path_to_ignore=$(echo "$COMMIT_MESSAGE" | grep -o '\[ignore:[^]]*\]' | sed 's/\[ignore://;s/\]//')
    if [ -n "$path_to_ignore" ]; then
        toggle_path_ignore "$path_to_ignore" "add"
    fi
fi

if [[ "$COMMIT_MESSAGE" == *"[unignore:"* ]]; then
    path_to_unignore=$(echo "$COMMIT_MESSAGE" | grep -o '\[unignore:[^]]*\]' | sed 's/\[unignore://;s/\]//')
    if [ -n "$path_to_unignore" ]; then
        toggle_path_ignore "$path_to_unignore" "remove"
    fi
fi

# 更新文章仓库
cd "$POSTS_DIR" || exit 1
log "拉取最新文章..."

# 配置Git环境
setup_git

# 重置所有本地更改
git reset --hard HEAD
git clean -fd  # 删除未跟踪的文件和目录

# 拉取最新更改
git pull origin main

# 检查是否有错误
if [ $? -ne 0 ]; then
    log "错误:拉取文章失败"
    exit 1
fi

# 处理新增和修改的文件
IFS=',' read -ra ADDED_FILES <<< "$COMMIT_ADDED"
IFS=',' read -ra MODIFIED_FILES <<< "$COMMIT_MODIFIED"

for file in "${ADDED_FILES[@]}" "${MODIFIED_FILES[@]}"; do
    if [ -n "$file" ] && [ -f "$POSTS_DIR/$file" ]; then
        process_file "$POSTS_DIR/$file"
    fi
done

# 处理删除的文件
IFS=',' read -ra REMOVED_FILES <<< "$COMMIT_REMOVED"
for file in "${REMOVED_FILES[@]}"; do
    if [ -n "$file" ]; then
        # 检查文件是否为Markdown文件
        if [[ "$file" != *.md ]]; then
            log "跳过删除非Markdown文件: $file"
            continue
        fi
        
        # 检查文件是否在子目录中
        dir_path=$(dirname "$file")
        if [ "$dir_path" = "." ]; then
            log "跳过删除根目录文件: $(basename "$file")"
            continue
        fi
        
        # 检查文件是否应该被忽略
        if should_ignore_file "$POSTS_DIR/$file"; then
            log "跳过删除被忽略的文件: $file"
            continue
        fi
        
        rm -f "$BLOG_POSTS_DIR/$(basename "$file")"
        log "删除文件: $(basename "$file")"
    fi
done

# 更新博客
cd "$BLOG_DIR" || exit 1
log "开始部署博客..."

sleep 1

# 停止hexo服务
if ! stop_hexo; then
    log "警告:继续部署,但hexo服务可能未完全停止"
fi

# 清理缓存
log "清理 Hexo 缓存..."
hexo clean

# 生成静态文件
log "生成静态文件..."
hexo generate

# 拷贝百度SEO文件
cp "$BLOG_DIR/$BAIDU_VERIFY_FILE" "$BLOG_DIR/public"

# 检查生成是否成功
if [ $? -ne 0 ]; then
    log "错误:生成静态文件失败"
    exit 1
fi

# 启动hexo服务
if ! start_hexo; then
    log "错误:部署完成但服务启动失败"
    exit 1
fi

# 部署hexo
hexo d

log "部署完成!"
exit 0
Hexo-Autocd 使用总结

首先保证 Markdown 文章仓库和 Hexo 应用目录在你的服务器上,通过 Hexo-Autocd 项目中的安装方法安装 Hexo-Autocd 并且确保 Hexo 已经使用 Systemd 集成。使用 Systemd 启动 HexoHexo-Autocd

sudo systemctl enable hexo --now
sudo systemctl enable hexo-autocd --now

然后编辑 /etc/hexo-autocd/config.yaml 确保 webhook 参数与 Markdown 文章仓库的 Github Webhook 参数一致,根据自己的需要选择开启 ssl

webhook:
    port: 8080
    path: /webhook
    secret: happyladysauce
logs:
    path: /etc/hexo-autocd/logs/webhooks.log
    level: trace # 日志级别,可选值:trace、debug、info、warn、error、fatal、panic
    format: text # 日志格式,可选值:json、text
    max_size: 100 # 日志文件最大大小(MB)
    max_backups: 5 # 日志文件最大备份数
    max_age: 30 # 日志文件最大保存时间(天)
scripts:
    path: /etc/hexo-autocd/scripts
    push: deploy.sh
    timeout: 5m # 脚本执行超时时间
    max_concurrent: 5 # 最大并发执行数
ssl:
    enabled: true
    cert_file: /etc/hexo-autocd/cert/fullchain.pem
    key_file: /etc/hexo-autocd/cert/privkey.pem

重启 Hexo-Autocd 然后整个项目就算部署完毕了,开始你的自动部署体验吧!

sudo systemctk restart hexo-autocd

Obsidian 黑曜石

为了完成在 Windows 上更加丝滑的 Git Push 操作,可以使用 Obsidian 作为 Markdown 笔记工具,通过 ObsidianGit 插件,可以让我们在编写 Markdown 的时候同步自动提交更新到 Github 仓库,进一步地减少我们的心智负担。

并且 Obsidian 拥有强大的插件系统,我还在使用他的 Excalidraw 手绘风格画图插件,使用起来非常的 Nice,我也是才接触 Obsidian 他还有更多的强大功能,等着我们去发现。

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

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

相关文章

智慧医院室内导航系统架构拆解:技术选型与性能攻坚指南

本文面向医院信息化团队技术负责人及医疗IoT解决方案开发者&#xff0c;聚焦解决大规模院区导航系统的扩展性、多源数据融合及实时路径规划等技术难点&#xff0c;提供从架构到落地的完整技术路线图。 如需获取智慧医院导航导诊系统解决方案请前往文章最下方获取&#xff0c;如…

Docker:安装与部署 Nacos 的技术指南

1、简述 Nacos(Dynamic Naming and Configuration Service)是阿里巴巴开源的一个动态服务发现、配置管理和服务治理的综合解决方案,适用于微服务架构。 Nacos 主要功能: 服务发现与注册:支持 Dubbo、Spring Cloud 等主流微服务框架的服务发现与注册。动态配置管理:支持…

tailwindcss 4 使用的一些注意点

目录 一、tailwindcss 4 官网地址变更了 二、自定义颜色的使用方式 三、安装的时候可能的报错 一、tailwindcss 4 官网地址变更了 之前的官网地址是&#xff1a;Tailwind CSS 中文网 现在的官网地址是&#xff1a;Tailwind CSS - Rapidly build modern websites without e…

stm32工程,拷贝到另一台电脑编译,错误提示头文件找不到cannot open source input file “core_cm4.h”

提示 cannot open source input file “core_cm4.h” ,找不到 [ core_cm4.h ] 这个头文件 . 于是我在原电脑工程文件里找也没有找到这个头文件 接下来查看原电脑keil的头文件引入配置,发现只引入了工程文件下的头文件, 那么core_cm4.h到底哪里来的? (到现在我也不清楚怎…

无锡东亭无人机培训机构电话

无锡东亭无人机培训机构电话&#xff0c;随着科技的迅猛发展&#xff0c;无人机逐渐走入我们的生活和工作领域&#xff0c;成为多种行业中不可或缺的工具。而在其广泛的应用中&#xff0c;如何正确、熟练地操控无人机成为了关键。因此&#xff0c;找到一家专业的无人机培训机构…

大厂文章阅读

1.异步任务处理系统&#xff0c;如何解决业务长耗时、高并发难题&#xff1f; 1)任务失败如何处理(CAS失败也可用)&#xff1a;1.指数退避,匹配下游任务执行系统的处理能力。比如收到下游任务执行系统的流控错误&#xff0c;或者感知到任务执行成为瓶颈&#xff0c;需要指数退…

卷积神经网络 CNN 系列总结(二)---数据预处理、激活函数、梯度、损失函数、优化方法等

数据预处理 零中心化、归一化 关于数据预处理我们有3个常用的符号,数据矩阵X,假设其尺寸是[N x D](N是数据样本的数量,D是数据的维度)。 均值减法(Mean subtraction)是预处理最常用的形式。它对数据中每个独立特征减去平均值,从几何上可以理解为在每个维度上都将数据…

速学Android 16新功能:带有进度的通知类型

前言 在当前已公布的Android 16版本中新增了一系列的功能特性和API&#xff0c;如&#xff1a; 动态壁纸的内容处理&#xff0c;提供新的 content API 预测性返回更新&#xff0c;添加了finishAndRemoveTaskCallback() 和 moveTaskToBackCallback等API 健康数据共享更新&…

微信小程序开发:微信小程序上线发布与后续维护

微信小程序上线发布与后续维护研究 摘要 微信小程序作为移动互联网的重要组成部分,其上线发布与后续维护是确保其稳定运行和持续优化的关键环节。本文从研究学者的角度出发,详细探讨了微信小程序的上线发布流程、后续维护策略以及数据分析与用户反馈处理的方法。通过结合实…

深度学习基础--CNN经典网络之分组卷积与ResNext网络实验探究(pytorch复现)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 ResNext是分组卷积的开始之作&#xff0c;这里本文将学习ResNext网络&#xff1b;本文复现了ResNext50神经网络&#xff0c;并用其进行了猴痘病分类实验…

面向对象的需求分析与UML构造块详解

目录 前言1 面向对象的需求分析概述2 UML构造块概述3 UML事物详解3.1 结构事物&#xff08;Structural Things&#xff09;3.2 行为事物&#xff08;Behavioral Things&#xff09;3.3 分组事物&#xff08;Grouping Things&#xff09;3.4 解释事物&#xff08;Annotational T…

计算机视觉色彩空间全解析:RGB、HSV与Lab的实战对比

计算机视觉色彩空间全解析&#xff1a;RGB、HSV与Lab的实战对比 一、前言二、RGB 色彩空间​2.1 RGB 色彩空间原理​2.1.1 基本概念​2.1.2 颜色混合机制​ 2.2 RGB 在计算机视觉中的应用​2.2.1 图像读取与显示​2.2.2 颜色识别​2.2.3 RGB 色彩空间的局限性​ 三、HSV 色彩空…

使用Docker安装Gogs

1、拉取镜像 docker pull gogs/gogs 2、运行容器 # 创建/var/gogs目录 mkdir -p /var/gogs# 运行容器 # -d&#xff0c;后台运行 # -p&#xff0c;端口映射&#xff1a;(宿主机端口:容器端口)->(10022:22)和(10880:3000) # -v&#xff0c;数据卷映射&#xff1a;(宿主机目…

【Web API系列】XMLHttpRequest API和Fetch API深入理解与应用指南

前言 在现代Web开发中&#xff0c;客户端与服务器之间的异步通信是构建动态应用的核心能力。无论是传统的AJAX技术&#xff08;基于XMLHttpRequest&#xff09;还是现代的Fetch API&#xff0c;它们都为实现这一目标提供了关键支持。本文将从底层原理、核心功能、代码实践到实…

ESP32开发入门:基于VSCode+PlatformIO环境搭建指南

前言 ESP32作为一款功能强大的物联网开发芯片&#xff0c;结合PlatformIO这一现代化嵌入式开发平台&#xff0c;可以大幅提升开发效率。本文将详细介绍如何在VSCode中搭建ESP32开发环境&#xff0c;并分享实用开发技巧。 一、环境安装&#xff08;Windows/macOS/Linux&#xf…

2025.4.13机器学习笔记:文献阅读

2025.4.13周报 题目信息摘要创新点网络架构实验结论不足以及展望 题目信息 题目&#xff1a; Physics-informed neural networks for inversion of river flow and geometry with shallow water model期刊&#xff1a; Physics of Fluids作者&#xff1a; Y. Ohara; D. Moteki…

编程助手fitten code使用说明(超详细)(vscode)

这两年 AI 发展迅猛&#xff0c;作为开发人员&#xff0c;我们总是追求更快、更高效的工作方式&#xff0c;AI 的出现可以说改变了很多人的编程方式。 AI 对我们来说就是一个可靠的编程助手&#xff0c;给我们提供了实时的建议和解决方&#xff0c;无论是快速修复错误、提升代…

Python自动化爬虫:Scrapy+APScheduler定时任务

在数据采集领域&#xff0c;定时爬取网页数据是一项常见需求。例如&#xff0c;新闻网站每日更新、电商价格监控、社交媒体舆情分析等场景&#xff0c;都需要定时执行爬虫任务。Python的Scrapy框架是强大的爬虫工具&#xff0c;而APScheduler则提供了灵活的任务调度功能。 一、…

技术分享|iTOP-RK3588开发板Ubuntu20系统旋转屏幕方案

iTOP-3588开发板采用瑞芯微RK3588处理器&#xff0c;是全新一代AloT高端应用芯片&#xff0c;采用8nmLP制程&#xff0c;搭载八核64位CPU&#xff0c;四核Cortex-A76和四核Cortex-A55架构&#xff0c;主频高达2.4GHz。是一款可用于互联网设备和其它数字多媒体的高性能产品。 在…

3.3.1 spdlog异步日志

文章目录 3.3.1 spdlog异步日志1. spdlog1. 日志作用2 .同步日志和异步日志区别 2. spdlog是什么下载命令&#xff1a;2. spdlog为什么高效3. spdlog特征5. spdlog输出控制6. 处理流程7. 文件io8.问题 2. 如何创建logger3. 如何创建sink4. 如何自定义格式化5. 如何创建异步日志…