资讯动态

AI辅助开发实战:用Claude Code搭建Spring Boot用户管理

发布时间:2026/10/13 13:08:44 来源:尧图企业网站定制
接到“Claude Code Spring Boot 用户管理”这个项目时我第一反应是一边是热得发烫的AI编程助手一边是Java后端开发者闭着眼睛都能写的用户CRUD这俩凑一起有什么可讲的但真正动起手来才发现用户管理这套东西恰恰是检验AI辅助开发最狠的试金石——它看起来简单实际牵扯到数据建模、接口校验、认证授权、异常处理一大堆细节任何一个环节偷懒都会在联调时爆雷。这篇文章想记录我用Claude Code从零搭一个Spring Boot用户管理模块的全过程包括模块设计、代码生成、Spring Security接入、JWT鉴权以及Claude Code里的skills功能到底怎么定义、怎么用才能真正把效率提上去。想用AI辅助写后端、又担心它输出一堆“看着能用、跑起来就挂”的代码的同学这篇应该能给你不少参考。我先说清楚定位我不打算把这篇文章写成Claude Code的官方教程也不会复读Spring Boot的入门文档。我写的是实操里真正会遇到的选择题——比如用户表到底要不要软删除、密码加密选BCrypt还是别的、JWT的过期策略怎么定、skills文件里该写什么不该写什么。这些决策背后都有理由你拿去就能在自己项目里落地。1. 项目开局为什么用户管理是检验AI辅助开发的试金石1.1 这个项目到底要做什么用户管理模块在业务系统里的地位相当于新手村的第一个任务。它覆盖面广但不至于失控注册、登录、查询用户列表、编辑用户信息、删除或禁用用户再往后加角色和权限。单独拆开看每个接口都不复杂组合起来却能把后端的常见知识点全部串一遍。这次项目的目标很明确用Claude Code作为主力编码工具Spring Boot 3.x Java 17做技术底座MySQL存数据Spring Security负责认证授权JWT做无状态登录态管理。最终交付一个能跑、能测、能接前端的用户管理API并且把整套开发过程沉淀成可复用的skills配置下次做类似模块时不需要从零开始。有一点我特别想强调用Claude Code做这类模块真正的价值不在于“帮你把代码写出来”——代码本来也不难写而在于它能把那些重复性、模板化的决策固化下来。比如实体类怎么写、异常怎么统一处理、分页查询的参数怎么约定这些如果每次都靠人肉复制粘贴项目多了以后风格会持续漂移。用skills统一约束以后输出质量稳定得多审查代码时也更省心。1.2 为什么选Claude Code而不是纯手写说实话写用户管理这种模块纯手写我也就多花两三个小时表面上看AI辅助的优势没那么明显。但实际用下来差别主要在三件事上。第一是上下文记忆。用户管理不是只写Controller就完事的前面要设计表结构、写Repository、配安全过滤链、调登录逻辑中间夹着各种实体字段和业务规则。Claude Code能在会话里记住我们前面定的表结构、字段命名规则、异常处理约定后续生成的代码会自动对齐这些约束不需要我反复强调。第二是批量重构的效率。用户模块在中途改需求是家常便饭比如“用户名从唯一改成允许重复”“密码字段要从明文换成加密存储”“新增一个状态字段用于账号禁用”。这种改动往往牵连好几个文件纯手写需要逐个定位用Claude Code做批量修改时它能把牵连的文件一起改掉并且保持接口风格一致。第三就是skills的复用。这是我有段时间用得比较深的功能把一套“用户模块开发规范”写成skill文件里面包含实体类模板、Controller命名规则、异常处理建议、安全配置要点下次再开新项目时只需要加载这个skillClaude Code生成的代码就会自动带上这些规范。这相当于给自己配了一个“带项目规范的结对编程伙伴”。提示如果你第一次接触Claude Code的skills可以把它理解成给AI预装的“操作手册”。它不是模型本身而是挂在每次生成请求前面的上下文指令告诉AI在这个项目里应该遵循什么规则、优先使用什么方案。2. 设计先行用户表结构和技术选型背后的考虑2.1 用户表到底该有哪些字段动手生成代码之前我先把表结构定了。因为后面所有代码都是围绕这张表长的表设计错了改起来最痛。我这里用的是比较常规的方案但每个字段都有讲究字段类型说明设计理由idbigint主键自增即可单库场景最简单可靠usernamevarchar(50)登录名唯一索引大小写敏感问题靠业务层约束passwordvarchar(100)密码哈希存BCrypt加密结果不存明文nicknamevarchar(50)昵称可空用户不填时默认用用户名emailvarchar(100)邮箱唯一索引后续找回密码要用statustinyint状态1正常 0禁用不做物理删除created_atdatetime创建时间数据库默认值或ORM自动填充updated_atdatetime更新时间审计需要所有表最好都有两个容易被新手忽略的点我得单独说。第一是password字段长度必须留够BCrypt哈希输出是60个字符留60正好但考虑到后面可能换算法我习惯了直接varchar(100)。第二是status字段代替物理删除这是很多老项目的教训——用户删了之后历史订单、操作日志的外键全断了后续统计和审计都查不了。所以禁用而不是删除是用户管理模块里的一个明智默认。2.2 技术选型为什么用Spring Security而不是自己写拦截器登录鉴权这块网上有大量“自己写个拦截器JWT工具类”的教程看着代码少、逻辑透明但真放到生产里会碰到一堆边角问题token过期后怎么处理、哪些接口要放行哪些要拦截、密码错误次数限制怎么做、权限变更后token要不要失效。这些自己从零实现坑远比想象的多。Spring Security虽然在初学者眼里“配置复杂、过滤链像黑盒子”但它把这些边界问题都考虑过了。尤其是Spring Security 6以后配置方式比老版本清晰了不少SecurityFilterChain的Bean定义一目了然。我这次选的就是Spring Boot 3.2 Spring Security 6的组合认证方式用JWT。这里有几个决策和大家同步一下密码加密用BCryptPasswordEncoder这是Spring Security内置的自带盐值不需要额外处理。JWT用jjwt库版本选0.12.x新版的API重新设计过比老版直观得多。token有效期设置2小时refresh token机制这次先不做单模块够用但代码里预留了扩展点。为什么这么选BCrypt是行业默认安全性有保障唯一要注意的是加密操作比MD5慢但用户登录场景完全能接受。JWT的无状态特性适合前后端分离服务端不用存session水平扩展时不用考虑会话同步问题这对以后部署多实例很友好。2.3 代码结构怎么组织才不臃肿我见过太多用户管理模块把全部逻辑压进Controller里一个类七八百行看着能跑维护起来想哭。这次我按经典分层来组织com.example.user ├── controller // 接口层只做参数接收和响应封装 ├── service // 业务层事务、校验、业务流程 ├── repository // 数据访问层Spring Data JPA的Repository ├── entity // 实体映射 ├── dto // 请求/响应对象不直接暴露实体 ├── security // Security配置、JWT过滤器、UserDetailsService └── common // 统一响应、异常处理、常量这种结构的好处是每一层只干一件事Claude Code在生成代码时也更容易对齐层次边界。比如它知道Controller里不应该出现具体的SQL操作知道DTO的字段校验注解应该放在哪一层生成出来的代码就不会跑偏。真遇到“Controller里直接写查询逻辑”的情况我审查时一眼就能揪出来。3. 实操闭环用Claude Code把模块一步一步跑起来3.1 初始化项目与基础依赖第一步我用Spring Initializr初始化了项目骨架选好Spring Web、Spring Security、Spring Data JPA、MySQL Driver、Lombok这几个依赖。然后打开Claude Code的终端会话把项目路径告诉它接下来的工作基本就是“对话式开发”。我给Claude Code的第一个指令是这样的请在这个Spring Boot项目中创建用户管理模块的基础结构包含 - User实体类映射到user表表结构我已经在文档中定义 - UserRepository接口继承JpaRepository - UserService接口和UserServiceImpl实现类 - UserController提供注册、登录、查询用户列表、更新用户、禁用用户的接口 - 统一响应体ResultT和全局异常处理这里有个经验指令里说得越具体AI的输出越贴合需求。尤其要把“表结构字段定义”和“分层规范”写清楚否则它可能会按照自己的理解造一套字段出来回头对不上表。Claude Code生成完代码后我不会直接跑。我先做一轮人工审查重点看三样东西实体类字段和表结构是否一致、Controller是否只做了参数转发、异常处理有没有漏掉业务异常类型。用Claude Code做审查也很方便直接让它“检查UserController中是否有事务操作泄漏到Controller层”就行它能把问题点和对应文件列出来。3.2 接入Spring Security和JWT依赖有了、基础CRUD跑通之后最核心的一步是接入认证授权。这一步我没让Claude Code自由发挥而是先自己定了方案再让它按方案实现。方案是这样的SecurityConfig里配置SecurityFilterChain放行注册接口、登录接口其余接口需要认证。JwtAuthenticationFilter继承OncePerRequestFilter从请求头Authorization里取token解析成功后把用户信息塞进SecurityContext。UserDetailsServiceImpl从数据库加载用户返回Spring Security的UserDetails对象。自定义AuthenticationEntryPoint处理未登录返回401。自定义AccessDeniedHandler处理无权限返回403。这些配置点我一条一条列给Claude Code它很快就把完整代码拼好了。过程中出现了一个值得说的细节新版Spring Security把WebSecurityConfigurerAdapter废弃了网上大量老教程还在用这种写法直接复制会编译报错。Claude Code对版本差异的处理比较到位生成的是基于SecurityFilterChain的配置方式帮我省了不少排查时间。JWT这块我单独说下怎么生成的。登录成功之后把用户ID和用户名塞进token的claims里用HS256签名密钥是一串至少32字节的随机字符串放在配置文件中。校验的时候先验签名再查过期时间最后把claims里的用户ID拿出来加载完整用户信息。// 登录成功的核心逻辑节选 String token Jwts.builder() .claims(Map.of(uid, user.getId(), username, user.getUsername())) .issuedAt(new Date()) .expiration(new Date(System.currentTimeMillis() 7200000L)) .signWith(secretKey) .compact();这代码看着简单但有一个很容易踩的坑signWith方法的参数在新旧版本里不一样旧版传String密钥新版要求先通过Keys.hmacShaKeyFor把字节数组转成SecretKey否则抛异常。这种版本差异正是AI辅助开发容易“看起来对、跑起来错”的重灾区后面我专门写了排查思路。3.3 注册登录的业务细节注册逻辑不是插入一条记录那么简单至少要考虑这些问题用户名查重注册前先检查用户名是否已存在存在则抛业务异常。密码加密密码必须BCrypt加密后入库绝不能明文保存。默认状态新用户默认status1nickname为空则取username。唯一约束冲突兜底并发情况下即使业务层查重了数据库唯一索引也能拦住但异常要转成友好提示。登录逻辑也类似先查用户是否存在再用passwordEncoder.matches校验密码最后判断status是否为1禁用的账号直接拒绝登录。这里我特别提醒一句查不到用户和密码错误最好返回同样的提示比如“用户名或密码错误”避免被用来做账号枚举。这些细节我同样整理成要点发给Claude Code让它实现的时候一条都不要漏。它把校验逻辑放在了Service层而不是Controller层这也是我期望的——Controller只负责接收参数和返回结果业务校验留在Service层这样单元测试和复用都更方便。3.4 接口自测与常见问题验证代码生成后我一般不急着写前端先用接口测试工具把后端整个链路打一遍。我习惯用IDEA自带的HTTP Client或者直接curl命令测以下几组场景注册成功返回用户信息密码字段不能出现在响应里。重复用户名注册返回友好错误提示。未登录访问用户列表返回401。登录成功返回tokentoken能访问受保护接口。禁用账号登录返回账号已被禁用。伪造token访问返回401。这组测试用例跑下来基本能覆盖模块80%的问题。Claude Code在这一步也能帮上忙比如让它生成一组HTTP测试请求脚本或者让它检查响应结构是否泄漏了敏感字段。有一点经验必须分享响应体里不能直接返回User实体否则password字段会被序列化出去这是新手最容易犯的安全问题。我的做法是定义UserVO只返回id、username、nickname、email、status、createdAt这些字段。Claude Code生成查询接口时会按这个约定来做但我每次还是会多看一眼响应JSON确认没有密码字段混在里面。4. Claude Code Skills的落地用法把经验固化成可复用的资产4.1 Skills到底是什么和普通提示词有什么区别很多用过Claude Code的朋友会问skills和直接在对话里写“你是一个Java后端专家请帮我写代码”有什么区别。我觉得最核心的区别在两点复用性和作用域。普通提示词是一次性的每次新开会话都要重新输入而且不同会话之间语气、格式、约束很容易漂移。Skills则是一个独立配置文件放在项目的.claude/skills目录下Claude Code在运行时能自动加载里面的规则会被持续应用到整个会话里。你甚至可以在新项目中直接引用同一个skill目录让多个项目共用一套规范。你可以把skills理解成“给Claude Code装上的项目专属插件”。它不只是引导AI写代码还能定义工作流、规定输出格式、约束技术方案。比如我这次就写了一个user-management的skill内容涵盖以下要点name: user-management description: 用户管理模块开发规范适用于Spring Boot JPA Spring Security项目 instructions: | 1. 实体类字段必须与user表结构一致字段命名使用驼峰 2. Controller只做参数接收和响应封装不写业务逻辑 3. Service层负责业务校验、事务、异常抛出 4. 所有响应统一使用ResultT业务异常使用BizException 5. 密码必须BCrypt加密存储任何接口不得返回password字段 6. 查询接口必须分页禁止一次性全量返回 7. 用户状态字段0为禁用1为正常不做物理删除这个文件写好后新开会话或者让Claude Code继续工作时它会自动按照这套规范来。我后来在一个新项目里复用同一个skill生成的用户模块代码风格和第一个项目几乎一致维护成本直线下降。4.2 一个实用的Skill是怎么设计出来的写skill不是把想法堆上去就完事我总结了一个设计流程先回顾痛点再抽象规则最后验证效果。痛点回顾阶段我会把做过的用户模块里所有“返工”记录翻出来看看哪些问题反复出现。比如实体类字段对不上表、Controller里写了一大坨业务逻辑、异常处理风格不统一、密码字段泄漏到响应里——这些都是真实发生过的返工点。把它们一条条列出来就是skill里要约束的核心内容。规则抽象阶段我不写过于具体的代码模板而是写“判断原则”。因为代码模板换个数据库、换个ORM框架可能就不适用了但“Controller不写业务逻辑”这种原则是跨项目通用的。当然实体类这类高度模板化的内容给个参考模板也没问题方便AI快速对齐风格。验证阶段最关键。我会故意在一个小项目里加载这个skill然后让它生成几个接口逐条检查输出是否符合规则。如果发现有规则没生效就调整skill的措辞让它更明确、更可执行。比如我最初写的“密码要加密存储”不够明确后来改成“密码字段必须使用BCryptPasswordEncoder进行加密数据库中不得存储明文密码”生效率高很多——AI对具体的、带工具名的指令执行得比抽象的指令好得多。4.3 Skills使用中的边界与避坑Skills不是万能的用了一段时间后我摸出几个边界。第一skills不能替代需求澄清。如果业务需求本身模糊比如“用户管理要支持多角色”但没说明角色和权限的关系是单角色还是多角色、角色表怎么设计skill再完善也帮不上忙。必须先想清楚方案再靠skill保证执行的一致性。第二skill规则过多会互相打架。我一开始把很多零散要求都塞进skill里比如“不要使用Lombok”“所有注释用中文”“JWT有效期2小时”结果生成出来的代码有时候会顾此失彼。后来我做了个取舍只放那些“违反会造成返工或安全风险”的硬规则其余风格类的偏好通过对话指定就好。第三skill不要写成百科全书。真正的经验在于“项目特有的规范”而不是“Java基础知识”。“Java实体类用Entity注解”这种内容写进去没有任何意义纯属浪费上下文窗口。好的skill每一条规则都能追溯到一次实际踩过的坑。5. 常见问题与排查技巧实录5.1 JWT签名报错签名密钥格式不对这个坑我上面提到过值得展开讲。在jjwt 0.12.x版本里用字符串密钥直接调signWith会编译失败或者运行时报错。新版API要求SecretKey key Keys.hmacShaKeyFor(jwtSecret.getBytes(StandardCharsets.UTF_8));然后signWith(key)而不是signWith(字符串)。这个改动让很多从老项目搬代码的人中招。排查的办法很简单看堆栈里有没有“SecretKey”或“illegal argument”字样再确认jwtSecret长度至少32字节不然签名算法会直接抛异常。5.2 Security过滤链配置后接口全被拦截Spring Security默认会拦住所有请求如果你只是加了starter依赖但没配放行规则注册接口也会返回401。排查时先看SecurityFilterChain里的requestMatchers配置明确哪些接口permitAll哪些需要认证。另一个隐藏问题是静态资源和错误页也会被拦截必要时也要放行。我习惯把所有白名单路径统一列在一个配置常量里改动时只动一个地方。5.3 前端拿不到自定义异常信息这个坑非常常见。业务异常抛出后如果全局异常处理器没有拦截到Spring Security的过滤器链会在进入Controller之前就把请求拦下来返回的可能是默认的401页面或者空响应。解决办法是自定义AuthenticationEntryPoint和AccessDeniedHandler在里面用ObjectMapper手动写出JSON格式的统一响应体。Claude Code生成这块时我也会专门检查一下确保异常响应格式和正常响应一致前端才能统一处理。5.4 Lombok版本冲突Spring Boot 3.x对Lombok版本有要求用旧版Lombok会导致编译时报“找不到符号”或者注解处理器异常。这个没什么玄学直接升级到和Spring Boot版本兼容的Lombok版本就行。如果出现编译报错但代码看起来没问题优先怀疑Lombok版本和JDK版本的匹配关系。5.5 分页查询返回结构不一致用Spring Data JPA的Page接口返回数据时默认结构里包含totalPages、totalElements、pageNumber等字段但如果直接把这个Page对象塞进统一响应体前端拿到的格式和你约定好的分页结构可能对不上。我的做法是手动构建一个PageVO只包含list、total、pageNum、pageSize四个字段前端对接起来统一。Claude Code生成分页接口时也会按这个约定来省得每次联调时扯皮。5.6 常见问题速查表症状大概率原因解决办法注册接口返回401Security过滤链未放行配置requestMatchers放行注册登录接口JWT签名时报错密钥长度不足或API版本不匹配使用Keys.hmacShaKeyFor并保证密钥至少32字节响应里出现密码字段直接返回了实体对象使用VO/DTO返回显式排除敏感字段编译报“找不到符号”Lombok版本与JDK/Spring版本不兼容升级Lombok版本接口返回500但日志没异常异常被框架吞掉检查全局异常处理器是否覆盖了ControllerAdvice禁用账号仍能登录登录逻辑没校验status字段在登录校验和token签发前统一判断用户状态6. 实操心得与后续扩展方向这一轮做下来我最大的体会有两点。第一Claude Code这类工具真正的杠杆在于“规范沉淀”而不只是“代码生成”。同样是用AI写用户管理模块不加skill的情况下它每次生成的代码风格都不同你要花时间审查和修改加了skill之后它输出的代码从一开始就符合你的项目约定审查成本低了一个量级。这个收益在项目数量增多后会越来越明显。第二用户管理模块虽然简单但它是很多系统的骨架。把认证方式、异常约定、统一响应、分页结构这些基础决策做好后面加角色权限、菜单管理、部门管理都只是顺着同样的路子扩展而已。我在这次项目里没有做refresh token但在JWT工具类里预留了刷新的方法也没有做角色权限表但用户表里预留了role字段——这些扩展点都是为了让后续迭代不用动大手术。最后分享一个我实际操作中的小技巧在把项目交给Claude Code之前先花15分钟把“表结构定义”“分层规范”“统一响应约定”这几个核心约束写进项目文档然后让Claude Code读取这些文档再开始生成代码。这个习惯比任何提示词都管用因为AI对项目上下文的利用能力远被大多数开发者低估了——它读得懂你写的东西只要你愿意先写清楚。如果你也想在自己的项目里试这套玩法我建议从一个小模块开始比如就做一个最简单的用户注册登录把skill定义、代码生成、安全接入、问题排查整个流程走一遍再决定要不要规模化使用。工具终究只是工具真正决定项目质量的还是你定义的规范和判断力。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑