尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
尚品甄选微服务电商项目实战:Java17+Spring Cloud+Redis+MinIO+Docker
简介一套基于Java 17与Spring Cloud微服务架构的尚品甄选电商平台全栈开发项目面向具备一定Java基础的全栈或后端开发者。项目将电商核心业务拆分为多个微服务模块覆盖后台用户管理、商品管理、订单处理及前台购物流程并集成Redis缓存、MinIO对象存储和Docker容器化部署有助于理解现代电商系统的架构设计与技术选型。压缩包共505个文件大小约3.06MB以185个Java源码、99个前端脚本、52个页面组件、17个服务配置及数据库脚本等为主涵盖前后端代码与部署配置目录结构清晰。目前已有82人学习下载。资源附赠开发文档并包含容器化部署脚本、数据库脚本、工具类等可复用内容便于对照项目梳理微服务拆分、缓存策略、文件存储及容器化流程也是一份适合毕业设计或项目实战参考的完整素材。1. 尚品甄选这套微服务电商项目先回答它解决了什么问题这套拿 Java 17 与 Spring Cloud 微服务架构搭出来的尚品甄选电商项目第一眼吸引我的是它的完整度前台用户端、后台管理端、商品与订单两条主线业务全都落地不是那种只有登录注册的教学工程。中间还串了 Redis 做缓存、MinIO 做图片与文件存储、Docker 做容器化部署几乎把一套小规模电商后端该有的基础设施都装进去了。适合两类人一类是想在简历上放一个真实微服务作品的 Java 从业者照着源码能看懂服务怎么拆、缓存怎么用另一类是公司内部做电商后台、商品系统的人可以直接借鉴它的权限模型和订单流程。下文按 服务拆分 → Redis 落地 → MinIO 接入 → Docker 部署 的路径拆最后补一个订单状态机与缓存一致性的实操技巧。2. 微服务骨架先行Java17 SpringCloud 的服务划分与端口规划2.1 服务拆几个合理按业务域切分而不是按页面切分电商后台做过一段时间的人大概率见过那种“按页面拆服务”的工程商品页一个模块、订单页一个模块、后台管理再一个模块Controller 堆在一起页面倒是齐了一到大促想单独扩容商品服务只能整体竖着切牵一发动全身。尚品甄选这套是按业务域竖切核心拆成用户、商品、订单三条线再加一个网关做统一入口这个切法可以原样搬到自己项目里。模块端口职责cloud-gateway8080统一入口、路由转发、跨域处理user-service8101前台用户与后台管理员登录、JWT 鉴权、角色权限product-service8102商品分类、商品 SPU/SKU、图片关联、库存查询order-service8103购物车、下单、订单状态流转、库存联动common无端口公共 DTO、统一返回体、异常处理器、工具类前后台两端共用 user-service 和 product-service权限靠角色区分而不是把前台和后台拆成两套独立系统这是中小规模电商比较省事的做法。端口规划上网关固定 8080业务服务从 8101 开始顺序排Nacos 注册中心 8848Redis 6379MinIO 9000/9001MySQL 3306。把这些固定下来后面写 Docker Compose 和配置微服务之间的调用时心智负担小很多。注意 9001 是 MinIO 的 Web 控制台端口9000 才是 API 端口很多人第一次部署会把这两个搞混。2.2 父工程 POM 与依赖版本对齐JDK17 带来的第一个硬门槛JDK 17 是 LTS 版本Spring Boot 3.x 也强制要求 17 起步所以这个项目的环境门槛不是可选项。真正动手前先把 JDK 下载安装这步走干净装完把 JAVA_HOME 指到安装目录命令行里java -version必须是 17mvn -v里显示的 Java 版本也得是 17否则 IDE 里可能还在用老版本编译跑起来全是「Unsupported class file major version」这类报错。父工程 POM 的依赖版本对齐是关键直接决定 Nacos 能不能注册上、OpenFeign 能不能调通。我按 Spring Boot 3.2.x Spring Cloud 2023.0.x Spring Cloud Alibaba 2023.0.x 这套组合来对齐可以少踩很多版本地狱的坑。parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.2.4/version relativePath/ /parent properties java.version17/java.version spring-cloud.version2023.0.1/spring-cloud.version spring-cloud-alibaba.version2023.0.1.0/spring-cloud-alibaba.version /properties dependencyManagement dependencies dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-dependencies/artifactId version${spring-cloud.version}/version typepom/type scopeimport/scope /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-alibaba-dependencies/artifactId version${spring-cloud-alibaba.version}/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement这里import作用域的意思是只引入依赖管理不在父工程直接引入具体依赖子模块需要什么自己声明这样每个服务可以控制自己的依赖面。Spring Cloud Alibaba 和 Spring Cloud 是配套发行的版本不能凭感觉乱拼错一档就会出现 Nacos 客户端连不上、心跳报错这类玄学问题查配置半天最后发现是版本不对。JDK 17 的语法红利在代码里用得很自然比如record定义 DTO、switch表达式做状态判断这些都是老 JDK 写起来很啰嗦的地方源码里可以直接照着学。2.3 网关、Nacos 与 OpenFeign 的配置模型网关用 Spring Cloud Gateway路由规则写在配置文件里比在代码里硬编码路由好维护。下面是这套项目网关路由的典型写法注意路由顺序和lb://前缀。spring: application: name: cloud-gateway cloud: nacos: server-addr: ${NACOS_ADDR:localhost:8848} gateway: routes: - id: user-route uri: lb://user-service predicates: - Path/api/user/**,/api/admin/** - id: product-route uri: lb://product-service predicates: - Path/api/product/** - id: order-route uri: lb://order-service predicates: - Path/api/order/**,/api/cart/**uri用lb://开头网关会从 Nacos 拉取对应服务的实例列表做负载均衡前端只认 8080 一个入口不用关心后面有几个服务实例。Path谓词的匹配是有顺序的越具体的路径放越前面如果冲突先命中的路由生效所以/api/user/**和/api/admin/**放在同一个路由的 predicates 里可以合并处理。${NACOS_ADDR:localhost:8848}是环境变量占位符本地默认 localhost到 Docker 部署时注入容器服务名同一份配置不用改代码。服务之间的调用用 OpenFeign接口声明式调用比 RestTemplate 手拼 URL 清晰得多尤其适合商品服务与订单服务之间的库存查询。FeignClient(name product-service) public interface ProductClient { GetMapping(/sku/{skuId}) SkuDTO getSku(PathVariable(skuId) Long skuId); }FeignClient的name必须和注册到 Nacos 的服务名一致否则运行时找不到服务。调用超时不要用默认值生产上我一般把连接超时设 3 秒、读取超时设 10 秒在对应服务的配置里调ribbon或者 Spring Cloud OpenFeign 的connectTimeout、readTimeout参数避免一个慢接口把调用线程拖死。公共的 DTO 放在 common 模块里两个服务都依赖 common这样 Feign 接口的返回类型不会因为包路径不一致导致序列化出错。3. Redis 缓存层落地商品详情缓存与分布式锁的取舍3.1 缓存粒度与 Key 设计为什么不整对象缓存商品详情是电商系统里读请求最密集的接口之一也是最容易把缓存写坏的地方。一个商品详情页面通常是聚合视图基础信息、SKU 列表、图片、富文本参数。如果偷懒把整个聚合结果塞进一个 key任何一个子模块更新都要重写这个大 key而且并发高的时候短时间内大量请求穿透到数据库缓存击穿的概率会明显上升。这套项目里用的是拆粒度缓存方案按数据更新频率拆成三个层级。缓存 Key内容过期时间product:base:{id}商品标题、上下架状态、品牌30 分钟 随机 0~5 分钟product:sku:{skuId}SKU 价格、库存、规格属性10 分钟product:images:{id}图片 ID 列表1 小时TTL 错开是防止缓存雪崩的常见做法如果所有 key 同时过期过期瞬间所有请求同时打到数据库数据库容易被压垮。过期时间加随机数本质是让失效时间在一个区间内分散开。还有一个值得照抄的细节查数据库没查到商品时不要直接返回往缓存里写一个空值并设置 3 到 5 分钟的短过期时间这样恶意刷不存在的商品 ID 时请求会打在缓存上而不是反复打数据库这招叫缓存空值防穿透。String key product:base: id; Object cached redisTemplate.opsForValue().get(key); if (cached ! null) { return (ProductBaseVO) cached; } ProductBaseDO product productMapper.selectById(id); if (product null) { redisTemplate.opsForValue().set(key, , 3, TimeUnit.MINUTES); return null; } ProductBaseVO vo convert(product); redisTemplate.opsForValue().set(key, vo, 30 RandomUtils.nextInt(5), TimeUnit.MINUTES); return vo;注意这里的类型转换隐患从 Redis 读出来的对象是Object直接强转前必须保证序列化器存进去的就是这个类型。空值回写时会遇到 String 与对象混存的问题所以我会在取值后判断是不是空字符串再返回否则会把强转成 VO 直接报类型转换异常。3.2 序列化策略与 RedisConfig调试友好是第一诉求Redis 的序列化器选择直接影响你排查问题的效率。默认的JdkSerializationRedisSerializer存进去的是二进制在 Redis Desktop Manager 里看到的全是\xAC\xED开头的乱码想确认某个 key 到底存了什么还得在代码里 debug。换成GenericJackson2JsonRedisSerializer之后value 是 JSON 文本肉眼可读跨服务共用也方便。Configuration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); GenericJackson2JsonRedisSerializer serializer new GenericJackson2JsonRedisSerializer(); template.setKeySerializer(RedisSerializer.string()); template.setHashKeySerializer(RedisSerializer.string()); template.setValueSerializer(serializer); template.setHashValueSerializer(serializer); template.afterPropertiesSet(); return template; } }key 用 String 序列化是为了在 Redis Desktop Manager 里能直接看到product:base:123这种可读的 keyvalue 用 JSON 是为了跨服务通用。要注意GenericJackson2JsonRedisSerializer会在 JSON 里写入class类型信息反序列化时靠它还原具体类型。代价是如果实体类改了包名或字段结构老缓存反序列化会直接报错所以实体结构变更时要么主动清掉相关缓存要么先把 TTL 调短等旧缓存自然过期。3.3 秒杀扣库存Redisson 分布式锁的看门狗与超时秒杀扣库存是分布式锁最典型的落地场景。第一反应用SETNX加EXPIRE两条命令实现的大多有锁超时设置不合理、忘记释放、误删别人锁的问题。尚品甄选这套用的是 Redisson它对锁续期和释放做了封装用起来比裸 Redis 命令可靠。RLock lock redissonClient.getLock(lock:seckill: skuId); boolean locked lock.tryLock(1, 10, TimeUnit.SECONDS); if (!locked) { throw new BusinessException(当前抢购人数太多请稍后再试); } try { int rows stockMapper.decrementStock(skuId); if (rows 0) { throw new BusinessException(库存不足); } } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } }tryLock(1, 10, TimeUnit.SECONDS)第一个参数是获取锁的等待时间拿不到锁就快速失败返回避免大量线程阻塞在抢锁上第二个参数是锁的持有时间到了自动释放防止业务异常导致死锁。但这里有个参数倾向如果业务执行时间有可能超过锁持有时间不要手工指定持有时间让 Redisson 走默认的 30 秒看门狗逻辑它会自动续期业务执行完再释放。isHeldByCurrentThread()判断是必须的防止锁已经过期被别的线程拿到当前线程释放时把别人的锁误删。热点商品的秒杀还可以给 key 加分区后缀把压力分散到多个 key 上但那是另一个复杂度话题新手先把单 key 锁跑通再去优化。4. MinIO 对象存储接入上传、预签名 URL 与反代访问4.1 桶规划与权限模型private 桶是底线MinIO 接入前先把权限模型想清楚否则后期改权限要连带改一堆代码。常见的翻车是把桶设成public图片 URL 直接拼在 HTML 里访问倒是方便但固定链接会被盗链、被刷流量而且桶里的文件一旦公开删除或替换都会立刻生效到线上。尚品甄选里我建议按用途拆分桶而不是一个桶装所有文件。桶名用途访问方式product-images商品主图、SKU 图、详情图private 预签名 URLproduct-files商品导入模板、批量素材包private 预签名 URL两个桶都是 private对外回显用预签名 URL这样每个文件的访问链接带签名参数过期后自动失效下载大批量文件时也不会因为链接缓存被反复刷。MinIO 的默认管理员账号是minioadmin/minioadmin容器部署时一定要用环境变量覆盖这个在第 5 章的坑位里会细说。4.2 上传接口实现与 SDK 参数坑MinIO 的 Java SDK 用法比较固定核心就三步构建客户端、检查桶、传对象。下面是本地开发环境的上传接口实现注意 endpoint 的写法。MinioClient client MinioClient.builder() .endpoint(http://localhost:9000) .credentials(minioadmin, your-password) .build(); if (!client.bucketExists(BucketExistsArgs.builder().bucket(product-images).build())) { client.makeBucket(MakeBucketArgs.builder().bucket(product-images).build()); } String objectName 2025/06/ UUID.randomUUID() .jpg; client.putObject(PutObjectArgs.builder() .bucket(product-images) .object(objectName) .stream(file.getInputStream(), file.getSize(), -1) .contentType(file.getContentType()) .build());endpoint这里要注意环境差异本地调试用localhost:9000但在 Docker Compose 网络里应用容器访问 MinIO 要用服务名http://minio:9000因为容器之间走的是内部网络localhost指向的是应用容器自己。stream的第三个参数是对象大小传入-1让 SDK 自动分片适合不确定大小的流如果明确知道文件大小最好传实际值上传性能更好。对象名按年/月/UUID组织避免所有文件堆在一个目录里也方便后面按时间归档。上传之后回显给前端的 URL 用预签名方式生成而不是直接暴露对象名。String presignedUrl client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder() .method(Method.GET) .bucket(product-images) .object(objectName) .expiry(3600) .build());expiry(3600)是 URL 的有效秒数一小时过期。产品图片和商品详情的配图可以给长一点比如 24 小时用户头像这种访问频繁的可以配合前端 CDN 缓存不建议给太长有效期否则链接泄露出去就能被人一直访问。预签名 URL 的生成不要求额外权限但生成出来的链接是带签名参数的泄露后对方拿到的也是限时访问权。4.3 图片回显与 nginx 反代配置预签名 URL 默认带的是 MinIO 的 endpoint前端直连 9000 端口容易被防火墙拦而且把 MinIO 的真实地址暴露给浏览器在安全上并不好看。常见做法是让前端只走应用域名用 nginx 把/minio/路径转发到 MinIO。location /minio/ { proxy_pass http://minio:9000/; proxy_set_header Host $http_host; }注意proxy_pass末尾的斜杠带斜杠表示把/minio/前缀剥掉后转发不带斜杠则是原样拼接。处理图片访问时前端拿到的链接就会变成http://你的域名/minio/product-images/xxx.jpg?X-Amz-...应用层可以通过反代统一加访问日志和流量控制。下载大文件时如果文件超过几百 MB直接走应用服务器转发会占内存和带宽更合理的做法是生成预签名 URL 后让浏览器 302 跳转过去应用只负责发跳转指令不承担文件流的转发。5. Docker 容器化部署compose 编排与五个高频坑排查记录5.1 Compose 编排基础设施与微服务healthcheck 是第一步Docker 部署这套项目最省事的路径是用 Docker Compose 把 MySQL、Redis、MinIO、Nacos 和业务服务编排在一起。第一次编排容易踩的坑是微服务启动比数据库快应用连不上数据库直接退出。所以healthcheck和depends_on必须配合使用。services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: shangpin ports: - 3306:3306 volumes: - mysql-data:/var/lib/mysql healthcheck: test: [CMD, mysqladmin, ping, -h, localhost] interval: 10s timeout: 5s retries: 5 redis: image: redis:7-alpine command: redis-server --appendonly yes ports: - 6379:6379 healthcheck: test: [CMD, redis-cli, ping] interval: 10s timeout: 5s retries: 5 minio: image: minio/minio command: server /data --console-address :9001 environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: your-password ports: - 9000:9000 - 9001:9001 volumes: - minio-data:/data user-service: build: ./user-service environment: NACOS_ADDR: nacos:8848 REDIS_HOST: redis MYSQL_HOST: mysql depends_on: mysql: condition: service_healthy redis: condition: service_healthydepends_on默认只保证启动顺序不保证服务可用加上condition: service_healthy才是真正等 MySQL 和 Redis 就绪后再启动业务服务。不写 healthcheck 的话应用启动时 Redis 还没就绪就会看到一堆连接超时报错。MySQL 数据挂到mysql-data卷里容器重建数据不丢MinIO 也一样它把数据写进/data卷必须挂否则重启容器后上传的图片全没了。5.2 多阶段构建与 JVM 内存参数业务服务的 Dockerfile 用多阶段构建构建阶段带 Maven 和 JDK运行阶段只留 JRE 和 jar镜像体积能明显降下来。FROM maven:3.9-eclipse-temurin-17 AS build WORKDIR /src COPY . . RUN mvn -B -DskipTests package FROM eclipse-temurin:17-jre COPY --frombuild /src/user-service/target/*.jar /app/app.jar EXPOSE 8101 ENTRYPOINT [java, -Xmx512m, -Xms256m, -jar, /app/app.jar]-Xmx512m设堆上限 512MB-Xms256m设初始堆 256MB。容器内存限制 1GB 时这个配置留了余量给 JVM 的元空间和线程栈不容易因为容器内存超限被 OOM Kill。如果你的服务接口并发高堆可以给到 768MB但容器内存也得跟着调到 1.5GB 以上。JVM 在容器里的内存计算经常被忽略-Xmx不等于容器内存两者之间要留足系统开销。5.3 高频坑排查五条按现象到原因到解决整理第一条Docker Desktop 启动失败提示virtualization support wasnt detected。现象是双击图标后直接报错服务起不来。原因是 Windows 的虚拟化功能没开或者 Hyper-V / WSL2 没启用。解决方法是进 BIOS 开启 Virtualization Technology然后在 Windows 功能里勾选「适用于 Linux 的 Windows 子系统」和「虚拟机平台」重启后再启动 Docker Desktop。第二条docker pull minio/minio拉不下来或者超时。现象是镜像下载卡在等待反复失败。原因是默认镜像源在本地网络下不通。解决方法是给 Docker 配置 registry-mirrors指向国内镜像站配置后重启 Docker Desktop 再拉取。第三条Redis 连接超时报io.lettuce.core.RedisCommandTimeoutException。现象是应用一启动就连 Redis 报错过一会儿又正常。原因是容器启动顺序没控制Redis 还没有就绪应用连接池里的连接全部超时。解决方法是给 redis 服务加 healthcheck业务服务的depends_on加condition: service_healthy另外检查连接池最大连接数不要默认无限并发高时连接池耗尽也会有类似的超时。第四条MySQL 8 连接失败报Access denied或者Public Key Retrieval is not allowed。现象是应用日志里反复出现连接异常。原因是 MySQL 8 默认认证插件是caching_sha2_password连接 URL 没有对应参数。解决方法是 JDBC URL 加上allowPublicKeyRetrievaltrueuseSSLfalse或者在容器初始化脚本里创建用户时指定mysql_native_password。第五条MinIO 改了MINIO_ROOT_USER和MINIO_ROOT_PASSWORD环境变量后旧账号还是能登录。现象是改完重启容器用新账号登不上旧账号依然有效。原因是 MinIO 的账号密码是在数据卷首次初始化时写入的卷已经存在环境变量不会再生效。解决方法是先docker compose down -v清掉旧数据卷再重建容器或者进入容器用mc客户端修改账号信息。这个坑最容易在改完配置重启后发现没变化白改半天。6. 订单状态机与缓存一致性一个能救命的双写校验技巧6.1 订单状态机的幂等设计订单模块是整个电商系统里最容易出线上问题的部分核心不在于 CRUD 写得多花哨而在于状态流转是否被严格约束。这套源码里订单状态用枚举收敛配合数据库版本号做乐观锁能挡住大部分重复请求。public enum OrderStatus { CREATED(0), PAID(1), SHIPPED(2), FINISHED(3), CANCELLED(4); private final int code; OrderStatus(int code) { this.code code; } public boolean canTransitTo(OrderStatus target) { return switch (this) { case CREATED - target PAID || target CANCELLED; case PAID - target SHIPPED || target CANCELLED; case SHIPPED - target FINISHED; case FINISHED, CANCELLED - false; }; } }状态机的好处是非法流转在业务代码入口就被拦住而不是等到数据库里出现脏数据才暴露。支付回调这类外部通知天然会重试所以更新订单状态时不能先查再改要用条件更新做 CASUPDATE orders SET status ?, version version 1 WHERE id ? AND status ? AND version ?更新行数为 0 说明状态已变直接幂等返回不重复执行后续发货逻辑。6.2 缓存与数据库的双写校验脚本订单状态更新后一般会同步写 Redis 缓存。如果缓存删除失败DB 和 Redis 就分叉了数据库已经是 PAID缓存还是 CREATED用户刷新订单详情会看到旧状态。为了能快速发现这种不一致我习惯在每次涉及订单状态变更的上线窗口跑一个双写校验脚本。# 1. 导出数据库订单状态分布 mysql -h$DB_HOST -u$DB_USER -p$DB_PASS -e \ SELECT status, COUNT(*) FROM orders GROUP BY status; /tmp/db_status.txt # 2. 扫描 Redis 中订单缓存 key按状态分组统计 redis-cli --scan --pattern order:info:* | head -n 5000 | while read key; do redis-cli hget $key status /tmp/redis_status.txt done sort /tmp/redis_status.txt | uniq -c这个脚本的思路是先把数据库的状态分布导出再抽样扫描 Redis 里的订单缓存对比两者状态的数量分布是否大致吻合。如果 Redis 里大量出现数据库里不存在的状态值说明有缓存没被正确更新。真正生产上我会把它做成定时任务发现不一致就删除对应缓存 key让下一次读请求回源数据库重新加载而不是手工在线上改数据。从那以后每次上线涉及订单状态变更我都强制跑一遍这个扫描确认缓存里没有旧状态的残留再放量。这套尚品甄选源码里的订单模块本身已经把状态机收敛得不错你自己改业务时记得把这条校验链路也带上。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

拒绝羡慕 Cursor!Xcode 自己也能利用 AI 大模型让撸码如虎添翼【超详细配置】

拒绝羡慕 Cursor!Xcode 自己也能利用 AI 大模型让撸码如虎添翼【超详细配置】

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/7 14:23:11
AI 编程智能体大比拼 2026:四种架构与选型指南(TaoToken 统一 Key 接入版)

AI 编程智能体大比拼 2026:四种架构与选型指南(TaoToken 统一 Key 接入版)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/7 14:23:11
Spring Boot 3.4.1与Vue3博物馆文创商城:实现要点与避坑指南

Spring Boot 3.4.1与Vue3博物馆文创商城:实现要点与避坑指南

简介:一份面向计算机专业学生、Java开发者及毕业设计作者的博物馆文创产品在线销售系统完整资源包。系统基于Spring Boot 3.4.1与Vue3搭建,后端采用Java实现安全身份验证、商品管理、购物车、订单生成与支付、物流跟踪等业务流程;前端以Vue3组…

📅 2026/10/7 14:23:11
MORE NEWS

更多资讯

📰

学习通刷课脚本全解析:Selenium自动化播放与FontTools字体解密实战

简介:一套基于 Python 的学习通自动刷课脚本源码,面向希望借助自动化完成平台课程任务、减少重复点击的学习者,也适合想在 Selenium 浏览器操作和 fonttools 字体处理上做实践参考的 Python 开发者。资源包共 27 个文件、约 2.41MB&#xff0…

📰

Obsidian图文写作流水线:从Workflow到Skill,Token成本直降七成

1. 从Workflow到Skill:一次被Token账单逼出来的架构调整去年下半年我开始用Obsidian搭自己的图文写作流水线,核心诉求很简单:把零散的素材、大纲、配图说明、发布文案串成一条自动化的链路。最开始我走的是Workflow路线——用插件把多个动作串…

📰

零依赖纯文本知识库:用文件夹+Git搭建永不过期的个人笔记系统

caveman 是我最近一直挂在嘴边的一个小项目代号,外号叫“穴居人方案”。圈子里偶尔看到叫 caveman 的工具或开源项目,思路大多差不多:把知识管理这件事打回原形,不用花哨的 App,不用云端数据库,就用文件夹、…

📰

Obsidian插件Superpowers详解:从安装配置到高效文本编辑技巧

1. 为什么 Obsidian 玩家都在聊 Superpowers如果你是个 Obsidian 重度用户,最近逛社区或插件市场时应该会频繁撞见“Superpowers”这个名字。它不是一个让你在笔记里写代码开外挂的神秘工具,而是一个把 Obsidian 原生的文本编辑、搜索、滚动、书签这些基…

📰

ARCGIS学习笔记(一):计算几何中面积被禁用?用TaoToken统一Key跑通Python面积求和

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

玩转 OpenClaw:用 Skill 系统搭建专属 AI 工作流的 TaoToken 实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬