十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Spring Boot内测调研复盘:从用户反馈到技术修复

Spring Boot内测调研复盘:从用户反馈到技术修复 EE308FZ 这个项目我是从去年年底开始接手的。当时它还不叫这个名字内部代号一直是 EE308后来因为要出内测版我把分支代号定为 Beta Spring想着这一版终于能用 Spring 体系把整个后端捋顺了。两周前 Beta 版本放出去给一小批用户试用昨天刚把回收的调研数据整理完。这份 Survey Report 与其说是给团队看的总结不如说是我自己踩了两个星期坑之后的技术复盘。反馈里暴露出来的问题远比功能做没做完更有价值——很多用户觉得“不好用”“进不去”“上传的东西打不开”追到代码层面全是 Spring 配置和版本迭代的锅。这篇就按报告的结构把调研设计、反馈分析、技术归因和修复方案完整拆开来写希望能给正在做 Spring 项目内测、或者准备写用户调研报告的人一点参考。先交代一下项目背景。EE308FZ 是一个面向设备接入和运行数据管理的小型平台主要功能包括用户管理、设备信息登记、实时数据看板、告警规则配置。上一版用的还是老式 Servlet JSP 的写法功能能跑但扩展性太差加一个导出功能都要动一堆代码。Beta Spring 这版完全重构技术栈换成 Spring Boot 3.x Spring Security MyBatis-Plus MySQL部署方式也从单机 WAR 包改成 Docker 容器。这次调研的目的很明确验证重构后的基础功能是否稳定、用户对交互有没有明显不满、有没有隐藏的安全和性能问题。参与内测的一共 75 人最终回收有效问卷 62 份另有 8 次深度访谈和全量日志分析。下面我会把整个过程拆成六个部分从调研方案讲到技术复盘再落到具体的修复动作上。1. 项目背景与 Beta Spring 版本定位1.1 EE308FZ 是什么为什么要做 Beta SpringEE308FZ 这个代号拆开看其实很直白——EE 是 Electronic Equipment 的缩写308 是设备接入网关的编号FZ 是“分组”的拼音首字母合在一起就是 308 号设备分组管理平台。平台本身的定位不复杂让运维人员能在网页上查看设备在线状态、配置告警阈值、浏览历史运行数据。但因为设备数量多、告警频率高系统对实时性和稳定性的要求并不低。Beta Spring 是重构后的第一个对外测试版本。之所以叫 Beta Spring是因为这一版的核心变化就是把后端从 Java EE 的传统 Servlet 写法整体迁移到 Spring 生态。以前每个模块都要自己 new Service、自己管理数据库连接代码量翻倍不说改一处经常影响一片。换到 Spring Boot 之后依赖注入把对象创建和装配这件事从业务代码里彻底解耦了开发效率提升非常明显——这是我坚持在 Beta 版就用新架构的根本原因。1.2 技术选型的核心考量选 Spring Boot 3.x 而不是 2.x主要是考虑到未来要对接 Spring AI 做告警文本的自动生成3.x 对 AI 相关的自动配置支持更好而且 Boot 3 强制要求 Java 17长期维护和性能上都有优势。Spring Security 用来处理登录认证和接口权限MyBatis-Plus 负责数据层Redis 做会话和告警频控缓存。这里有一个很关键的选择逻辑Spring Boot 本身只是帮我们省去了繁琐的 XML 配置和 Bean 装配过程但它解决不了业务复杂度问题。比如设备接入协议的解析、告警规则引擎的优先级计算这些还是得自己写。所以 Beta Spring 版本我刻意做了模块划分——controller、service、mapper、entity 四层结构每一层只做自己分内的事这样后续无论是加 Spring Cloud 做微服务拆分还是引入 MQ 做异步告警推送都不会伤筋动骨。1.3 调研目标与用户群体这次调研目标定得很具体就三个维度第一Beta 版核心功能——登录、设备管理、数据看板、告警配置——是否稳定可用第二用户操作过程中是否遇到阻塞性 Bug第三系统性能和安全性有没有明显短板。用户群体分三批第一批是团队内部的 12 名开发人员第二批是 18 名一线运维人员第三批是 45 名从老版本迁移过来的老用户。内部开发人员的作用是帮忙做深度功能测试运维人员暴露真实业务场景里的问题老用户则反馈 UI 交互和易用性变化。不同角色看问题的角度完全不一样后面整理反馈的时候这种分层的价值会体现得非常明显。2. 用户调研方案设计与数据收集方式2.1 多渠道反馈收集问卷、日志与访谈做用户调研最怕的就是只撒一份问卷出去然后坐等回收。问卷能覆盖的数量大但信息密度低很多用户只会填“能用”或者“不好用”完全看不出技术层面的原因。所以我这次用了三轨并行的方案。第一轨是问卷用在线表单做了 25 道题涵盖基本信息、功能使用频率、满意度评分、开放性问题。第二轨是系统日志埋点我在前端页面埋了几个关键事件——登录成功率、看板加载时间、告警配置保存是否报错后端同步记录接口响应时间和异常堆栈。第三轨是深度访谈在问卷回收后从反馈比较极端特别满意和特别不满意的用户里各挑 4 个人做一对一沟通把模糊的描述还原成具体的操作路径。三条线汇总之后用户反馈就不再是干巴巴的一句话而是能直接对应到某个接口、某段代码的线索。比如有人在问卷里写“上传设备图片总是失败”日志一看是静态资源请求 404再追下去发现是 Spring Security 把/upload/**这个路径给拦截了——这种排查方式比让用户反复截图试错高效太多了。2.2 关键指标与评分规则问卷部分采用 SUSSystem Usability Scale系统可用性量表的简化版10 道题按 5 分制打分最后换算成百分制。功能模块单独打分分为“频率”和“满意度”两个维度——频率统计用户实际用得多不多满意度衡量用得顺不顺。频率高但满意度低的功能是下一阶段优先优化的对象。日志埋点则侧重两个硬指标接口 P95 响应时间和错误率。P95 的意思是 95% 的请求都能在这个时间内完成比平均耗时更能反映真实体验。Beta Spring 版本我给自己划的红线是核心查询接口 P95 不超过 800ms登录接口错误率不超过 1%。最终数据出来后这两项都达标了但某些场景比如看板加载大量设备数据下 P95 还是偶尔冲高后面单独分析。2.3 样本情况与数据清洗62 份有效问卷的分布是开发人员 11 份、运维人员 16 份、普通业务用户 35 份。性别和年龄这些维度对这个项目没什么分析意义直接略过但角色和使用频率一定保留——后续分析问题时同一句话来自开发人员和来自业务用户优先级完全不同。数据清洗主要处理两类情况一类是明显乱填的问卷比如所有题目都打同分、开放问题写“不知道”的直接剔除另一类是日志中的爬虫和监控探针请求过滤掉这些无效流量后真正的用户请求占据 91.4%数据可信度比较高。3. 核心调查结果与 Spring 技术归因分析3.1 功能满意度高频功能与核心痛点先看整体数据SUS 可用性评分平均 72.6 分属于“可以接受但远谈不上优秀”的区间说明 Beta 版能跑通主流程但细节打磨还差很多。分功能统计下来使用频率最高的是“设备状态查看”和“告警列表浏览”满意度也相对稳满意度最低的三个功能是“设备图片上传”“告警规则保存”“批量导出”。“告警规则保存”这个点特别有意思。功能频率很高但满意度只有 3.1/5而且开放问题里至少 10 个人提到“保存成功后有时看不到新规则要刷新才出来”。这不是简单的缓存问题后面查代码才发现是 MyBatis-Plus 的更新操作返回了成功但事务没有正确提交——典型的 Spring 事务传播行为使用不当引发的 Bug。3.2 Spring 依赖注入与三级缓存启动慢和循环依赖的真面目Beta 版本刚发布时好几个用户反馈“系统启动特别慢”“偶尔启动失败”。启动慢我们排查过一部分原因是初始化时加载设备协议解析器太耗时但有一个启动失败的问题非常典型异常信息是BeanCurrentlyInCreationException——这是 Spring 容器在创建 Bean 时遇到了循环依赖。这里值得给不熟悉 Spring 原理的朋友解释一下。Spring 用三级缓存来解决构造器注入之外的循环依赖问题一级缓存放完整的单例 Bean二级缓存放提前暴露的早期 Bean三级缓存放 ObjectFactory 工厂对象。如果 A 依赖 B、B 又依赖 A在单例模式下 Spring 可以先创建 A 的早期引用放到二级缓存等 B 创建完再回填 A 的完整属性。但如果循环依赖发生在构造器注入中或者有Async这类代理对象参与三级缓存就解不了。我自己踩的坑是设备告警处理器AlarmHandler和告警规则服务RuleService互相调用其中RuleService是构造器注入导致启动直接抛异常。解决办法不是去改注入方式而是重新审视代码结构——把AlarmHandler里需要RuleService的逻辑抽到一个独立组件里彻底解除循环依赖。这比用Lazy糊弄过去要干净得多也避免了某些场景下代理对象提前初始化导致 AOP 失效的风险。3.3 Spring Security 配置登录、CORS 与权限放行用户反馈里排名前列的另一类是“登录成功后无法访问接口”“跨域请求失败”。这些问题的根源基本都指向 Spring Security 的过滤器链配置。Spring Security 的逻辑是这样的所有请求都要经过FilterChainProxy只有通过SecurityFilterChain里允许放行的规则才能到达 Controller 层。开发阶段为了调试方便很多人会把permitAll()写得过于宽松但一旦进入 Beta 版本收紧权限之后之前能访问的路径突然全部 401用户就会开始投诉。我这次遇到的跨域问题也很有代表性。前端部署在 8080 端口后端跑在 8081 端口浏览器的同源策略直接拦截了请求。如果只是加CrossOrigin注解某些复杂请求比如带Authorization头的 GET 请求还是会失败。正确做法是在 Spring Security 的过滤链里加一个 CorsFilter同时配置allowedOriginPatterns而不是写死允许所有来源。另外上传图片的路径/upload/**被登录拦截导致 404这也是 Spring Security 的经典问题——静态资源如果也要鉴权必须明确把它加入permitAll()列表如果不加用户就会被重定向到登录页前端再返回一个无法解析的响应体验极差。3.4 分层架构目录规范与包管理方式Beta Spring 版本里我还做了一件让后续分析轻松很多的事严格按功能模块分包而不是按技术层分包。以前是 controller 包下放所有控制类service 包下放所有服务类项目一大人就懵了。现在改成按业务域分device 包、alarm 包、user 包每个包内部再分 controller/service/mapper。这样定位用户反馈的问题时直接从包名就能锁定代码范围不用在几十个类文件里大海捞针。4. 安全性专项静态资源遍历与 Actuator 暴露4.1 静态资源目录遍历的真实风险分析调研中有一个运维用户提到一个操作他在地址栏手动拼路径去访问设备图片结果发现用%2e%2e/这种编码方式居然能向上跳目录。这是我这次最紧张的一个反馈因为它直接关联到一个真实的 CVE 漏洞——CVE-2024-38819该漏洞影响使用特定版本 Tomcat 的 Spring Boot 应用攻击者可以通过路径编码绕过限制访问到 Web 应用目录之外的静态资源文件。这个漏洞的原理简单说就是 Tomcat 在处理 URL 时对%2e%2e/即../的 URL 编码形式的解码和标准化顺序处理不当。Spring Boot 内嵌的 Tomcat 如果版本过低加上静态资源目录配置过于宽松就可能被利用读取服务器上的敏感文件。虽然我们部署环境没有直接暴露在公网但内部系统同样不能留这种口子。处理方案分两步第一升级内嵌 Tomcat 到修复版本9.0.89 及以上或 10.1.25 及以上关键的 CVE 修复直接依赖版本更新第二在静态资源映射层增加二次校验——写一个拦截器对请求路径做标准化处理如果最终解析出来的路径包含..就直接拒绝。这两层防护叠加之后我再测试路径穿越已经无法跳出上传目录。4.2 用户反馈中的端口暴露Actuator 端点防护Beta Spring 版本为了排查线上问题我在配置里开放了 Spring Boot Actuator。有用户反馈说“访问某个端口能看到系统信息”查了日志才知道是/actuator/env和/actuator/beans这些端点。Actuator 是 Spring Boot 提供的运维监控组件本身是好东西但如果在生产环境没有做权限保护等于把系统内部结构、环境变量、配置项这些敏感信息直接摆到公网上。我这次犯的错误是把management.endpoints.web.exposure.include*写得太随意了。后续的修复动作是把 Actuator 单独绑定到一个不对外暴露的内部端口并且只在dev和test环境开启生产环境只保留health和info两个端点且通过 Spring Security 配置限定只有运维网段的 IP 能访问。这样既保留了监控能力又不至于让系统裸奔。4.3 安全配置参考清单把这次调整后的安全配置整理成下面这张表方便直接对照检查配置项推荐做法说明内嵌 Tomcat 版本升级到修复 CVE-2024-38819 的版本路径穿越漏洞是硬性风险必须在公测前完成静态资源映射限制上传目录范围并增加路径标准化拦截不要直接映射整个磁盘路径只映射指定的根目录Actuator 暴露生产环境只暴露 health、info绑定内网端口调试端点只允许开发环境使用Spring Security 放行静态资源、登录接口、健康检查按需放行其余接口全部鉴权不要为调试开白名单跨域配置指定 allowedOriginPatterns不使用*前后端域名固定后写死5. 高频问题分类与修复优先级5.1 基于反馈整理的问题速查表调研数据汇总后我把所有问题按严重程度和影响范围分成 P0、P1、P2 三档。P0 是阻断用户完成关键任务的问题必须在下个迭代立即修复P1 是影响体验但存在绕过方案的问题安排在一周内修复P2 是优化建议和非阻塞问题排期处理。问题描述反馈频次严重级别技术归因修复方案设备图片上传后无法访问12P0Spring Security 拦截/upload/**静态资源路径调整 Security 配置放行上传目录路径编码访问上层目录3P0内嵌 Tomcat 版本存在 CVE-2024-38819升级 Tomcat增加路径标准化拦截器告警规则保存后列表不刷新10P1事务提交时机和缓存数据不一致调整事务边界主动清理缓存登录后接口跨域报错8P1CORS 配置不完整未处理预检请求在 Security 链上配置 CorsFilter系统启动偶尔失败4P1构造器注入导致循环依赖拆分类消除循环依赖Actuator 端点可公开访问2P0暴露端点配置过于宽松收紧端点暴露范围并做 IP 限制值得注意的是P0 级的问题里有两个都是安全相关。这也是 Beta 调研最值钱的部分——某些问题在功能层面看起来“不明显”但如果没在测试期发现一旦正式上线后果完全不一样。5.2 从反馈反向修正 Spring 配置的路径对比用户反馈和最终代码修改记录我发现一个规律几乎 70% 的反馈最终都能追溯到 Spring 配置上而不是业务代码本身的 Bug。这里说的配置包括 Spring Security 的过滤链规则、事务管理器的事务传播方式、MyBatis-Plus 的乐观锁配置、Jackson 的序列化规则等等。举个例子用户反馈“告警规则的并发修改会被覆盖”排查后是 MyBatis-Plus 的Version乐观锁没有配好导致两条并发请求都能读到旧版本号先后提交后一条覆盖了前一条。从用户视角看这是数据丢失从技术视角看这是 Spring 配置缺失。所以做用户调研分析时一定要建立“用户描述 → 技术归因 → 配置修正”的映射能力否则问题清单再长也只会陷入一个一个打补丁的被动循环。6. Beta 版本调研后的优化与下阶段规划6.1 动手修复的重中之重先堵安全漏洞再改体验问题修复优先级我定得很明确第一天先升级 Tomcat 版本把路径遍历这个洞补上第二天收紧 Actuator 暴露范围并重新规划 Spring Security 的放行规则。这两个动作做完之后系统从“裸奔”状态恢复到基本安全后面再动功能就不怕因为配置调整引入新风险。接下来处理的是循环依赖和事务边界问题。循环依赖的重构花了我一个晚上核心思路是把告警处理器中调用规则存储的部分拆到独立的RuleQueryService让依赖方向变成单向的AlarmHandler→RuleQueryService→RuleRepository。事务问题则是检查每个 Service 方法上的Transactional注解那些不需要跨表多写在同一个事务里协作的方法直接去掉这个注解避免长事务占用数据库连接。6.2 下阶段演进Spring AI 与 Spring Cloud 的入口设计Beta Spring 版本跑通之后团队内部已经在讨论下一阶段的演进方向两个明确的方向是 Spring AI 和 Spring Cloud。Spring AI 的引入不是为了追热点而是通过接入大模型把告警信息自动生成事件摘要和处置建议减少运维人员手动分析日志的时间。这次调研中有不少运维用户反馈“告警太多看不过来”正好是 AI 可以切入的场景。Spring Cloud 的方向则更多是出于扩展性考虑。目前全部功能挤在一个应用里虽然部署方便但设备接入、告警分析、用户管理这些模块未来如果流量差距拉大横向扩容会比较吃力。后续计划按gateway网关、device-service设备服务、alarm-service告警服务拆开各服务独立部署用 Nacos 做服务发现和配置中心。当然这是下一个 Beta 版本要做的事这里先不展开详细设计。6.3 个人实操中的体会与建议经历这一轮调研和修复我最想提醒做 Spring 项目内测的团队一句话用户调研报告不只是写给别人看的文档它应该是你代码改进的直接输入来源。每一次反馈都值得追问一句“这条问题对应的 Spring 配置是什么”而不是简单回复“功能修好了”。我实际测试中发现花一个下午把用户原始描述归类成“配置类 - 代码逻辑类 - 交互设计类 - 外部依赖类”四种类型后面的排查效率会高非常多。配置类问题占了 60% 以上而这部分通常改一行配置就能解决验证也很快。另外日志埋点一定要在 Beta 版发布前就做好否则像 CORS 报错、401 跳转重定向这种浏览器端看不到的网络错误问卷开放题里根本收集不到有效信息。这次 Beta Spring 调研给我最大的收获不是评分数字而是建立了“用户反馈到代码问题”的完整链路——设备图片打不开能想到静态资源拦截启动失败能想到循环依赖路径穿越能想到 Tomcat 补丁版本。有了这条链路下一轮迭代做起来就会踏实很多。
返回列表