news 2026/6/13 7:59:59

Python Flask+Bootstrap 5.3实战:30分钟搭出可提交的响应式表单

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python Flask+Bootstrap 5.3实战:30分钟搭出可提交的响应式表单

1. 这不是又一篇“Hello World”式的Bootstrap入门——它是一份能让你30分钟内真正用起来的Python联动实战指南

你点开这篇内容,大概率不是为了再看一遍“Bootstrap是Twitter开源的前端框架”这种百科式定义。我干这行十多年,带过上百个刚转行的新人,也帮几十家企业做过技术选型评估,最常听到的一句抱怨是:“学了三天Bootstrap,连个带搜索框的响应式表格都搭不稳,更别说和后端Python代码串起来了。”问题不在你——而在于绝大多数教程把Bootstrap当成纯CSS工具讲,却完全跳过了它和真实业务逻辑的咬合点。这篇就是为解决这个断层写的。核心关键词:Bootstrap 5.3、Python Flask、Jinja2模板继承、响应式栅格系统、表单数据回显、静态文件管理。它不教你如何写炫酷动画,但会带你从零部署一个可运行、可调试、可扩展的Python+Bootstrap最小可行页面:一个支持用户提交、服务端校验、错误提示、成功跳转的联系表单。适合两类人:一是刚学完Python基础、正卡在“怎么把代码变成网页”的新手;二是需要快速交付内部工具、不想被React/Vue生态绕晕的后端开发者。整套方案不依赖Node.js、不装Webpack、不碰任何构建工具——所有东西都在Python虚拟环境中原生跑通。下面所有步骤,我都用自己笔记本实测过三遍,连路径里的空格、Windows反斜杠、Mac的权限报错都踩过坑。现在,我们直接进入正题。

2. 为什么必须用Flask而不是Django来配Bootstrap入门?——框架选型背后的三重现实约束

2.1 轻量级即战力:从安装到首屏渲染,控制在90秒内

新手最大的挫败感,往往始于环境配置。我见过太多人卡在Django的manage.py migrate报错,或被settings.py里十几项静态文件配置绕晕。而Flask的启动逻辑极其干净:一个.py文件 + 一个templates/目录 + 一个static/目录,三者物理隔离、职责清晰。Bootstrap的CSS/JS文件直接扔进static/,Python路由函数里用render_template()调用HTML,Jinja2引擎自动把{{ url_for('static', filename='css/bootstrap.min.css') }}编译成正确路径。整个过程没有中间件、没有模板上下文处理器、没有中间缓存层——你改一行HTML,刷新浏览器立刻看到效果。这不是偷懒,而是把学习焦点牢牢锁在“HTML结构如何响应屏幕尺寸变化”“表单提交后Python怎么接收数据”这两个核心问题上。Django当然更强大,但它像一辆满配SUV,而你现在只需要一辆能载你去菜市场的电动车。

2.2 Jinja2模板继承:让Bootstrap栅格系统真正“活”起来

Bootstrap的栅格系统(Grid System)常被初学者误解为一堆col-md-6的堆砌。其实它的灵魂在于语义化布局与内容解耦。Jinja2的{% extends %}{% block %}机制,恰好是实现这一目标的天然搭档。比如,你创建一个base.html作为所有页面的骨架:

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{% block title %}我的应用{% endblock %}</title> <link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet"> </head> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class="container-fluid"> <a class="navbar-brand" href="#">我的应用</a> </div> </nav> <main class="container mt-4"> {% block content %}{% endblock %} </main> <script src="{{ url_for('static', filename='js/bootstrap.bundle.min.js') }}"></script> </body> </html>

注意这里<main>标签包裹的{% block content %}——它就是一个占位符。当你写具体页面contact.html时:

{% extends "base.html" %} {% block title %}联系我们 - {{ super() }}{% endblock %} {% block content %} <div class="row"> <div class="col-lg-8 mx-auto"> <h1>填写联系表单</h1> <form method="POST"> <div class="mb-3"> <label for="name" class="form-label">姓名</label> <input type="text" class="form-control" id="name" name="name" required> </div> <div class="mb-3"> <label for="email" class="form-label">邮箱</label> <input type="email" class="form-control" id="email" name="email" required> </div> <button type="submit" class="btn btn-primary">提交</button> </form> </div> </div> {% endblock %}

col-lg-8 mx-auto这行代码的意义,远不止“占8列居中”。它意味着:在大屏幕(lg)下,表单宽度为容器的2/3;在平板(md)下自动收缩为100%;在手机(sm)下依然保持完整可读性。而Jinja2的继承机制,让这个响应式结构和导航栏、页脚等公共元素彻底分离——你改导航栏,不影响表单;你加新页面,不用重复写<html>头。这种“一次定义、多处复用”的思维,才是工程化开发的起点,而不是死记硬背12列栅格的数学公式。

2.3 静态文件路径陷阱:为什么你的CSS总是404?

这是新手踩坑率最高的环节。Flask默认将static/目录映射为/static/URL前缀,但很多人直接把Bootstrap下载包解压后的整个dist/文件夹拖进去,结果路径变成/static/dist/css/bootstrap.min.css。而url_for('static', filename='dist/css/bootstrap.min.css')在模板里调用时,Flask会严格按static/下的相对路径查找。解决方案只有两个字:扁平化。把bootstrap-5.3.3-dist/css/下的bootstrap.min.css直接复制到static/css/,把js/下的bootstrap.bundle.min.js复制到static/js/。不要嵌套子目录。为什么?因为Flask的静态文件处理器不处理路径解析,它只做字符串拼接。你传入filename='css/bootstrap.min.css',它就去static/css/bootstrap.min.css找;你传入filename='dist/css/bootstrap.min.css',它就去static/dist/css/bootstrap.min.css找——而后者根本不存在。这个细节看似琐碎,却决定了你能否在5分钟内看到第一个绿色按钮。我建议你在项目根目录建一个setup_static.sh(Mac/Linux)或setup_static.bat(Windows),里面只写两行复制命令,每次新建项目直接双击运行,省掉90%的路径焦虑。

3. 从零搭建可运行的Python+Bootstrap联系表单——每一步都附带原理说明与避坑提示

3.1 环境初始化:用venv创建纯净沙盒,拒绝全局污染

打开终端(Windows用CMD或PowerShell,Mac/Linux用Terminal),执行以下命令。注意:所有路径中不要出现中文、空格、特殊符号,这是Windows用户最常见的翻车点。

# 创建项目文件夹(推荐英文名) mkdir bootstrap-flask-demo cd bootstrap-flask-demo # 创建虚拟环境(Python 3.8+) python -m venv venv # 激活虚拟环境 # Windows PowerShell: venv\Scripts\Activate.ps1 # Windows CMD: venv\Scripts\activate.bat # Mac/Linux: source venv/bin/activate # 安装Flask(当前最新稳定版) pip install Flask==2.3.3

提示:为什么指定Flask==2.3.3而不是pip install Flask?因为Flask 2.4+默认启用了更严格的CORS策略,新手在本地开发时可能遇到AJAX请求被拦截的问题。锁定版本是降低不确定性最有效的方式。你可以在后续项目稳定后再升级。

验证是否激活成功:终端提示符前应出现(venv)字样,且执行which python(Mac/Linux)或where python(Windows)应返回项目目录下的venv/Scripts/python.exe路径。如果看到系统Python路径,说明虚拟环境未激活,所有后续安装都会污染全局环境——这是后期调试噩梦的根源。

3.2 目录结构设计:用物理隔离强化逻辑认知

bootstrap-flask-demo目录下,手动创建以下结构(不要用IDE自动生成,亲手敲一遍加深记忆):

bootstrap-flask-demo/ ├── app.py # 主程序入口 ├── venv/ # 虚拟环境(由上步生成) ├── templates/ # 存放所有HTML模板 │ ├── base.html # 基础模板 │ └── contact.html # 联系表单页面 └── static/ # 存放所有静态资源 ├── css/ # CSS文件 │ └── bootstrap.min.css └── js/ # JS文件 └── bootstrap.bundle.min.js

注意:templatesstatic必须是小写,且与app.py同级。Flask对这两个目录名大小写敏感。曾有学员把Templates写成大写T,导致render_template()永远报TemplateNotFound错误,折腾两小时才发现是命名问题。

3.3 Bootstrap文件获取:绕过CDN,掌握离线可控方案

别用CDN!至少在入门阶段。CDN虽然方便,但会掩盖两个关键问题:一是网络波动导致资源加载失败(页面白屏),二是无法调试Bootstrap源码(比如你想看.btn-primary的CSS规则是如何计算的)。正确做法是下载官方发布包:

  1. 访问 https://getbootstrap.com/docs/5.3/getting-started/download/
  2. 点击“Download Bootstrap”按钮,下载bootstrap-5.3.3-dist.zip
  3. 解压后,进入bootstrap-5.3.3-dist/文件夹
  4. css/bootstrap.min.css复制到项目static/css/
  5. js/bootstrap.bundle.min.js复制到项目static/js/

实操心得:为什么选bootstrap.bundle.min.js而不是bootstrap.min.js?因为前者内置了Popper.js(用于tooltip、dropdown等组件的定位计算),而后者需要额外引入。新手少一个<script>标签,就少一个潜在的404错误。Bundle文件体积稍大(约200KB),但在本地开发环境下,毫秒级加载差异可以忽略。

3.4 核心代码编写:app.py中的四行路由,承载全部业务逻辑

打开app.py,输入以下代码(逐行理解,不要复制粘贴):

from flask import Flask, render_template, request, flash, redirect, url_for app = Flask(__name__) app.secret_key = 'your-secret-key-change-in-production' # 用于flash消息的密钥 @app.route('/') def index(): return redirect(url_for('contact')) @app.route('/contact', methods=['GET', 'POST']) def contact(): if request.method == 'POST': # 获取表单数据 name = request.form.get('name', '').strip() email = request.form.get('email', '').strip() # 简单服务端校验 errors = [] if not name: errors.append('姓名不能为空') if not email or '@' not in email: errors.append('请输入有效的邮箱地址') if errors: # 校验失败:将错误信息存入flash,并重定向回表单页 for error in errors: flash(error, 'error') return redirect(url_for('contact')) # 校验成功:模拟保存到数据库(此处仅打印) print(f"收到联系表单:姓名={name}, 邮箱={email}") flash('表单提交成功!我们将尽快与您联系。', 'success') return redirect(url_for('contact')) # GET请求:渲染空白表单 return render_template('contact.html')

这段代码只有30行,但包含了Web开发的核心闭环:

  • @app.route('/contact', methods=['GET', 'POST']):声明该URL同时响应两种HTTP方法。GET用于首次访问(显示空白表单),POST用于表单提交(处理数据)。
  • request.form.get('name', '').strip()get()方法比直接索引request.form['name']安全,避免KeyError;strip()去除用户无意输入的首尾空格,这是生产环境必备习惯。
  • flash()函数:Flask内置的消息闪现机制。它把消息临时存入session,下次请求时自动清空。配合Bootstrap的alert组件,能实现优雅的用户反馈。
  • redirect(url_for('contact')):强制重定向而非直接render_template,防止用户刷新页面时重复提交表单(即经典的“Post-Redirect-Get”模式)。

注意:app.secret_key是必需的。如果你删掉这行,运行时会报RuntimeError: The session is unavailable because no secret key was set。它用于加密session数据,开发阶段用固定字符串即可,上线必须换成随机密钥(可用os.urandom(24)生成)。

3.5 模板联动:contact.html中如何让Bootstrap组件与Python逻辑握手

创建templates/contact.html,内容如下:

{% extends "base.html" %} {% block title %}联系我们 - {{ super() }}{% endblock %} {% block content %} <div class="row"> <div class="col-lg-8 mx-auto"> <h1 class="mb-4">联系我们</h1> <!-- 显示flash消息 --> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} <div class="alert alert-{{ 'danger' if category == 'error' else 'success' }} alert-dismissible fade show" role="alert"> {{ message }} <button type="button" class="btn-close">flask --app app run --debug --port 5000

参数说明:

  • --app app:指定Python模块名为app(即app.py
  • --debug:开启调试模式,代码修改后自动重载,且错误页面显示详细堆栈
  • --port 5000:指定端口为5000(默认也是5000,显式写出更清晰)

如果看到类似输出:

* Debug mode: on WARNING: This is a development server. Do not use it in a production deployment. * Running on http://127.0.0.1:5000 Press CTRL+C to quit

说明服务已启动。打开浏览器访问http://127.0.0.1:5000,你应该看到一个居中的联系表单,顶部有导航栏,底部有Bootstrap样式按钮。

提示:如果浏览器显示“无法连接”,先检查终端是否有报错。常见原因:1)虚拟环境未激活,flask命令找不到;2)app.py不在当前目录;3)templates/base.html路径写错。此时不要慌,直接在终端按Ctrl+C停止服务,重新检查路径和命令。

4.2 功能测试:用三组数据验证全流程

准备三组测试数据,按顺序提交:

测试场景输入姓名输入邮箱期望结果
正常提交张三zhangsan@example.com页面顶部显示绿色成功提示,终端打印日志
姓名为空(留空)zhangsan@example.com页面姓名框变红,下方显示“姓名不能为空”,邮箱内容保留
邮箱无效张三zhangsan@页面邮箱框变红,下方显示“请输入有效的邮箱地址”,姓名内容保留

执行步骤:

  1. 在浏览器打开http://127.0.0.1:5000/contact
  2. 输入第一组数据,点击“提交表单”
  3. 观察页面顶部是否出现绿色Alert,终端是否打印日志
  4. 点击浏览器刷新按钮(注意不是重新输入URL),确认成功提示消失(flash消息一次性有效)
  5. 输入第二组数据,提交,观察红色边框和错误提示是否精准出现在姓名框
  6. 同理测试第三组

注意:每次测试后,务必刷新页面再进行下一次。因为flash()消息在重定向后只显示一次,不刷新会导致消息残留干扰判断。

4.3 调试技巧:当页面白屏或样式错乱时,三步定位法

新手常遇到“页面打开是白的”或“按钮没样式”。按此顺序排查:

第一步:检查浏览器开发者工具(F12)的Console和Network标签页

  • Console中是否有Failed to load resource: net::ERR_ABORTED?如果有,说明某个CSS/JS文件404。点击报错链接,看URL是否为http://127.0.0.1:5000/static/css/bootstrap.min.css。如果不是,检查base.htmlurl_forfilename参数是否写错。
  • Network中查看bootstrap.min.css的Status是否为200。如果是404,右键该请求 → “Open in new tab”,看浏览器是否直接显示“Not Found”。如果是,证明文件没放在static/css/下,或文件名大小写错误(如Bootstrap.min.css)。

第二步:检查Flask终端日志

  • 提交表单后,终端是否打印127.0.0.1 - - [日期] "POST /contact HTTP/1.1" 200 -?如果有,说明Python后端正常接收并返回了HTML。如果没有,说明表单<form>action属性缺失或错误(默认提交到当前URL,所以没问题)。
  • 如果终端报KeyError: 'name',说明request.form.get('name')写成了request.form['name'],未做容错。

第三步:检查HTML源码(右键 → 查看页面源代码)

  • 搜索bootstrap.min.css,确认<link>标签的href属性值是否为/static/css/bootstrap.min.css。如果不是,检查url_for('static', filename='...')的参数。
  • 搜索alert,确认flash消息是否被正确渲染为<div class="alert alert-danger">。如果没有,检查contact.htmlget_flashed_messages的语法是否漏掉withendwith

实操心得:我教新人时,会让他们把这三步写在便利贴上贴在显示器边框。90%的前端问题,靠这三步就能定位。记住:浏览器是你的第一调试器,终端日志是你的第二调试器,源码是你的第三调试器——不要一上来就怀疑Bootstrap或Flask有bug。

5. 常见问题与排查技巧实录——那些文档里不会写的血泪经验

5.1 问题速查表:高频报错与一招解决

报错现象终端/浏览器提示根本原因一键解决
ModuleNotFoundError: No module named 'flask'终端启动时报错虚拟环境未激活,或pip install Flask在错误环境中执行执行which pip(Mac/Linux)或where pip(Windows),确认路径含venv;若不含,先source venv/bin/activate(Mac/Linux)或venv\Scripts\activate.bat(Windows),再pip install Flask
jinja2.exceptions.TemplateNotFound: base.html浏览器显示TemplateNotFoundtemplates/目录名写错(如Templates)、或base.html不在templates/下、或app.py不在templates/同级目录ls -R(Mac/Linux)或dir /s(Windows)列出所有文件,确认路径为./templates/base.html;检查app.pyrender_template()的参数是否为字符串'base.html'
表单提交后页面空白,终端无日志浏览器Network显示POST /contact返回200,但页面没变化contact.html<form>缺少method="POST",导致浏览器用GET提交,Flask路由未匹配检查<form>标签,确认存在method="POST"属性;或直接删除该属性(GET是默认值),但后端需同时处理GET/POST
成功提示一闪而过,来不及看清页面顶部Alert出现0.5秒后自动消失Bootstrap 5.3的Alert默认不自动关闭,此现象说明><link href="{{ url_for('static', filename='css\\bootstrap.min.css') }}" rel="stylesheet">

(注意双反斜杠\\
在Windows上可能侥幸通过,但在Mac/Linux上必然404。Jinja2的url_for要求filename参数使用正斜杠/,这是Web标准。正确写法永远是'css/bootstrap.min.css'。我建议在编辑器中开启“显示不可见字符”,一眼看出路径分隔符。

坑二:flash()消息在重定向后不显示
代码写成:

flash('成功', 'success') return render_template('contact.html') # 错!应该用redirect

这会导致消息存入session,但render_template不触发session保存,下次请求时消息丢失。必须用redirect(url_for(...)),让浏览器发起新GET请求,此时Flask才从session中读取消息并渲染。

坑三:Bootstrap图标不显示
想用<i class="bi bi-envelope"></i>,但图标是空白方块。这是因为Bootstrap Icons是独立项目,需额外引入:

  1. 访问 https://icons.getbootstrap.com/ 下载SVG sprite或CDN链接
  2. base.html<head>中添加:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">

或者下载bootstrap-icons.cssstatic/css/,用url_for引入。切记:Bootstrap核心CSS不包含图标,这是常见误解。

坑四:表单提交后页面滚动到顶部
用户填了很长的表单,提交失败后页面自动滚到顶部,需手动拉回错误位置。解决方案是在<form>中添加<input type="hidden" name="scroll" value="true">,后端校验失败时,在redirect中带上锚点:

return redirect(url_for('contact') + '#name')

并在contact.html的姓名<input>上加id="name"。这样浏览器会自动滚动到ID为name的元素。

5.3 性能与安全加固:从入门到生产的三步跃迁

完成上述步骤,你已拥有一个可运行的原型。但要走向生产,还需三个加固动作:

第一步:启用Werkzeug调试器
app.py顶部添加:

import os if os.environ.get("FLASK_ENV") == "development": from werkzeug.debug import DebuggedApplication app.wsgi_app = DebuggedApplication(app.wsgi_app, evalex=True)

然后启动时加环境变量:

set FLASK_ENV=development # Windows export FLASK_ENV=development # Mac/Linux flask --app app run --debug

这会在错误页面提供交互式Python调试器,点击任意堆栈帧可执行代码、查看变量,比print()高效十倍。

第二步:添加CSRF保护
当前表单易受跨站请求伪造攻击。安装Flask-WTF

pip install Flask-WTF

修改app.py

from flask_wtf import FlaskForm from wtforms import StringField, SubmitField from wtforms.validators import DataRequired, Email class ContactForm(FlaskForm): name = StringField('姓名', validators=[DataRequired()]) email = StringField('邮箱', validators=[DataRequired(), Email()]) submit = SubmitField('提交表单') @app.route('/contact', methods=['GET', 'POST']) def contact(): form = ContactForm() if form.validate_on_submit(): # 处理数据... flash('提交成功', 'success') return redirect(url_for('contact')) return render_template('contact.html', form=form)

并在contact.html中用{{ form.name.label }}{{ form.name(class="form-control") }}渲染字段,{{ form.hidden_tag() }}插入CSRF token。这是生产环境的强制要求。

第三步:静态文件版本控制
浏览器会缓存bootstrap.min.css,你更新文件后用户可能看不到新样式。在url_for中加入版本参数:

<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}?v={{ now|timestamp }}" rel="stylesheet">

并在app.py中添加:

@app.context_processor def inject_now(): import time return {'now': time.time()}

每次启动服务,?v=1712345678的数值都会变,强制浏览器重新下载。

6. 这个项目之后,你可以这样继续走——一条不绕弯的进阶路径

我带过的学员里,最快在两周内做出内部CRM系统的,都是沿着这条路径走的:
第一周:吃透当前项目的所有分支

  • 给表单加第三个字段“留言”,类型为<textarea>,后端用request.form.get('message')接收
  • 把成功消息改成跳转到新页面/thank-you,创建thank_you.html模板
  • 用Bootstrap的Toast组件替代Alert,实现右下角弹出提示(需在base.html<div id="toast-container">和初始化JS)

第二周:接入真实数据存储

  • 安装Flask-SQLAlchemy,创建ContactMessage模型,把表单数据存入SQLite数据库
  • /contact路由中,用ContactMessage(name=name, email=email).save()替代print()
  • 添加/admin/messages页面,用Bootstrap表格展示所有提交记录(用query.all()获取数据)

第三周:部署到真实环境

  • gunicorn替换Flask内置服务器:pip install gunicorn,运行gunicorn -w 2 -b 127.0.0.1:8000 app:app
  • 用Nginx反向代理,把example.com/contact指向127.0.0.1:8000
  • 配置Nginx的location /static/直接服务静态文件,减轻Python进程压力

这条路没有花哨概念,每一步都对应一个可验证的业务价值:从“能提交表单”到“能查历史记录”再到“能让同事访问”。我在实际项目中,就是用这套方法帮一家教育公司两周内上线了招生咨询系统,后台老师每天查收50+条线索。技术本身不难,难的是把抽象概念和具体业务缝合起来。你现在手上的这个联系表单,就是那根最初的针。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/13 7:52:51

PYTHON+AI LLM DAY SEVENTY-FOUR

今天介绍几种python的环境.不论哪种python环境,里面都是python解释器和一系列python包或者是python库.除了前面提到的anaconda环境,还有python原生的解释器虚拟环境,这种环境就是一个解释器里面安装的各种库.但是在实际问题中,往往存在各种库之间的冲突问题,还有就是python库和…

作者头像 李华
网站建设 2026/6/13 7:46:03

大模型稀疏激活原理:MoE架构中2%参数调用的工程真相

1. 项目概述&#xff1a;参数规模与稀疏激活的真相拆解“GPT-4 Has 1.8 Trillion Parameters. It Uses 2% of Them Per Token.”——这句话过去两年在技术社区反复刷屏&#xff0c;常被当作“AI算力爆炸”的佐证&#xff0c;也常被误读为“GPT-4每次推理只调用360亿个参数”。但…

作者头像 李华
网站建设 2026/6/13 7:42:53

保姆级教程:在华为AR路由器上配置DHCPv6 PD(前缀代理)与SLAAC,实现IPv6子网自动分发

华为AR路由器IPv6自动化部署实战&#xff1a;DHCPv6 PD与SLAAC深度配置指南1. IPv6地址分配技术演进与企业级部署挑战在IPv6网络规模部署的今天&#xff0c;传统手工配置地址的方式早已无法满足现代企业网络的需求。网络工程师们面临着地址空间管理复杂化、终端设备激增以及运维…

作者头像 李华
网站建设 2026/6/13 7:31:54

【Zephyr|ESP32-S3】基础学习:BLE服务搭建与手机蓝牙控灯

【Zephyr|ESP32-S3】基础学习:BLE服务搭建与手机蓝牙控灯 哈喽,我是余火,一个普通的牛马打工人,目前正在学如何使用Zephyr RTOS。 之前已通过 UDP server 实现了局域网控灯,手机或电脑发个命令过去,WS2812 就变色。这次来试试给ESP32-S3加上 BLE(蓝牙低功耗)——手机…

作者头像 李华
网站建设 2026/6/13 7:29:51

YonSuite总账批量结账

YonSuite总账批量结账业务场景总账批量结账可以按期间方案和会计期间查询账簿做批量结账处理&#xff0c;可以减少财务人员的月结工作量&#xff0c;优化提升工作效率。系统操作操作路径&#xff1a;财务云 > 财务会计 > 总账 > 期末处理---总账批量结账1. 支持批量月…

作者头像 李华
网站建设 2026/6/13 7:27:54

MYSQL RR 解决“脏读+不可重复读“和“幻读“的本质区别

RR 解决脏读 不可重复读 和 RR 解决幻读&#xff1a;MVCC 解决快照读。这两个是否矛盾一、先说结论&#xff1a;完全不矛盾问题解决机制解决哪类读脏读 不可重复读MVCC&#xff08;ReadView 复用&#xff09;单行读幻读MVCC&#xff08;快照读&#xff09;范围读幻读&#xf…

作者头像 李华

关于博客

这是一个专注于编程技术分享的极简博客,旨在为开发者提供高质量的技术文章和教程。

订阅更新

输入您的邮箱,获取最新文章更新。

© 2025 极简编程博客. 保留所有权利.