新闻详情

新闻详情

首页 / 资讯中心 / 详情

SpringBoot+微信小程序点餐系统开发实战:从建表到下单全流程

发布时间:2026/9/14 11:56:51来源:尧图网络
SpringBoot+微信小程序点餐系统开发实战:从建表到下单全流程
简介一款基于Spring Boot与微信小程序的点餐系统面向Java后端与微信小程序学习者尤其适合作为计算机相关专业的毕业设计、课程设计或项目立项演示。服务端整合了MyBatis、Kafka、WebSocket、Vue.js、Layui、Lombok、Freemarker等主流技术运行环境为JDK 1.8与MySQL客户端采用微信小程序实现覆盖点餐场景的核心业务闭环。资源包共包含276个文件以Java源码、JavaScript脚本、CSS样式、FreeMarker模板、JSON与XML配置为主同时包含小程序前端WXML/WXSS页面及少量图片、音频等静态资源压缩包整体仅1.43MB结构清晰便于按模块查阅。目前已有179人学习下载代码均经过测试运行成功另附README说明文档可帮助读者快速理解项目架构与启动流程也支持在此基础上二次修改扩展功能是实战练手与毕设参考的不错选择。1. 一个点餐系统核心是“点”而不是“餐”餐饮门店里最常见的瓶颈不是后厨翻台而是客人等服务员、服务员记菜名、再到后厨口头下单。基于SpringBoot和微信小程序的点餐系统本质是把这条链路压缩成“扫码进小程序-看菜下单-订单落库-商家接单”。对开发者来说这套题目恰好覆盖了微信登录的code换token流程、SpringBoot接口设计、MySQL订单事务、Redis缓存会话以及小程序端的页面加载与本地购物车状态既能当毕业设计也能改造成小商家可用的点餐工具。下面按照从数据到代码的顺序把整套方案的落地方案讲清楚。2. 点餐系统的数据模型先定义订单状态和库存再写接口2.1 业务闭环和角色划分先理清业务闭环。点餐系统的角色只有两类微信用户和商家管理员。微信用户打开小程序通过wx.login拿到code后端用code换openid并落库生成用户用户看到分类和菜品列表后加入购物车提交订单完成“待支付-已支付-制作中-已完成”的状态流转。商家端可以不做小程序常见做法是先让后端把订单查询接口出好管理端页面用Vue或直接用数据库改状态C端小程序跑通后再补后台。订单和库存是点餐系统里最容易出错的地方。如果库存不扣减会出现“订单生成了但菜品卖完了”如果扣库存和生成订单不在同一个事务里会出现“扣了库存但订单没创建”。所以数据模型必须在写第一行接口前定义清楚尤其是订单状态字段和库存扣减方式。2.2 核心表结构与建表SQL一个完整但不过度设计的点餐系统数据库最少需要五张表category菜品分类、dish菜品、user用户、orders订单、order_item订单明细。用户收货地址可以冗余到订单表里因为用户改地址不能影响历史订单。点餐系统建表 SQL 如下CREATE TABLE category ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(32) NOT NULL COMMENT 分类名称, sort INT DEFAULT 0 COMMENT 排序值越小越靠前, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE dish ( id BIGINT PRIMARY KEY AUTO_INCREMENT, category_id BIGINT NOT NULL COMMENT 所属分类, name VARCHAR(64) NOT NULL, price DECIMAL(10,2) NOT NULL COMMENT 单价单位元, image VARCHAR(255) COMMENT 图片URL, stock INT DEFAULT 0 COMMENT 库存数量, status TINYINT DEFAULT 1 COMMENT 1上架 0下架, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_category_id (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE user ( id BIGINT PRIMARY KEY AUTO_INCREMENT, openid VARCHAR(64) NOT NULL COMMENT 微信openid, nickname VARCHAR(64), avatar VARCHAR(255), create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE orders ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL COMMENT 业务订单号, user_id BIGINT NOT NULL COMMENT 下单用户ID, total_amount DECIMAL(10,2) NOT NULL, status TINYINT DEFAULT 0 COMMENT 0待支付 1已支付 2制作中 3已完成 4已取消, address VARCHAR(255) COMMENT 收货地址, phone VARCHAR(20), remark VARCHAR(255), create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_order_no (order_no), KEY idx_user_id (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE order_item ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_id BIGINT NOT NULL, dish_id BIGINT NOT NULL, dish_name VARCHAR(64) NOT NULL COMMENT 下单时的菜品名快照, dish_image VARCHAR(255), price DECIMAL(10,2) NOT NULL COMMENT 下单时单价快照, quantity INT NOT NULL, KEY idx_order_id (order_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;建表时统一使用 utf8mb4菜品名和备注才不会有中文乱码问题。order_item 里冗余 dish_name 和 dish_image而不是下单时去关联 dish 表这是为了避免菜品改名或删除后历史订单没法看。订单金额也要存 total_amount商家改价不影响已生成的订单。2.3 实体类与Mapper层写法后端使用 MyBatis-Plus 能省掉大量 XML。实体类用 TableName 注解指向表名主键用 TableId 声明是自增。以 Dish 实体为例Data TableName(dish) public class Dish { TableId(type IdType.AUTO) private Long id; private Long categoryId; private String name; private BigDecimal price; private String image; private Integer stock; private Integer status; }对应 Mapper 接口只需要继承 BaseMapper不需要写任何 SQLMapper public interface DishMapper extends BaseMapperDish { }这种写法能让新手快速上手但对复杂查询比如“订单列表带用户昵称”还是要写自定义 SQL。MyBatis-Plus 的分页插件需要在配置类里注册 PaginationInnerInterceptor否则 page 方法不会真正分页只会查全表再包装结果。分页插件配置会在第 3 章给出完整代码。2.4 订单状态字段的取值约定订单状态是后端最容易失控的字段。常见错误是用字符串存状态比如“已支付”“已支付 ”,多一个空格就查不到了。我一般用 TINYINT 存业务状态并在后端定义一个 OrderStatus 常量类public class OrderStatus { public static final int WAIT_PAY 0; public static final int PAID 1; public static final int MAKING 2; public static final int FINISHED 3; public static final int CANCELLED 4; }状态流转规则如下表所示状态值含义允许进入的操作0待支付用户支付 - 1超时取消 - 41已支付商家接单 - 2用户退款 - 42制作中商家出餐 - 33已完成无4已取消无支付接口在开发阶段可以先用“模拟支付”也就是把订单状态直接改为已支付。后面接入微信支付时再替换成支付回调处理逻辑但状态字段定义不需要改动这样前后端对接成本最低。3. SpringBoot 后端把登录、菜品、下单三个接口跑通3.1 项目结构和依赖版本选择后端工程建议按功能分包controller、service、mapper、entity、common。我见过很多点餐系统的源代码把 controller 和 mapper 全放在一个包下面项目一大了维护成本立刻上来。分包结构参考如下com.example.diancan ├── controller ├── service │ └── impl ├── mapper ├── entity ├── common │ ├── Result.java │ └── BizException.java └── config └── MybatisPlusConfig.javapom.xml 核心依赖如下parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version /parent dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependenciesSpringBoot 版本不要追太高2.7.18 是稳定版本网上大多数踩坑经验都基于这个版本的配置。如果你用 SpringBoot 3.xRedis 配置前缀会从 spring.redis 改成 spring.data.redisMyBatis-Plus 也需要用新启动器代码会多出很多兼容性改动。3.2 application.yml 里最值得注意的配置server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/diancan?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost port: 6379 database: 1 mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl wx: appid: 你的appid secret: 你的secretmysql url 里必须加 characterEncodingutf8 和 serverTimezoneAsia/Shanghai否则本地时间会比实际少 8 小时。mybatis-plus 的 map-underscore-to-camel-case 让 category_id 自动映射到 categoryId不需要写一堆 resultMap。log-impl 设置为 StdOutImpl 后控制台会打印每条 SQL开发阶段排查问题非常有用线上再关掉。依赖中还有 spring-boot-starter-data-redis它默认用 Lettuce 连接池单机开发不需要额外配置。Redis 在这里用来存登录 token也可以缓存菜品分类和菜品列表减少数据库压力。3.3 微信登录接口code 换 openid再换自己的 token微信小程序端调用 wx.login 拿到的是临时 code后端必须拿 code 到微信接口换 openid 和 session_key。注意 session_key 绝对不能返回给前端它用来解密手机号和用户隐私信息。后端收到 openid 后查 user 表不存在就创建用户然后生成自己的 token 存 Redis。登录接口代码RestController RequestMapping(/api/user) RequiredArgsConstructor public class UserController { private final UserService userService; PostMapping(/login) public ResultString login(RequestBody MapString, String body) { String code body.get(code); return Result.ok(userService.login(code)); } }Service 实现类核心逻辑public String login(String code) { String url String.format( https://api.weixin.qq.com/sns/jscode2session?appid%ssecret%sjs_code%sgrant_typeauthorization_code, wxAppid, wxSecret, code); String response restTemplate.getForObject(url, String.class); JSONObject json JSON.parseObject(response); if (json.getInteger(errcode) ! null) { throw new BizException(微信登录失败 json.getString(errmsg)); } String openid json.getString(openid); User user userMapper.selectOne( new LambdaQueryWrapperUser().eq(User::getOpenid, openid)); if (user null) { user new User(); user.setOpenid(openid); userMapper.insert(user); } String token UUID.randomUUID().toString().replace(-, ); redisTemplate.opsForValue().set( login:token: token, user.getId().toString(), 7, TimeUnit.DAYS); return token; }wx.login 产生的 code 只能使用一次有效期大概五分钟所以这个接口不能用缓存每次登录都必须真实请求微信服务器。token 用 UUID 而不是直接把 openid 传给前端好处是后端可以控制 token 过期时间用户换手机或被盗时也能强制失效。这里没有再拿 session_key因为点餐系统不需要获取微信手机号如果需要预定桌位或识别会员可以再扩展手机号解密。3.4 菜品列表接口与分页插件小程序端首页需要同时加载分类、菜品、推荐排序最省事的方式是提供两个接口分类列表直接全量返回菜品列表按 categoryId 分页返回。分页查询依赖 MyBatis-Plus 分页插件配置如下Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }菜品查询 Servicepublic IPageDish pageDish(Long categoryId, long page, long size) { LambdaQueryWrapperDish wrapper new LambdaQueryWrapper(); if (categoryId ! null categoryId 0) { wrapper.eq(Dish::getCategoryId, categoryId); } wrapper.eq(Dish::getStatus, 1) .orderByAsc(Dish::getCategoryId) .orderByDesc(Dish::getId); return dishMapper.selectPage(new Page(page, size), wrapper); }page 和 size 直接透传给前端但服务端必须限制最大值。我一般会在 Controller 里加 RequestParam(defaultValue 1) long page 和 RequestParam(defaultValue 10) long size并且 size 不能超过 20避免一次拉全量菜品拖垮接口。菜品图片不要用小程序本地路径要存后端可访问的 URL开发阶段可以用本地静态资源映射上线后改用 OSS 或 CDN。3.5 下单接口中的事务与库存扣减下单是点餐系统里对数据一致性要求最高的接口。一个订单包含多条明细必须先算总价再扣库存最后插入订单和明细。整个过程必须在同一个事务里否则任何一步失败都会留下脏数据。推荐的下单 Service 代码Transactional(rollbackFor Exception.class) public String createOrder(Long userId, CreateOrderDTO dto) { Orders order new Orders(); order.setOrderNo(generateOrderNo()); order.setUserId(userId); order.setStatus(OrderStatus.WAIT_PAY); order.setAddress(dto.getAddress()); order.setPhone(dto.getPhone()); order.setRemark(dto.getRemark()); BigDecimal totalAmount BigDecimal.ZERO; ListOrderItem items new ArrayList(); for (OrderItemDTO itemDTO : dto.getItems()) { Integer rows dishMapper.deductStock(itemDTO.getDishId(), itemDTO.getQuantity()); if (rows 0) { throw new BizException(菜品库存不足 itemDTO.getDishId()); } Dish dish dishMapper.selectById(itemDTO.getDishId()); totalAmount totalAmount.add( dish.getPrice().multiply(BigDecimal.valueOf(itemDTO.getQuantity()))); OrderItem item new OrderItem(); item.setDishId(dish.getId()); item.setDishName(dish.getName()); item.setDishImage(dish.getImage()); item.setPrice(dish.getPrice()); item.setQuantity(itemDTO.getQuantity()); items.add(item); } order.setTotalAmount(totalAmount); orderMapper.insert(order); for (OrderItem item : items) { item.setOrderId(order.getId()); orderItemMapper.insert(item); } return order.getOrderNo(); }这里的 deductStock 必须使用一条原子 SQLUPDATE dish SET stock stock - #{quantity} WHERE id #{dishId} AND stock #{quantity}普通 select 再 update 在并发场景下会超卖原子 SQL 把“检查库存”和“扣减库存”合成了一个动作影响行数为 0 就说明库存不足直接抛异常让事务回滚。Transactional 的 rollbackFor Exception.class 是为了让自定义 BizException 也能触发回滚否则默认运行时异常才会回滚检查型异常会提交事务这是下单接口最容易踩的坑。4. 微信小程序端从页面初始化到提交订单4.1 小程序项目结构和全局配置前端工程建议用微信开发者工具的原生项目不要一上来就引入 uniapp。原生项目结构简单真机调试和报错信息都直接对应到页面上。工程结构如下miniprogram/ ├── app.js ├── app.json ├── pages/ │ ├── index/ # 菜品列表和点餐首页 │ ├── cart/ # 购物车页 │ └── order/ # 订单列表 └── utils/ └── request.jsapp.json 里注册页面路径、设置窗口标题和 tabBar。页面数量少tabBar 可以只放“点餐”和“订单”两个入口。底部 tabBar 的图标可以用本地图片没有设计稿时也可以直接用 text不影响开发联调。4.2 全局请求封装和登录态管理小程序不能直接把后端接口路径写死在每个页面里应该封装一个 request.js。它统一处理 baseUrl、token、错误提示和返回 Promise。// utils/request.js const BASE_URL http://localhost:8080; function request(path, method, data) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL path, method: method || GET, data: data || {}, header: { Content-Type: application/json, Authorization: wx.getStorageSync(token) }, success(res) { if (res.data.code 0) { resolve(res.data.data); } else { wx.showToast({ title: res.data.msg, icon: none }); reject(res.data); } }, fail(err) { wx.showToast({ title: 网络异常, icon: none }); reject(err); } }); }); } module.exports { request, BASE_URL };后端统一返回格式是 { code, msg, data }code 为 0 表示成功。这样页面里只需要处理业务数据不需要每个按钮都写错误 toast。token 从 storage 里读取登录成功后写入不需要每次请求都手动传参。4.3 使用 wx.login 完成静默登录并缓存 token小程序的登录流程和传统网页登录不同用户不需要输入账号密码。app.js 在 onLaunch 里检查本地 token如果不存在就调用 wx.login用返回的 code 请求后端登录接口。// app.js App({ onLaunch() { const token wx.getStorageSync(token); if (token) { this.globalData.token token; } else { this.login(); } }, login() { wx.login({ success: (res) { const code res.code; wx.request({ url: http://localhost:8080/api/user/login, method: POST, data: { code }, success: (resp) { const token resp.data.data; this.globalData.token token; wx.setStorageSync(token, token); } }); } }); }, globalData: { token: } });这里的登录是静默的用户无感知。token 设置了 7 天过期过期后后端返回 401小程序再调用 wx.login 重新换取。不要每次 onShow 都调 wx.login微信官方对 code 换 session_key 有频率限制频繁调用会被风控。4.4 点餐页的数据加载与商品选择点餐页需要放在 tabBar 第一个位置进入时请求分类和菜品数据。小程序没有 filter 管道菜品价格建议在后端就格式化成字符串前端直接用 WXML 渲染避免浮点数精度问题。addToCart 的代码放在 index.js 里用户点击“加入购物车”后把菜品对象写入本地 storage。购物车结构用对象而不是数组key 是 dishId这样修改数量时不需要遍历查找。addToCart(event) { const dish event.currentTarget.dataset.dish; let cart wx.getStorageSync(cart) || {}; if (cart[dish.id]) { cart[dish.id].quantity 1; } else { cart[dish.id] { dishId: dish.id, name: dish.name, price: dish.price, image: dish.image, quantity: 1 }; } wx.setStorageSync(cart, cart); this.updateCartCount(); }4.5 购物车本地缓存与提交订单购物车为什么放本地而不是后端对点餐系统来说用户从点餐到下单通常在一分钟内完成本地缓存实现简单、不占后端资源也不会因为断网丢失已选菜品。如果需要做“用户换手机购物车还在”的功能那就要在后端 Redis 或数据库建购物车表这里不展开。提交订单时把购物车对象转成数组连同地址备注一起 POST 给后端submitOrder() { const cart wx.getStorageSync(cart) || {}; const items Object.values(cart); if (items.length 0) { wx.showToast({ title: 购物车为空, icon: none }); return; } request(/api/order/create, POST, { items, address: this.data.address, phone: this.data.phone, remark: this.data.remark }).then((orderNo) { wx.removeStorageSync(cart); wx.showToast({ title: 下单成功 }); wx.redirectTo({ url: /pages/order/detail?orderNo orderNo }); }); }下单成功后必须清空本地购物车否则用户再次进入点餐页会重复提交。页面跳转用 redirectTo 而不是 navigateTo避免订单详情页无限堆积在页面栈里。真实项目里这里还要接微信支付支付成功后更新订单状态再跳转订单详情。5. 源代码和文档说明交付一个别人能跑起来的项目5.1 仓库结构前后端建议用单仓库管理点餐系统通常是一个人完成的前后端代码把它拆成两个仓库反而增加交接成本。我一般推荐用单仓库monorepo方式管理结构如下diancan/ ├── backend/ │ ├── src/ │ ├── pom.xml │ └── Dockerfile ├── miniprogram/ │ ├── pages/ │ ├── app.js │ └── app.json ├── docs/ │ ├── database.sql │ ├── API.md │ └── DEPLOY.md └── README.md这样的目录交给别人第一眼就知道哪部分是后端、哪部分是小程序、哪部分是文档。数据库脚本必须放在 docs 目录而不是聊天记录或网盘里新环境初始化时直接执行 database.sql 即可。5.2 文档说明里必须写清的四件事README.md 不用写详细教程但要回答四个问题项目是什么、用了什么技术、怎么启动、怎么部署。期望一个新工程师在 10 分钟内把项目跑起来文档才合格。API.md 建议手写一个精简版不要依赖 Swagger 页面。Swagger 能看参数但不能说明业务规则比如下单接口必须携带 token、订单状态怎么流转。API.md 里对每个接口列出请求方法、路径、请求参数、成功返回示例和失败码。DEPLOY.md 写部署检查清单MySQL 是否创建库、Redis 是否启动、application.yml 的数据库密码是否替换、小程序 request 合法域名是否在微信公众平台配置。后端打包命令用 mvn clean package -DskipTests前端用微信开发者工具上传版本再到 mp 后台提交审核。5.3 交接前的验证清单和两个排错技巧在把源代码交出去之前至少验证以下场景新用户第一次登录能自动创建账号同一用户重复登录 token 不重复生成菜品下架后点餐页不再显示库存不足时下单接口返回明确提示且订单表无脏数据下单后 Redis 里的 token 仍能正常访问订单详情。遇到“当前不会命中断点”时先确认代码是以 Debug 方式启动而不是 Run。IDEA 里 Run 按钮旁边有 bug 图标点击它启动才能断住。如果断点打在没有执行的代码行比如接口 Service 实现类没有被 Controller 调用到也会出现这个提示。优先在 Controller 方法第一行打断点确认请求进来了再往下追。小程序端请求报“不在以下 request 合法域名列表中”时开发者工具里可以临时勾选“不校验合法域名”完成联调但真机预览必须使用 HTTPS 域名。后端没有域名时可以先用内网穿透工具把 localhost:8080 临时映射成 HTTPS 地址注意这只能用于开发不能用于上线。最后把后端打包命令 mvn clean package -DskipTests 写进 DEPLOY.md新环境部署执行这一条命令就能生成可运行的 jar不会有人再来问怎么打包。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

oauth2-proxy 接入 login.gov:从应用注册到 JWT 签名的完整配置指南 2026/9/14 14:00:13

oauth2-proxy 接入 login.gov:从应用注册到 JWT 签名的完整配置指南

oauth2-proxy 接入 login.gov:从应用注册到 JWT 签名的完整配置指南 【免费下载链接】oauth2-proxy A reverse proxy that provides authentication with Google, Azure, OpenID Connect and many more identity providers. 项目地址: https://gitcode.com/GitHub…

阅读更多 →
Windows下MD5校验的三种实用方法对比 2026/9/14 14:00:13

Windows下MD5校验的三种实用方法对比

1. Windows环境下MD5校验的三种实战方案 作为开发者和系统管理员,我们经常需要验证文件的完整性。上周我接手一个项目时,客户发来的压缩包在传输过程中出现了损坏,导致解压后关键数据丢失。这种场景下,MD5校验就成了我们的"文…

阅读更多 →
Wagtail 私有页面如何用登录、共享密码和用户组限制访问? 2026/9/14 14:00:13

Wagtail 私有页面如何用登录、共享密码和用户组限制访问?

Wagtail 私有页面如何用登录、共享密码和用户组限制访问? 【免费下载链接】wagtail A Django content management system focused on flexibility and user experience 项目地址: https://gitcode.com/GitHub_Trending/wa/wagtail 如果你正在用 Wagtail 管理…

阅读更多 →
Python网络入侵检测系统生产级部署实战 2026/9/14 14:00:13

Python网络入侵检测系统生产级部署实战

简介:这是一套面向计算机专业本科生的毕业设计级网络入侵检测与防御系统实战源码,聚焦网络安全实践能力培养,适用于毕设、课程设计及安全方向入门开发。系统基于Python构建,完整实现网络流量实时捕获分析、多类攻击识别、自动拦截…

阅读更多 →
Rufus:3 步把 ISO 变成可启动 U 盘,7 种文件系统兼容 BIOS 与 UEFI 全机型 2026/9/14 14:00:13

Rufus:3 步把 ISO 变成可启动 U 盘,7 种文件系统兼容 BIOS 与 UEFI 全机型

Rufus:3 步把 ISO 变成可启动 U 盘,7 种文件系统兼容 BIOS 与 UEFI 全机型 【免费下载链接】rufus The Reliable USB Formatting Utility 项目地址: https://gitcode.com/GitHub_Trending/ru/rufus Rufus 是一款免安装的 USB 格式化工具&#xff…

阅读更多 →
在 Zola 中快速搭建文档站:Karzok 主题安装、配置与部署完整指南 2026/9/14 13:57:13

在 Zola 中快速搭建文档站:Karzok 主题安装、配置与部署完整指南

在 Zola 中快速搭建文档站:Karzok 主题安装、配置与部署完整指南 【免费下载链接】zola A fast static site generator in a single binary with everything built-in. https://www.getzola.org 项目地址: https://gitcode.com/GitHub_Trending/zo/zola 本文…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞