news 2026/10/8 23:59:14

律所案件管理系统开发实战:Spring Boot+Vue前后端分离全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
律所案件管理系统开发实战:Spring Boot+Vue前后端分离全解析

上个月帮朋友所在的律所搭了一套案件管理系统,前后端分离,Spring Boot + Vue + MyBatis + MySQL这套组合。做之前我以为难点在于案件数据怎么建模,做完才发现,真正的门槛在于“案件状态”怎么流转、不同角色能看到什么数据、以及前后端联调时那堆跨域和格式的破事。这篇文章我把整套项目的需求拆解、数据库设计、后端接口、前端页面、部署流程全部写出来,源码也会整理成完整工程放在文末说明里,照着跑就能起来。

这套系统适合三类人:一是律所或中小型服务机构想找个内网案件管理底座的人,二是正在做毕业设计、需要前后端分离实战项目的学生,三是想搞明白Spring Boot和Vue这两个生态怎么真正配合工作的开发者。我不会只贴代码,会更侧重“为什么这么设计”,这样你拿到源码之后才能改得动、扩得开。

1. 律所案件管理到底在管什么:需求拆解是第一优先级

很多团队一上来就画表、写Controller,结果做到一半发现律师要的“审批流”和案管要的“结案归档”根本对不上。所以我先花了两天把真实业务捋清楚,再做设计。

1.1 角色与权限:谁能看到哪个数据

律所里至少有四类角色,权限边界非常明确:

  • 主任/合伙人:跨案件查看业绩、审批收案和结案、看收费情况。
  • 承办律师:只能看自己承办或协办的案件,录进展、传文书、提交归档。
  • 律师助理:帮律师录当事人信息、整理证据材料、登记开庭提醒,但看不到案件毛利。
  • 前台/行政:负责咨询登记、立案信息录入、收费登记,不能看到律师的内部评注。

这套权限模型我用的是“角色-菜单-按钮”三层,后端在JWT里带上角色字段,前端根据角色渲染菜单和按钮。后端接口层面再用Spring AOP做权限注解,没有权限的直接返回403,不能只靠前端隐藏按钮——那样太脆了。

1.2 案件的生命周期:一个状态机的价值

案件不是一条静态记录,它有一个生命周期,每一步都会改变它可用的操作和字段。我们最终把案件状态机简化成六个节点:

  1. 咨询登记:来访或电话咨询,只记录当事人基本信息和案情摘要。
  2. 待审批:律师决定收案,填写收费方案、利益冲突检索结果,提交主任审批。
  3. 承办中:审批通过后正式立项,分配承办律师和助理。
  4. 已结案:判决/调解/和解/撤诉等结案方式确认,填写结案报告。
  5. 已归档:纸质卷宗和电子材料归档,案件进入历史库。
  6. 已作废:审批不通过或当事人放弃委托,保留记录但不参与统计。

这个状态机既简单又可扩展。比如将来想加“二审”或者“执行”阶段,只需要在状态枚举里新增节点,再在状态流转表里配置新路径就行,不用动表结构。

1.3 模块划分:六个业务模块加一个系统管理

我最终把系统拆成了七个模块,每个模块只负责一组明确的职责:

  • 案源管理:咨询登记、历史咨询跟进。
  • 案件管理:收案审批、案件台账、结案归档。
  • 当事人管理:自然人/法人档案、关联案件。
  • 文书管理:起诉状、答辩状、代理词、证据清单等模板和上传文件。
  • 开庭管理:开庭排期、地点、法官、提醒。
  • 收费管理:固定收费、风险代理分段收费、开票状态。
  • 系统管理:用户、角色、菜单、字典、操作日志。

模块划分的原则是“一个模块只回答一个问题”。比如“开庭提醒”为什么不放在“案件管理”里?因为一个案件可能有多个开庭节点,而且开庭信息还要同步给多个助理,单独成模块之后权限和数据归属都清晰很多。

2. 技术栈为什么是“Spring Boot + Vue + MyBatis + MySQL”这套组合

做技术选型的时候我其实纠结过要不要用FastAPI或者Go,但考虑到要部署到律所自己的Windows服务器、后续维护的人也未必是资深后端,最后敲定了Java系最稳妥的Spring Boot + MyBatis + MySQL,前端用Vue 3 + Element Plus。

2.1 前后端分离的真正优势

前后端分离对这类“内网业务系统”的价值,不只是“页面和接口分开写”,而是可以独立部署、独立扩展、独立排障:

  • 后端只提供JSON接口,不关心页面长什么样。
  • 前端是纯静态资源,可以放在Nginx里,也可以扔到任何一个静态文件服务器。
  • 业务变化时,后端加接口不影响前端整体发布;前端改页面不影响后端运行。
  • 团队协作时,前端可以Mock接口并行开发,不用等后端写完才能干活。

当然代价也有——跨域、Token传递、接口文档维护这些问题是分离后才出现的。我在第6章和第7章会详细讲这些坑。

2.2 和传统“单体JSP/SSM模板”方案对比

很多老系统用的是Spring MVC + JSP,页面和服务端混在一起。我做了个简单对比,方便你判断为什么前后端分离是更适合这个项目的选择:

对比项前后端分离(本项目)传统JSP/Thymeleaf单体
前后端耦合只通过JSON接口交换数据页面嵌在后端模板里
部署方式前端静态资源 + 后端Jar独立部署整个打成WAR放Tomcat
团队协作前端/后端可并行开发前端改动要重启应用
扩展性接口可复用给App、小程序几乎只能服务Web页面
调试体验Chrome DevTools看Network即可服务端渲染HTML,报错混在一起

如果你的系统里没有特别强的SEO需求、也不是那种几千个后端模板页面的老系统,前后端分离基本是当前最稳妥的默认选择。

2.3 项目目录结构:一上来就分开

工程我分成两个顶级目录,前后端完全独立,不要放在同一个工程里互相污染。

lawyer-case-system/ ├── backend/ # Spring Boot后端 │ ├── src/main/java/com/lawfirm/ │ │ ├── common/ # 统一返回、异常处理、工具类 │ │ ├── config/ # CORS、MyBatis、拦截器配置 │ │ ├── security/ # JWT拦截器、权限注解 │ │ ├── module/ # 按业务模块分包 │ │ │ ├── caseinfo/ │ │ │ ├── party/ │ │ │ ├── document/ │ │ │ ├── session/ │ │ │ ├── fee/ │ │ │ └── system/ │ │ └── LawfirmApplication.java │ └── src/main/resources/ │ ├── mapper/ # MyBatis XML文件 │ ├── application.yml │ └── db/init.sql # 建表脚本和初始化数据 └── frontend/ # Vue3 + Vite + Element Plus ├── src/ │ ├── api/ # 按模块封装的请求方法 │ ├── router/ # 路由表 │ ├── store/ # 用户状态、菜单状态 │ ├── views/ # 页面组件 │ └── components/ # 通用组件 └── vite.config.ts

这样拆的好处是,后端的mapper和前端页面都能按模块名字快速定位,新增一个“证据管理”模块时,两边各加一个目录就完事。

3. 数据库设计:把“案件状态机”建明白,后面代码都是体力活

数据库是整个项目的地基。很多人做管理系统喜欢追求表数量多、字段堆满,我反而建议把核心表收敛在可控范围内,把字段含义设计到位。

3.1 五张核心业务表

最终核心表是以下六张,每张表都和外键关系尽可能简洁:

表名用途关键字段
sys_user系统用户(登录/角色)username, password, role_id, lawyer_no
case_info案件主表case_no, case_name, case_type, status, fees, judge, create_by
case_party当事人表(一个案件多当事人)case_id, party_type, party_name, id_card, phone
case_document文书/证据材料case_id, doc_type, file_name, file_path, upload_by
court_session开庭记录case_id, session_time, court_place, judge, reminder_status
case_fee收费记录case_id, fee_type, total_amount, paid_amount, invoice_status

为什么把当事人单独抽出来而不是直接挂在案件表里?因为一个案件至少两方当事人(原告和被告),还可能追加第三人,一个当事人也可能关联多个案件。不抽表的话,要么字段冗余,要么就只能存一个当事人的名字。

3.2 案件状态流转与业务约束

状态机在数据库里我实现成两步:

  1. case_info.status字段存当前状态,值对应枚举常量。
  2. sys_dict字典表存状态名称、状态颜色(前端标签用)、可操作的下一状态列表。

举个例子:

当前状态可流转到操作人角色
咨询登记待审批 / 已作废行政、前台
待审批承办中 / 已作废主任
承办中已结案承办律师
已结案已归档承办律师、助理
已归档(终态)-

这个设计初看起来没有专门建“审批流程表”,但律所业务规模下完全够用。如果后续要支持多级审批,只需要在字典表里加“待审批-复核中”等状态,再配新的流转路径,而不需要推倒重来。

3.3 初始化数据脚本:一开始就要有字典

建表脚本里我特别注意把字典数据和默认账号一起初始化进去。很多项目表和代码写完,结果打开系统什么菜单都没有,就是因为少了初始化数据。我的init.sql里固定放了:

  • 五个角色:admin、director、lawyer、assistant、clerk。
  • 一个默认管理员账号,密码加密后写入。
  • 案件类型字典:民事、刑事、行政、非诉。
  • 案件状态字典和状态流转配置。
  • 党员学习等与业务无关的不要硬塞,保持干净。

这里要提醒一句:MySQL字符集务必用utf8mb4,尤其文书名称、当事人姓名里可能出现特殊符号和生僻字。用utf8不兼容四字节字符,插入直接报错。

4. 后端代码怎么写:JWT鉴权、案件CRUD与MyBatis调试

后端这块我按“配置 → 登录鉴权 → 核心接口 → 分页与调试”的顺序讲,这也是你拿到源码后最容易看懵的部分。

4.1 Spring Boot项目结构与配置

后端用的是Spring Boot 2.7.x,Java 8/11都行。为什么不直接上Spring Boot 3?因为很多老旧的MyBatis版本和JDBC驱动在Spring Boot 3上要做额外适配,对于一套要交付给律所长期维护的系统,稳比新重要。

application.yml关键配置如下:

server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/lawfirm_db?useUnicode=true&characterEncoding=utf8mb4&useSSL=false&serverTimezone=Asia/Shanghai username: root password: your_password servlet: multipart: max-file-size: 20MB max-request-size: 100MB mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.lawfirm.module configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl jwt: secret: your-secret-key-change-in-production expire-hours: 12

这里有两个容易被忽略的点:

  1. map-underscore-to-camel-case: true:数据库字段create_by直接映射到Java属性createBy,不需要手写一堆resultMap。
  2. log-impl: StdOutImpl:开发阶段把SQL打到控制台,方便调试。生产环境记得换成别的日志实现,不然SQL裸奔在日志里,有敏感信息泄露风险。

4.2 登录与JWT鉴权:按角色控制访问

登录接口逻辑很直接,查询用户、比对BCrypt密码、签发JWT令牌:

@PostMapping("/auth/login") public Result login(@RequestBody LoginDTO dto) { User user = userMapper.findByUsername(dto.getUsername()); if (user == null || !BCrypt.checkpw(dto.getPassword(), user.getPassword())) { return Result.error("用户名或密码错误"); } String token = JwtUtil.createToken(user.getId(), user.getRoleId()); return Result.success(new LoginVO(token, user)); }

JWT的关键是拦截器。我用OncePerRequestFilter校验每个请求的Authorization头,解析出用户ID和角色后放到ThreadLocal里,业务代码里直接取当前登录人信息:

@Component public class JwtFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) { String token = req.getHeader("Authorization"); if (StringUtils.hasText(token) && token.startsWith("Bearer ")) { Claims claims = JwtUtil.parse(token); UserContext.set(claims.get("userId", Integer.class), claims.get("roleId", Integer.class)); } chain.doFilter(req, resp); } }

权限控制用自定义注解@RequireRole加AOP实现,比如只有主任能审批收案:

@PostMapping("/approve") @RequireRole({"director"}) public Result approve(@RequestBody ApproveDTO dto) { caseService.approve(dto); return Result.success(); }

这种实现方式比引入Spring Security全家桶简单得多,对律所这种角色固定、权限规则清晰的小系统来说足够牢靠。

4.3 MyBatis的XML写法与动态SQL

案件列表页是查询条件最多的接口:按案件编号、案件类型、状态、承办律师、收案时间范围,再加上分页。这种多条件组合查询我用MyBatis动态SQL最舒服:

<select id="queryCasePage" resultType="com.lawfirm.module.caseinfo.CaseVO"> SELECT c.*, u.real_name AS lawyer_name FROM case_info c LEFT JOIN sys_user u ON c.lawyer_id = u.id <where> <if test="caseNo != null and caseNo != ''"> AND c.case_no LIKE CONCAT('%', #{caseNo}, '%') </if> <if test="caseType != null and caseType != ''"> AND c.case_type = #{caseType} </if> <if test="status != null and status != ''"> AND c.status = #{status} </if> <if test="lawyerId != null"> AND c.lawyer_id = #{lawyerId} </if> <if test="startDate != null"> AND c.create_time &gt;= #{startDate} </if> <if test="endDate != null"> AND c.create_time &lt;= #{endDate} </if> </where> ORDER BY c.update_time DESC LIMIT #{offset}, #{pageSize} </select>

注意两点经验:第一,动态SQL里的<if>判断宁多勿少,否则线上用户随便选个空条件,查出来的可能就是全表,直接打出问题;第二,多表关联时resultType不要追求覆盖所有字段,只映射你需要的VO字段,避免查出一堆用不到的大字段,影响性能。

4.4 分页与查询逻辑:量不大的时候不用插件

很多教程上来就集成PageHelper,但我的建议是:像律所这种几百上千案件量的系统,手动LIMIT分页完全够用,少一个中间件就少一个坑。我自己封装了一个简单PageResult:

public class PageResult<T> { private long total; private List<T> list; }

Service层先COUNT(*)查总数,再查当前页数据,两套SQL在XML里贴着写,逻辑清晰,也方便以后改成更复杂的统计查询。

5. 前端Vue 3实现:路由、请求封装与案件列表页实战

前端我用的是Vite + Vue 3 + Element Plus + Pinia。相比Vue 2 + Webpack那套,启动速度快,开发体验好,部署也只是产出静态文件,管理成本很低。

5.1 Vite项目初始化与目录约定

初始化命令很简单:

npm create vite@latest frontend -- --template vue cd frontend npm install npm install element-plus axios pinia vue-router

目录上我没有用特别复杂的架构,按功能区分:

  • src/api/:每个模块一个文件,比如case.js、party.js。
  • src/router/:路由表,含动态菜单项。
  • src/store/:Pinia保存用户信息和菜单权限。
  • src/views/:页面组件,按模块建子目录。
  • src/components/:通用组件,比如状态标签、上传组件。

5.2 路由配置:别把权限写死在页面上

路由我分成“静态路由”和“动态路由”。登录页、404这些是静态的;业务页面根据角色动态添加,避免普通用户直接在地址栏敲URL进入管理页面。

const staticRoutes = [ { path: '/login', component: () => import('@/views/Login.vue') } ]; const dynamicRoutes = [ { path: '/cases', component: Layout, meta: { roles: ['admin', 'director', 'lawyer', 'assistant'] }, children: [ { path: 'list', component: () => import('@/views/case/CaseList.vue') } ] } ];

路由守卫里做两件事:确认已登录、确认角色匹配:

router.beforeEach((to, from, next) => { const userStore = useUserStore(); if (to.path !== '/login' && !userStore.token) { next('/login'); } else { next(); } });

5.3 Axios拦截器:统一处理Token和错误码

Axios拦截器是前后端联调的核心,前端所有请求都应该走同一套逻辑。我这套拦截器做了三件事:带上Token、统一处理业务错误码、捕获401跳回登录页。

service.interceptors.request.use(config => { const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); service.interceptors.response.use(res => { const data = res.data; if (data.code === 200) { return data.data; } if (data.code === 401) { localStorage.removeItem('token'); window.location.href = '/login'; } return Promise.reject(new Error(data.msg || '请求失败')); }, err => { return Promise.reject(err); });

拦截器里最容易忽略的是超时时间设置。我遇到过当事人上传超大文件,后端处理超过默认超时时间,前端直接显示网络错误,排查半天。最后在创建axios实例时设置了timeout: 30000,并且文件上传接口单独放宽到两分钟。

5.4 案件列表页与状态标签组件

列表页是律师每天打开频率最高的页面,我把筛选区、表格、分页做成了一个完整页面。状态列用Element Plus的el-tag展示,不同类型不同颜色,这需要前后端约定好。我的方案是后端字典表存了status_color字段,前端直接读取:

<el-table-column prop="status" label="状态"> <template #default="{ row }"> <el-tag :type="statusColor(row.status)">{{ statusName(row.status) }}</el-tag> </template> </el-table-column>

#default就是Vue 3的插槽语法,Element Plus的列插槽非常常用,自己写表格组件的时候也会大量用到。这里是Vue插槽在真实业务里的典型场景。

6. 从开发机到服务器:后端Jar包与前端Nginx的部署全流程

项目做完不部署等于白做。我在这套系统上跑通了两条部署路径:一条是Windows本机/小型服务器部署,一条是Linux服务器部署。最终上线用的是Linux + Nginx + systemd。

6.1 环境准备

后端需要JDK 8+和MySQL 5.7+/8.0。MySQL安装这里我不展开,只说一个建议:不要为了图省事在服务器上用Docker装MySQL,除非你很了解Docker的数据卷和数据持久化配置。我踩过Docker容器一重启数据库全丢的坑,后来老老实实用系统自带的MySQL。如果你确实要用Docker,必须把数据目录映射到宿主机,并且固定容器名,这点Docker官方的文档里写得很清楚,别跳步。

前端构建需要Node 16+,生产环境构建只依赖Nginx。

6.2 后端打包与启动

后端打包用Maven,跳过测试直接打包:

cd backend mvn clean package -DskipTests

打出来的lawfirm-1.0.0.jar在target目录下。生产环境启动不要直接java -jar跑在前台,我用的是systemd配置守护进程:

[Unit] Description=Lawfirm Case System After=network.target mysql.service [Service] User=www WorkingDirectory=/opt/lawfirm ExecStart=/usr/bin/java -Xms256m -Xmx512m -jar /opt/lawfirm/lawfirm-1.0.0.jar --spring.profiles.active=prod Restart=always RestartSec=5 [Install] WantedBy=multi-user.target

Restart=always是关键,进程异常退出后自动拉起,省得半夜被电话叫起来手动重启。

6.3 前端构建与Nginx配置

前端构建:

cd frontend npm run build

生成dist目录。把dist下的文件上传到/opt/lawfirm/frontend,然后配置Nginx:

server { listen 80; server_name your-domain.com; root /opt/lawfirm/frontend; index index.html; location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location / { try_files $uri $uri/ /index.html; } location /files/ { alias /opt/lawfirm/uploads/; } }

这个配置里有两个重点:

  1. /api/代理到后端,后面写的proxy_pass http://127.0.0.1:8080/;注意最后有个斜杠,它会剥掉/api前缀,后端接口就不需要加/api前缀了。
  2. try_files $uri $uri/ /index.html;是Vue history路由必需的,否则刷新/cases/list页面会404。

6.4 上线时的目录约定和数据库备份

我建议服务器上固定这套目录结构,后续维护成本最低:

/opt/lawfirm/ ├── lawfirm-1.0.0.jar ├── config/ # 外部application-prod.yml ├── frontend/ # 前端构建产物 ├── uploads/ # 上传的文书、证据文件 ├── logs/ # 应用日志 └── backup/ # 数据库备份

数据库备份我写了一个简单脚本,每天凌晨用crontab执行:

mysqldump -u root -p****** lawfirm_db > /opt/lawfirm/backup/lawfirm_$(date +%Y%m%d).sql

备份是律所这种数据敏感系统的底线,哪怕没有专业DBA,定时备份脚本也要有。

7. 实际踩坑记录:跨域、时区、二级缓存与外部配置

最后这部分是这套项目里最值钱的经验,全是我自己踩过的,按“问题现象—原因—解决方案”三步写,你可以直接对照排查。

7.1 跨域问题:开发环境与生产环境要分开处理

开发环境前端跑在5173端口,后端跑在8080端口,直接请求必然跨域。我在后端写了全局CORS配置:

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }

生产环境因为Nginx做了反向代理,前端和后端在同一个域名下,反而不存在跨域问题。很多新手把生产环境也当开发环境配置CORS,前端地址和后端地址不同域,结果Nginx代理没配好,导致登录接口永远调不通——排查了半天,最后发现跨域配置和代理重复了。

7.2 MySQL时区问题:数据时间差了8小时

项目跑起来后,前端显示的案件创建时间比真实时间慢了8个小时。查下来是时区问题:MySQL连接串里的serverTimezone没配置对,JDBC驱动用了默认的UTC时区,存进去的时间被转换错了。

解决方式有两个,我两个都做了:

  1. JDBC连接串加:serverTimezone=Asia/Shanghai
  2. Jackson全局配置时区,保证JSON序列化也统一:
spring.jackson.time-zone=GMT+8 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss

这一步不做,前端看到的日期永远是错乱的,而且这种错乱很难定位。

7.3 MyBatis二级缓存:这个场景千万别开

MyBatis默认一级缓存在SqlSession内部生效,没问题。但网上教程经常让人开二级缓存(<cache>标签),我在这个项目上明确不建议开。

原因很直接:案件管理系统对数据实时性要求高,律师今天刚上传一个结案文书、主任立刻审批,如果二级缓存没及时清理或者多个操作节点共用缓存,用户看到的案件状态可能就是旧的,这在律所业务里是大事。如果你是做后台管理系统,默认关闭二级缓存;如果你不确定缓存机制,默认关闭二级缓存。

7.4 上传文件的存储位置:别往Jar包里写

文书上传功能遇到一个比较严重的坑:开发阶段文件直接传到项目的./uploads目录下,测试没问题。但打包成Jar运行后,文件写到了Jar包所在目录的相对路径下,一旦发布新版本替换Jar包,旧文件路径全乱了。

最终方案是把上传路径做成外部配置:

app: upload-dir: /opt/lawfirm/uploads

代码里读取配置项拼完整路径,Nginx再把/files/映射到这个外部目录。这样替换Jar包不影响已上传文件,备份上传目录也方便。这个设计看起来很简单,但很多中小项目就是在这里栽跟头。

等你跑完一遍,试着自己加一个“证据材料批量上传”功能,或者把结案统计做成ECharts图表,就会真正掌握这套前后端分离系统的完整开发脉络。我在实际做过之后最大的体会是:这类管理系统技术上没有什么高深的东西,难的是把业务状态、权限、数据关系理清楚,且每个决策都要考虑后续维护的人——哪怕那个人是三个月后的自己。

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

Hadoop2集群搭建实战:从规划配置到YARN与Spark衔接

我第一次动手搭分布式环境的时候&#xff0c;用的就是Hadoop2。当时网上教程不少&#xff0c;但大多数是照着抄配置、敲命令&#xff0c;出了问题没人告诉你为什么。后来陆陆续续帮同事排过不少坑&#xff0c;自己也重装过好几遍&#xff0c;才慢慢把每个参数背后的逻辑理清楚。…

作者头像 李华
网站建设 2026/10/8 23:57:03

SYN Flood攻击防御实战:内核调优与流量清洗全攻略

凌晨一点&#xff0c;手机连环震动。打开运维群一看&#xff0c;某台线上业务服务器的告警已经刷屏&#xff1a;TCP连接数暴涨、CPU毛刺、业务接口响应超时。登录跳板机看了一眼&#xff0c;netstat -ant里SYN_RECV状态连接密密麻麻&#xff0c;从同一个或几个可疑IP段源源不断…

作者头像 李华
网站建设 2026/10/8 23:56:50

Gitee实战:从SSH密钥到开源协作的完整指南

先说个我的判断&#xff1a;Gitee这几年在国内开发者圈子里&#xff0c;已经从“备胎”变成了“日常”。2025年再看这个平台&#xff0c;它的价值早就不只是“国内能访问的Git托管”这么简单。围绕Gitee长出来的本土化协作习惯、开源合规玩法、Pages静态托管&#xff0c;甚至游…

作者头像 李华
网站建设 2026/10/8 23:55:59

连续失败后如何止损?重建容错率的工程化指南

看到“连跪两天&#xff0c;容错率变了”这句话时&#xff0c;我第一反应是想起自己上一次连续搞砸项目的经历。连输两天&#xff0c;最可怕的不是那两天的实际损失&#xff0c;而是第三天做决策时&#xff0c;你的整个判断系统已经悄悄换了版本。所谓容错率&#xff0c;原本是…

作者头像 李华
网站建设 2026/10/8 23:54:04

CentOS 7 下用 Shell 脚本 + Docker 一键部署 Redis 3主3从集群

简介&#xff1a;这份资源提供了一套基于 Docker 的 Redis 集群一键部署方案&#xff0c;面向需要在 CentOS 7.x 环境下快速搭建 Redis 集群的运维与后端开发人员。使用者只需按说明将参数传递给安装脚本&#xff0c;即可自动完成镜像加载、容器编排与集群初始化&#xff0c;省…

作者头像 李华
网站建设 2026/10/8 23:51:34

WPF富文本编辑器开发实战:从FlowDocument到仿Word开源Demo

简介&#xff1a;这是一份基于WPF的开源富文本编辑器代码与演示项目&#xff0c;面向希望在.NET桌面应用中实现类Word编辑功能的开发者&#xff0c;尤其适合具备一定C#与XAML基础、想研究富文本处理机制的中高级人员。压缩包共289个文件&#xff0c;约753KB&#xff0c;以cs源码…

作者头像 李华