尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Spring Boot 实战:流浪宠物管理系统开发与部署全流程
简介基于 Spring Boot 的 Java Web 流浪宠物管理系统毕业设计资料包面向高校毕业设计学生、Java Web 初学者及流浪宠物救助站工作人员。系统覆盖宠物档案、救助进度、志愿者信息等核心模块实现宠物信息录入、查询、统计与分析并支持志愿活动发布可帮助救助组织更高效地统筹资源、推进救助进度。资源以 RAR 压缩包提供约 28.53MB主体为系统源代码与配套毕业论文论文详细阐述设计思路、实现过程与关键技术适合项目复现、毕业设计参考或二次扩展。压缩包内文件清单未在页面展示可在下载后按目录查看。已有 182 人学习浏览。通过该资料可掌握 Spring Boot 与前端页面的整合开发方法并获得可运行的宠物管理项目案例对理解 Java Web 项目结构、数据库设计和业务实现有直观参考价值。1. 用 Spring Boot 做 JavaWeb 流浪宠物管理系统先确定边界再动手还没开始写代码前先想清楚这套系统的边界。标题里同时出现 JavaWeb、Spring Boot、源代码和毕业论文意味着它要交付的不是一个能跑通的最小 demo而是一套结构完整、能部署、能演示、能写成文档的完整管理系统。流浪宠物管理系统的业务主线并不复杂核心是宠物档案、领养申请、用户权限和公告信息这几块但真正拉开档次的地方在于表结构设计是否严谨、领养申请的状态流转是否闭环、图片上传在本地环境和服务器环境下是否都能正常工作。这些点才是答辩时评委和面试官真正会追问的地方。本文会沿着这套系统的主线从数据建模讲到分层代码实现再落到三个最容易出错的功能模块和部署排错清单。新手可以按照章节顺序把项目从零搭起来有 Spring Boot 经验的同学可以直接跳到最后两章重点看状态机、上传路径和自动建表这些容易翻车的边界。2. 流浪宠物管理系统的数据模型表设计定到字段级别2.1 JavaWeb 项目为什么普遍选择 Spring Boot 作为基础框架流浪宠物管理系统这类 JavaWeb 管理系统近几年的主流实现方式已经从传统的 SSMSpring SpringMVC MyBatis逐步迁移到 Spring Boot。这不是单纯追赶技术热点而是 Spring Boot 确实更适合中小型管理系统的交付节奏内嵌 Tomcat 让项目不再需要单独部署 war 包starter 依赖机制把过去繁琐的 XML 配置压缩成少量配置项自动装配机制则让数据源、事务、JSON 序列化这些基础设施开箱即用。但这不意味着可以完全不懂底层原理。Spring Boot 的自动配置是约定优先当实际环境与约定不一致时排错难度反而比传统 SSM 更高。举一个常见例子数据源配置里的driver-class-name如果写成老版本的com.mysql.jdbc.Driver在 MySQL 8 驱动下启动就会警告甚至报错serverTimezone不设置为 Asia/Shanghai连接时又会出现时区异常。这些都属于 Maven 依赖没问题、代码逻辑没问题、纯粹配置细节卡壳的情况后面 3.3 节会专门列一份参数表。持久层方面MyBatis 和 MyBatis-Plus 是 JavaWeb 项目里最常见的两个选择。MyBatis 胜在 SQL 完全自主可控适合需要写复杂联表查询的场景MyBatis-Plus 则在单表 CRUD 上几乎不用写 SQL内置分页插件和条件构造器对开发效率提升明显。流浪宠物管理系统的数据量不大单表操作占比高论文里要写出来的查询逻辑也比较模式化用 MyBatis-Plus 能让代码更紧凑答辩时也容易讲明白。2.2 核心表拆分用户、宠物、领养申请、公告这套系统里最核心的实体是宠物和领养申请用户表负责支撑登录和管理员身份公告表用来填充首页信息。先看建表语句再逐个说明字段约束的理由。CREATE DATABASE IF NOT EXISTS pet_db DEFAULT CHARACTER SET utf8mb4; USE pet_db; CREATE TABLE IF NOT EXISTS sys_user ( id BIGINT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL COMMENT 登录名, password VARCHAR(100) NOT NULL COMMENT BCrypt加密后的密码, nickname VARCHAR(50) DEFAULT COMMENT 显示昵称, phone VARCHAR(20) DEFAULT , role TINYINT NOT NULL DEFAULT 0 COMMENT 0-普通用户 1-管理员, avatar VARCHAR(255) DEFAULT , create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_username (username) ) ENGINEInnoDB COMMENT 系统用户表; CREATE TABLE IF NOT EXISTS pet ( id BIGINT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL COMMENT 宠物昵称, species VARCHAR(30) NOT NULL COMMENT 品种如 中华田园猫/金毛, gender TINYINT DEFAULT 0 COMMENT 0-公 1-母, age_months INT NOT NULL DEFAULT 1 COMMENT 月龄, vaccine TINYINT DEFAULT 0 COMMENT 是否已接种 0-未 1-已, health_status VARCHAR(100) DEFAULT COMMENT 健康状况描述, status TINYINT NOT NULL DEFAULT 0 COMMENT 0-待领养 1-已领养 2-已下架, cover VARCHAR(255) DEFAULT COMMENT 封面图URL, detail_address VARCHAR(255) DEFAULT COMMENT 发现地点或收容地点, publish_user_id BIGINT NOT NULL COMMENT 发布人ID通常是管理员, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, version INT NOT NULL DEFAULT 0 COMMENT 乐观锁版本号, KEY idx_status (status), KEY idx_species (species) ) ENGINEInnoDB COMMENT 流浪宠物信息表; CREATE TABLE IF NOT EXISTS adoption_record ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL COMMENT 申请人ID, pet_id BIGINT NOT NULL COMMENT 宠物ID, status TINYINT NOT NULL DEFAULT 1 COMMENT 1-待审核 2-审核通过 3-已完成 4-已驳回, apply_reason VARCHAR(500) DEFAULT COMMENT 申请理由, audit_remark VARCHAR(200) DEFAULT COMMENT 审核备注, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, audit_time DATETIME DEFAULT NULL, UNIQUE KEY uk_user_pet (user_id, pet_id) ) ENGINEInnoDB COMMENT 领养申请表; CREATE TABLE IF NOT EXISTS notice ( id BIGINT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(100) NOT NULL, content TEXT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB COMMENT 公告表;字段设计上有几个值得较真的点。第一状态字段全部使用 TINYINT 数字字典而非字符串status的语义在 Java 层用常量或枚举维护数据库中不存中文避免字符集差异和拼写不一致问题。第二version字段是为乐观锁准备的后续领养审核更新时会用到初期不建这个字段后面对并发案例没法讲。第三adoption_record上加了唯一索引uk_user_pet防止同一用户对同一只宠物重复提交申请这是数据库层面的硬约束比在业务代码里 if 判断可靠得多。用户表和宠物表之间没有建立物理外键只保留逻辑引用关系。原因有两点物理外键在删除关联数据时会互相掣肘比如管理员删除一个已经被申请过的宠物档案有外键约束就必须先处理申请记录而毕业设计里更看重业务逻辑的自洽解释。答辩时被问到外键问题时回答“引用完整性由应用层保证外键保留在逻辑设计中”是站得住的。2.3 初始数据与自动建表参数让新环境一条命令跑起来Spring Boot 本身不做自动建表MyBatis-Plus 同样只管持久层不负责 DDL所以不少第一次接触 Spring Boot 的人会困惑明明代码没错为什么Table doesnt exist。常见的做法是准备两个 SQL 文件放在src/main/resources/sql/目录下schema.sql负责建表data.sql负责写入初始管理员账号和演示数据然后在application.yml里开启 SQL 初始化。spring: sql: init: mode: always schema-locations: classpath:sql/schema.sql >com.example.pet ├── PetApplication.java ├── common │ └── Result.java ├── config │ ├── WebConfig.java │ └── MybatisPlusConfig.java ├── controller │ ├── UserController.java │ ├── PetController.java │ ├── AdoptionController.java │ └── UploadController.java ├── entity │ ├── User.java │ ├── Pet.java │ └── AdoptionRecord.java ├── mapper │ ├── UserMapper.java │ ├── PetMapper.java │ └── AdoptionRecordMapper.java ├── service │ ├── PetService.java │ └── impl │ └── PetServiceImpl.java └── resources ├── application.yml └── mapper └── PetMapper.xml分层规则上我一般保持三条底线Controller 只做参数接收、调用 Service、包装返回值不直接操作数据库Service 层承载业务规则和事务边界Mapper 层只负责 SQL 与数据库交互XML 里的 SQL 不允许出现业务判断。这样做的直接好处是出问题时定位快比如某个列表数据不对先在 Controller 里确认入参再去 Service 看过滤条件最后查 XML 里的 SQL三步就能锁定问题。3.2 统一返回体与宠物分页查询一套可以复用的代码骨架先写统一返回体后续所有接口都用它包装前端判断code是否为 200 即可public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT r new Result(); r.code 200; r.message 操作成功; r.data data; return r; } public static T ResultT fail(String message) { ResultT r new Result(); r.code 500; r.message message; return r; } // getter/setter 省略 }宠物分页接口是这套系统最典型的列表查询完整链路从 Controller 到 Mapper 依次实现。Controller 接收当前页、每页条数和搜索关键字RestController RequestMapping(/api/pet) public class PetController { Resource private PetService petService; GetMapping(/list) public ResultPagePet list(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(required false) String keyword, RequestParam(required false) Integer status) { return Result.success(petService.queryPage(pageNum, pageSize, keyword, status)); } }Service 实现里用 MyBatis-Plus 的 LambdaQueryWrapper 构造动态查询条件Service public class PetServiceImpl extends ServiceImplPetMapper, Pet implements PetService { Override public PagePet queryPage(Integer pageNum, Integer pageSize, String keyword, Integer status) { PagePet page new Page(pageNum, pageSize); LambdaQueryWrapperPet wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.hasText(keyword), Pet::getName, keyword) .eq(status ! null, Pet::getStatus, status) .orderByDesc(Pet::getCreateTime); return this.page(page, wrapper); } }这段代码里的LambdaQueryWrapper是 MyBatis-Plus 的条件构造器第一个参数是布尔表达式为 true 时才拼接对应条件。StringUtils.hasText(keyword)保证关键字为空时不拼LIKE条件status ! null保证未选择状态下不限制状态动态 SQL 的逻辑从这里就能全部看懂。如果要写原生的多表联查则需要在PetMapper.xml里定义 SQL 并通过Mapper注解注入XML 方式的优势是复杂查询结果能直接映射到 VO 对象。3.3 application.yml 配置参数数据源与 MyBatis 易错项汇总这一份配置几乎可以直接用于流浪宠物管理系统的本地开发server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/pet_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: ${DB_USER:root} password: ${DB_PASSWORD:123456} servlet: multipart: max-file-size: 10MB max-request-size: 20MB mybatis-plus: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl数据源 URL 里几个参数再过一遍useUnicodetruecharacterEncodingutf8保证中文写入不乱码serverTimezoneAsia/Shanghai解决 MySQL 8 驱动的时区报错不配会抛The server time zone value异常useSSLfalse因为本地开发环境通常没有配置 SSL 证书allowPublicKeyRetrievaltrue是 MySQL 8 配合 caching_sha2_password 认证方式的常见要求否则连接时报公钥检索失败。${DB_USER:root}是环境变量占位符的标准写法冒号后面的root是默认值。项目交付时把数据库口令放在环境变量里源码包中只保留这一个占位符这样即使源码外传数据库口令也不会直接暴露。map-underscore-to-camel-case负责把数据库的create_time自动映射为实体的createTime关闭后所有字段映射都要手动配置TableField是新手最容易踩的坑。StdOutImpl会把执行的 SQL 和参数直接打到控制台开发期很实用部署时改成 Slf4j 或直接关闭。分页插件也需要显式配置MyBatis-Plus 默认不启用分页拦截器Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }没有这个 BeanPage对象传进 Service 后分页不会生效查询结果依然是全表数据这是一个非常隐蔽的配置漏项。开发中遇到列表接口数据量不对先检查拦截器是否注册。3.4 登录与权限拦截器够用不用一上来就上 Security流浪宠物管理系统的角色只有普通用户和管理员两种用 HandlerInterceptor 加 Session 完全可以覆盖。登录接口校验用户名密码通过后写入 Session拦截器里判断 Session 是否存在对于/admin/**路径再校验role是否为 1。Spring Security 对这个体量的项目来说太重过滤器链的配置和权限表达式会让答辩讲偏但简历里如果写了熟悉 Spring Security不妨把 Premi 注解部分补充了解。拦截器写好后要记得在 WebConfig 里注册并且放行登录接口、静态资源和/upload/**图片访问路径Configuration public class WebConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns(/**) .excludePathPatterns(/api/user/login, /upload/**, /api/pet/list); } }这里的addPathPatterns和excludePathPatterns都是路径匹配规则放行的三个路径分别是登录接口、宠物图片静态资源、游客可见的宠物列表。如果漏了/upload/**就会出现图片加载 302 跳转到登录页的怪问题。4. 图片上传、申请状态机、搜索列表三个实战要点4.1 宠物图片上传数据库只存路径文件落盘到独立目录宠物图片是流浪宠物管理系统的刚需功能但也是实现方式最容易出问题的部分。基本原则是文件保存到服务器磁盘或对象存储数据库只保存访问 URL绝不能把图片字节塞进数据库字段。本地开发环境下采用本地目录存储加静态资源映射的方式最直接。RestController RequestMapping(/api/upload) public class UploadController { Value(${pet.upload-path}) private String uploadPath; PostMapping(/image) public ResultString uploadImage(RequestParam(file) MultipartFile file) { String originalFilename file.getOriginalFilename(); String ext originalFilename.substring(originalFilename.lastIndexOf(.)); String filename System.currentTimeMillis() _ UUID.randomUUID() ext; File dest new File(uploadPath filename); try { file.transferTo(dest); return Result.success(/upload/ filename); } catch (IOException e) { return Result.fail(图片上传失败); } } }上传后的访问路径通过资源映射对外暴露Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceLocations(file: uploadPath); }uploadPath在 application.yml 中配置为绝对路径例如本机 Windows 下的D:/pet_upload/Linux 下则是/opt/pet_upload/注意两种系统的路径分隔符差异。这里最大的坑有两个一是配置相对路径时当前工作目录不同会导致文件找不到所以只推荐绝对路径二是上传文件不能存到src/main/resources/static/upload/下因为项目重新打包后这个目录会被替换之前上传的图片全部丢失。multipart.max-file-size限制单张图片大小示例配置里是 10MB。4.2 领养申请的状态闭环事务加条件更新防并发领养申请是整个系统的业务核心状态设计为四个值1 待审核、2 审核通过、3 已完成、4 已驳回。用户提交申请、管理员审核、用户确认领养的完整流程必须闭环否则会出现宠物已被领养还能被申请的脏数据。审核通过方法的实现要点如下Transactional(rollbackFor Exception.class) public boolean audit(Long recordId, Integer targetStatus, String auditRemark) { // 1. 查询当前申请记录 AdoptionRecord record this.getById(recordId); if (record null || record.getStatus() ! 1) { throw new RuntimeException(申请记录不存在或已被处理); } // 2. 条件更新宠物状态防止并发审核同一只宠物 int updated petMapper.updateStatusIfWaiting(record.getPetId()); if (updated 0) { throw new RuntimeException(宠物已被其他申请占用); } // 3. 更新申请状态 LambdaUpdateWrapperAdoptionRecord wrapper new LambdaUpdateWrapper(); wrapper.eq(AdoptionRecord::getId, recordId) .eq(AdoptionRecord::getStatus, 1) .set(AdoptionRecord::getStatus, targetStatus) .set(AdoptionRecord::getAuditRemark, auditRemark) .set(AdoptionRecord::getAuditTime, LocalDateTime.now()); return this.update(wrapper); }Transactional声明事务边界方法内任何一步抛出 RuntimeException数据库操作全部回滚。第二步的updateStatusIfWaiting是重点对应的 SQL 类似UPDATE pet SET status 1, version version 1 WHERE id #{petId} AND status 0通过 WHERE 条件里的状态判断保证两个管理员同时审核同一只宠物时只有一个请求能更新成功影响行数为 0 的请求直接抛异常。这种条件更新比先查再判断更可靠因为查出结果到执行更新之间存在时间窗口并发下会出问题。数据库唯一索引uk_user_pet在用户提交申请时兜底重复提交直接抛 DuplicateKeyExceptionService 层捕获这个异常后给前端返回友好提示而不是暴露堆栈。4.3 搜索列表带联表统计分页与关键字过滤一起处理宠物列表页通常会显示每只宠物被申请的次数这个数据来自adoption_record表。在 PetMapper.xml 里写联表 SQLselect idselectPetListWithApplyCount resultTypecom.example.pet.vo.PetVO SELECT p.*, (SELECT COUNT(*) FROM adoption_record a WHERE a.pet_id p.id) AS apply_count FROM pet p where if testkeyword ! null and keyword ! AND (p.name LIKE CONCAT(%, #{keyword}, %) OR p.species LIKE CONCAT(%, #{keyword}, %)) /if if teststatus ! null AND p.status #{status} /if /where ORDER BY p.create_time DESC /select子查询统计申请次数的写法在这个数据量级别完全够用apply_count映射到 PetVO 里的额外字段。LIKE CONCAT(%, #{keyword}, %)用 CONCAT 拼接而不是在业务层拼好字符串再传入目的是避免 SQL 注入风险。where标签自动处理第一个条件前的 AND关键字和状态条件都是可选参数与 3.2 节的 LambdaQueryWrapper 互为补充单表查询用 Wrapper联表统计用 XML两个方案都要会。5. 源码交付前用这几条把环境与部署坑排查干净5.1 冷启动验证顺序一个新环境下拿到这份源代码按固定顺序验证可以省掉大量排错时间。先确认 MySQL 已启动且能通过命令行登录执行CREATE DATABASE pet_db DEFAULT CHARACTER SET utf8mb4;创建空库然后直接执行mvn spring-boot:run启动项目。观察启动日志里是否有Table pet_db.sys_user doesnt exist或 SQL 初始化失败的信息没有异常后再访问宠物列表接口确认分页正常、中文不乱码。建议在项目里集成 springdoc-openapi启动后访问/swagger-ui.html就能看到全部接口比手工拼 URL 测试效率高很多。5.2 新环境排错对照表症状常见原因处理方式BindException: Port already in use8080 端口被占用修改server.port或释放原端口Access denied for user rootlocalhost数据库账号密码错误核对spring.datasource.username/password与 MySQL 实际账号Unknown database pet_db数据库未创建手工执行建库语句Invalid bound statement (not found)Mapper XML 没被扫描到检查mapper-locations路径和 XML namespace 是否与接口全限定名一致Table doesnt exist自动建表未生效确认spring.sql.init.modealways且 data.sql 执行顺序在 schema.sql 之后The server time zone value异常数据源 URL 缺少时区参数拼接serverTimezoneAsia/Shanghai这里面Invalid bound statement出现频率最高多为 XML 文件存放位置不对或 namespace 少了一个包名层级调整mapper-locations后再试。5.3 数据库口令不落盘的小改进源码包在交付和传播过程中大概率会被其他人看到application.yml里直接写明文数据库密码并不是好习惯。把配置改成${DB_PASSWORD:123456}的形式本地开发依赖冒号后的默认值部署到服务器时通过环境变量注入真实口令jar 包内不出现任何明文连接信息。这一步既不影响本地开发又能避免数据库口令随源代码一起扩散交付时也能在同龄人的项目里体现差异化。本文还有配套的精品资源点击获取
RELATED

相关推荐

GD25Q80E实战:从SPI时序到STM32 QSPI外设完整指南

GD25Q80E实战:从SPI时序到STM32 QSPI外设完整指南

每次有同学拿着开发板跑来问“我想外挂一颗Flash,GD25Q80E和W25Q16选哪个”,我都会先反问一句:你打算让它存什么?字库、固件、参数还是日志?别看SPI NOR Flash的命令表翻来覆去就那么十几条,很多人折腾一整…

📅 2026/9/17 8:31:05
五层级领导力实战:从职位权力到价值观感召

五层级领导力实战:从职位权力到价值观感召

1. 领导力层级的本质解析领导力并非与生俱来的天赋,而是一种可以通过系统学习和实践不断提升的能力。在我十五年的团队管理实践中,深刻体会到领导力的提升就像攀登一座五层高塔,每一层都需要不同的技能和心态转变。最基础的领导力来自职位赋予…

📅 2026/9/17 8:31:05
SpringBoot+Vue城中村流动人口管理系统设计与实践

SpringBoot+Vue城中村流动人口管理系统设计与实践

1. 项目背景与需求分析城中村流动人口管理一直是基层治理的难点痛点。以松北村为例,这个典型的城乡结合部聚集了超过2万名外来务工人员,但房东们还在用纸质本子记录租客信息,村委会掌握的数据往往滞后3-6个月。去年疫情期间,光是排…

📅 2026/9/17 8:31:05
MORE NEWS

更多资讯

📰

用Astra一次性生成像素游戏:从提示词设计到手感调优的实战工作流

最近我把一个存了很久的想法落地了:用 Astra 做一款像素游戏,关键要求是“一次性生成”。不是让它聊聊天、出几个代码片段,而是给出明确需求,一次拿到一个能直接跑起来、能玩、手感还过得去的完整网页小游戏。跑了几天&#xff0c…

📰

BMS算法全解析:从SOC估算到均衡控制与机器学习落地

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

📰

链路聚合LACP的隐性陷阱:单链路故障如何引发全网震荡与加固方案

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

📰

Citus分布式集群搭建与性能调优实战:从单机PostgreSQL到分片集群

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

📰

嵌入式面试I2C与SPI协议级故障诊断实战

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

📰

C# WPF在半导体工控系统中的实时性实战

1. 项目概述:这不是一个“写个界面”的练习,而是一套嵌入产线的工业神经中枢“重庆教主硬核实战”这个前缀不是噱头,是实打实的现场烙印——它意味着这套系统从设计第一天起,就踩在洁净车间的地砖上,听着晶圆传送带的伺…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

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

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

📞 💬