ARTICLE DETAIL

资讯详情

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

DeepSeek 搭配 Claude Code 重构 Oracle Fusion/SAP 最佳业务实践:安全模块部署包文件大小与 Jakarta EE 11 标准适配

DeepSeek 搭配 Claude Code 重构 Oracle Fusion/SAP 最佳业务实践:安全模块部署包文件大小与 Jakarta EE 11 标准适配 1. 从 171 KB 的 WAR 说起Oracle Fusion/SAP 安全模块为什么值得重构如果你所在的公司采购了 Oracle WebLogic、IBM WebSphere 或者国产应用服务器却还在上面跑 Spring Boot 内嵌 Tomcat 的架构那基本等于买了一台越野车只在小区里代步。Oracle Fusion 中间件和 SAP NetWeaver 本身就完整实现了 Jakarta EE 规范EJB 容器、JPA 持久化、JSF 渲染、JTA 事务、JMS 消息、安全域集成这些能力全部内置且经过企业级验证。你额外引入 Spring 全家桶不仅多背了几十 MB 的依赖还把服务器自带的安全域、连接池、事务管理器全部绕开了。我最近在做一个安全控制台模块的重构目标很明确用 Jakarta EE 11 标准JSF EJB JPA重写不引入任何第三方 JSF 组件库不引入第三方 JS 库前端只用原生 HTML/CSS/JS。整个模块涵盖认证、授权、角色管理、用户管理、权限矩阵、角色层级、审计日志、菜单管理八大功能。重构完成后的部署包openbusiness-security.war只有171 KB内含 35 个 EJB 类、11 个 Entity 类、14 个 XHTML 页面以及配套的 CSS/JS。这个体积是什么概念同等功能的 Spring Boot 安全模块光spring-boot-starter-securityspring-boot-starter-data-jpa Thymeleaf 的依赖树就能轻松超过 40 MB。171 KB 对比 40 MB差距是 200 倍以上。这不是压缩技巧而是架构选择带来的根本差异——把能力交还给应用服务器而不是在每个 WAR 里重复打包一遍。这篇文章会完整走一遍重构流程从 DeepSeek 做代码分析与方案设计到 Claude Code 执行实际重构再到通过 TaoToken 统一接入 API 通道最后给出可复制的settings.json和config.toml配置骨架以及部署包体积对比和 Jakarta EE 11 兼容性验证动作。适合正在做 Oracle Fusion/SAP 业务实践、考虑从 Spring 迁移到标准 Jakarta EE 的团队参考。2. 重构前的三个核心问题2.1 依赖膨胀一个安全模块为什么要 40 MB传统 Spring 方案下一个安全模块的依赖清单大致是这样的Spring Security 核心 Web Config 约 8 MBSpring Data JPA Hibernate 约 15 MBThymeleaf 约 3 MB再加上各种 transitive dependency最终 fat jar 轻松突破 40 MB。问题在于这些依赖里的大部分功能Oracle WebLogic 和 WebSphere 早就提供了。EJB 容器提供声明式事务和安全JPA 提供持久化JSF 提供视图层JTA 提供分布式事务JAAS/Jakarta Security 提供认证授权。你在 WAR 里再打包一套 Spring 的实现等于在已经有发动机的车里再塞一台发动机。2.2 标准适配Jakarta EE 11 的命名空间迁移Jakarta EE 9 开始所有javax.*包名迁移到jakarta.*。到 Jakarta EE 11这个迁移已经完成同时带来了几个关键变化Jakarta Security 3.0 引入了新的SecurityContextAPIJakarta Faces 4.1 增强了 WebSocket 集成Jakarta Persistence 3.2 支持了新的查询特性。如果你的代码还停留在javax.persistence.Entity在 Jakarta EE 11 容器上会直接报ClassNotFoundException。2.3 团队技能只会 Spring 的人怎么办这是最现实的顾虑。过去不敢用 EJB JSF是因为学习曲线陡、调试困难、社区资料少。但现在有了 AI 编程助手这个顾虑基本可以放下。EJB 的StatelessInject比 Spring 的ServiceAutowired更简洁JSF 的 Facelets 比 Thymeleaf 更贴近 HTML。AI 能帮你把 Spring 的写法翻译成 Jakarta EE 的写法而且标准 API 的稳定性远高于框架 API。3. TaoToken 前置统一 Key 与 API 通道在开始重构之前需要先把 AI 编程助手的接入通道准备好。我用的方案是通过 TaoToken 统一管理 API Key这样 DeepSeek 和 Claude Code 可以共用一套凭证体系不用在多个平台之间来回切换。TaoToken 的定位是统一的模型 API 接入层支持 DeepSeek、Claude 等主流模型的调用。对于这个重构项目我的分工是DeepSeek 负责代码分析和方案设计成本低、上下文长Claude Code 负责实际的文件修改和命令执行工具调用能力强。接入步骤很直接。首先访问 TaoToken 官网 注册账号然后在控制台创建一个 API Key。这个 Key 同时可以用于 DeepSeek 和 Claude 的调用。创建 Key 的入口在 Console 控制台进入后找到 API Keys 管理页面点击创建新 Key。建议给 Key 起一个有意义的名字比如openbusiness-refactor方便后续区分不同项目的用量。API 的基础地址是https://taotoken.net/api这个地址在配置 Claude Code 和 DeepSeek SDK 时都会用到。注意 API 地址不带 UTM 参数直接使用即可。注意API Key 创建后只显示一次务必立即复制保存到安全的地方。如果丢失只能重新创建。4. 可复制配置settings.json 与 config.toml 骨架4.1 Claude Code 的 settings.jsonClaude Code 的配置文件位于~/.claude/settings.json。这个文件控制模型选择、API 端点、工具权限等。以下是我在实际重构中使用的配置骨架{ model: claude-sonnet-4-20250514, apiProvider: custom, apiBaseUrl: https://taotoken.net/api, apiKey: sk-your-taotoken-key-here, maxTokens: 8192, temperature: 0.2, permissions: { allow: [ Bash(unzip -l *), Bash(find *), Bash(grep *), Bash(mvn *), Read(*), Write(src/main/java/openlabx/org/cn/security/**), Write(src/main/webapp/**) ], deny: [ Bash(rm -rf *), Bash(git push --force *) ] }, projectContext: { language: java, framework: jakarta-ee-11, buildTool: maven, sourceRoot: src/main/java, webRoot: src/main/webapp } }几个关键点说明。apiBaseUrl指向 TaoToken 的 API 地址apiKey填入你在控制台创建的 Key。temperature设为 0.2 是因为重构任务需要确定性输出不需要太多创造性。permissions.allow里我放开了unzip -l、find、grep、mvn这些只读或构建命令以及针对安全模块目录的写入权限。deny里禁止了rm -rf和强制推送防止误操作。4.2 DeepSeek 的 config.tomlDeepSeek 的配置我用 TOML 格式管理放在项目根目录的.deepseek/config.toml[api] base_url https://taotoken.net/api api_key sk-your-taotoken-key-here model deepseek-chat max_tokens 16384 temperature 0.3 [context] project_root /home/clauder/projects/openbusiness include_patterns [ src/main/java/**/*.java, src/main/webapp/**/*.xhtml, pom.xml ] exclude_patterns [ target/**, *.class, .git/** ] [analysis] focus [jakarta-ee-migration, dependency-audit, package-size] report_format markdownmax_tokens设到 16384 是因为 DeepSeek 支持长上下文分析整个模块的代码结构时需要较大的输出空间。include_patterns限定了分析范围避免把target目录下的编译产物也读进来。4.3 Maven pom.xml 的 Jakarta EE 11 依赖重构后的pom.xml关键依赖部分全部使用providedscope因为运行时由应用服务器提供properties maven.compiler.source21/maven.compiler.source maven.compiler.target21/maven.compiler.target jakarta.jakartaee-api.version11.0.0/jakarta.jakartaee-api.version /properties dependencies dependency groupIdjakarta.platform/groupId artifactIdjakarta.jakartaee-api/artifactId version${jakarta.jakartaee-api.version}/version scopeprovided/scope /dependency /dependencies build finalNameopenbusiness-security/finalName plugins plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-war-plugin/artifactId version3.4.0/version configuration failOnMissingWebXmlfalse/failOnMissingWebXml packagingExcludes WEB-INF/lib/*.jar /packagingExcludes /configuration /plugin /plugins /buildpackagingExcludes排除WEB-INF/lib下的所有 jar因为所有依赖都是provided不需要打进 WAR。这是 171 KB 体积的关键——WAR 里只有编译后的 class 文件和静态资源。5. 重构执行从 Spring 到 Jakarta EE 11 的迁移步骤5.1 第一步用 DeepSeek 做依赖审计先让 DeepSeek 分析现有项目的依赖树找出哪些是可以被应用服务器替代的mvn dependency:tree -DoutputFiledeps.txt然后把deps.txt和pom.xml一起喂给 DeepSeek提示词如下分析这个 Maven 项目的依赖树识别出以下类别 1. 可以被 Jakarta EE 11 容器替代的依赖如 Spring Security - Jakarta Security 2. 必须保留的第三方依赖 3. 存在版本冲突的依赖 输出格式表格列为 [依赖坐标, 当前版本, 替代方案, 风险等级]DeepSeek 会返回一份清晰的对照表。我实测下来一个典型的安全模块有 60% 以上的依赖可以被容器替代。5.2 第二步包名迁移 javax 到 jakarta这是机械但必须精确的工作。用 Claude Code 批量执行find src/main/java -name *.java -exec sed -i \ -e s/javax\.persistence/jakarta.persistence/g \ -e s/javax\.ejb/jakarta.ejb/g \ -e s/javax\.inject/jakarta.inject/g \ -e s/javax\.enterprise/jakarta.enterprise/g \ -e s/javax\.faces/jakarta.faces/g \ -e s/javax\.security/jakarta.security/g \ -e s/javax\.validation/jakarta.validation/g \ -e s/javax\.annotation/jakarta.annotation/g \ {} 执行完后用grep -r javax\. src/main/java检查是否有遗漏。注意javax.sql.DataSource和javax.naming不在迁移范围内这两个包在 Jakarta EE 11 中仍然保留javax前缀。5.3 第三步EJB 层重构原来的 SpringService类改成 EJBStatelessAutowired改成Inject。以用户服务为例package openlabx.org.cn.security.ejb; import jakarta.ejb.Stateless; import jakarta.inject.Inject; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; Stateless public class UserService { PersistenceContext(unitName securityPU) private EntityManager em; Inject private PasswordHasher passwordHasher; public User createUser(User user, String rawPassword, String createdBy) { user.setPasswordHash(passwordHasher.hash(rawPassword)); user.setCreatedBy(createdBy); user.setCreatedAt(java.time.Instant.now()); em.persist(user); return user; } public java.util.ListUser searchUsers(String query, int offset, int limit) { return em.createQuery( SELECT u FROM User u WHERE LOWER(u.username) LIKE :q ORDER BY u.username, User.class) .setParameter(q, % query.toLowerCase() %) .setFirstResult(offset) .setMaxResults(limit) .getResultList(); } }注意这里没有定义Local接口用的是 EJB 3.1 的 no-interface view。容器会从具体类直接生成代理Inject按具体类型注入即可。这比 Spring 的接口 实现模式少写一个文件。5.4 第四步JSF 视图层重构Facelets 页面用纯 XHTML不引入 PrimeFaces 等第三方组件库。一个典型的用户列表页!DOCTYPE html html xmlnshttp://www.w3.org/1999/xhtml xmlns:hjakarta.faces.html xmlns:fjakarta.faces.core h:head title用户管理/title h:outputStylesheet namecss/security.css/ /h:head h:body h:form iduserForm h:inputText value#{userBean.query} placeholder搜索用户名/ h:commandButton value搜索 action#{userBean.search}/ h:dataTable value#{userBean.users} varu border1 h:column f:facet nameheader用户名/f:facet #{u.username} /h:column h:column f:facet nameheader角色/f:facet #{u.roleName} /h:column h:column f:facet nameheader操作/f:facet h:commandLink value编辑 action#{userBean.edit(u.id)}/ /h:column /h:dataTable /h:form /h:body /htmlh:dataTable是 JSF 标准组件不需要任何第三方库。样式通过h:outputStylesheet加载自定义 CSS整个前端资源加起来不到 20 KB。5.5 第五步打包与体积对比执行mvn clean package后对比重构前后的 WAR 体积ls -lh target/openbusiness-security.war unzip -l target/openbusiness-security.war | tail -n 4 | head -60重构前的 Spring 版本 fat jar 约 42 MB重构后的 Jakarta EE 版本 WAR 为 171 KB。体积缩减比例超过 99%。具体构成如下内容类型文件数大小EJB 类.class35约 85 KBEntity 类.class11约 22 KBXHTML 页面14约 38 KBCSS/JS6约 18 KB配置文件3约 8 KB合计69171 KB6. 验证请求与成功结果6.1 部署到 Oracle WebLogic把 WAR 部署到 WebLogic 12.2.1.4支持 Jakarta EE 11 的版本需要 WebLogic 15c 或更高。部署命令$DOMAIN_HOME/bin/weblogic.Deployer \ -adminurl t3://localhost:7001 \ -username weblogic \ -password welcome1 \ -deploy target/openbusiness-security.war \ -name openbusiness-security \ -targets AdminServer部署成功后访问http://localhost:7001/openbusiness-security/应该能看到登录页。6.2 验证 EJB 注入在 WebLogic 控制台的 EJB 模块页面应该能看到 35 个 EJB 被正确注册。检查UserFacade、RoleFacade等 Facade 类的状态为Active。6.3 验证 Jakarta EE 11 兼容性用以下命令检查 WAR 中是否还有javax残留unzip -p target/openbusiness-security.war \ WEB-INF/classes/openlabx/org/cn/security/ejb/UserService.class \ | strings | grep -c javax\.输出应该为 0。如果有非零值说明还有未迁移的引用。6.4 通过 TaoToken 验证模型调用在重构过程中我用 TaoToken 的模型对话功能验证代码片段的正确性。访问 模型对话把 EJB 代码粘贴进去让模型检查是否符合 Jakarta EE 11 规范。这个步骤在迁移初期特别有用能快速发现Local接口缺失、PersistenceContext单元名错误等问题。7. 本篇常见错排查7.1 ClassNotFoundException: javax.persistence.Entity这是最常见的错误说明包名迁移不完整。用grep -r javax.persistence src/main/java定位残留文件。注意 IDE 的自动导入可能又给你导回了javax版本检查 import 语句。7.2 EJB 注入失败No EJB found for injection如果Inject报找不到 EJB检查三点类上是否有Stateless或Stateful是否在beans.xml中声明了 bean-discovery-modeJakarta EE 11 默认是annotated不需要显式声明以及是否在同一个部署单元内。7.3 JSF 页面报 TagLibraryExceptionJakarta Faces 4.1 的命名空间是jakarta.faces.html而不是http://xmlns.jcp.org/jsf/html。所有 XHTML 页面的 xmlns 声明都要更新。用grep -r xmlns.jcp.org src/main/webapp检查。7.4 WAR 体积异常增大如果打包后 WAR 超过 1 MB检查pom.xml中是否所有依赖都设了providedscope。特别容易漏的是jakarta.jakartaee-api如果 scope 是compile整个 API jar 会被打进 WAR。7.5 WebLogic 部署报 UnsupportedClassVersionErrorJakarta EE 11 要求 Java 21 编译。检查maven.compiler.source和target是否都设为 21以及 WebLogic 的 JVM 版本是否支持 Java 21。WebLogic 15c 默认使用 Java 21。7.6 TaoToken API 返回 401检查settings.json和config.toml中的apiKey是否正确复制注意不要有多余空格。如果 Key 已过期去 API Keys 管理页 重新生成。8. 长期编码与 Agent 场景的接入建议如果你打算把这种重构工作常态化比如持续维护 Oracle Fusion/SAP 的安全模块建议使用 Coding Plan 来管理长期的模型调用。Coding Plan 适合需要频繁调用 API 的编码场景相比按量付费更划算。对于 Claude Code 的深度集成可以参考 Claude Code Anthropic 接入文档里面有完整的配置示例和工具权限说明。接入文档在 API 文档 页面可以找到。回到重构本身171 KB 的 WAR 不是终点。下一步我打算把 Facade 层抽成Local接口为将来可能的跨模块调用做准备。目前所有 EJB 都是 no-interface viewFacade 直接注入 Service模块边界清晰。如果将来需要导出 REST API只需要在 Facade 层加Path注解Service 层完全不用动。这个分层策略是这次重构最大的收获——把变化隔离在边界层核心业务逻辑保持稳定。
返回列表