DeepSeek using Claude Code 重构Oracle Fusion/SAP最佳业务实践:修正Facade 接口、DTO、API及其它编程规范

前言:

在最初开始编程之前,其实我说了要使用facade模式,并且还要求claude code写道了相关的SKILL,但是我并没有仔细检测这个SKILL;因为我认为这是一个非常简单的事情。结果等我把安全模块基本开发完了,检查代码合规性的时候发现了问题。

❯ 讨论:在开始开发业务系统之前 ,我想解决 facade模式以及将来把业务方法导出为API ,并支持agent 操作的问题。据上次聊天的信息,当前的安全模块没有采用接口,是这样的吗

● 分析完成。以下是我对当前架构的总结和讨论要点。


当前状态确认

是的,安全模块完全没有使用 Java 接口。 整个 openlabx.org.cn.security 包中零个自定义接口。

当前架构层次

Web 层 (JSF @Named Bean)

↓ @Inject

Facade (@Stateless) ------ 薄层,仅做委托

↓ @Inject

Service (@Stateless / @ApplicationScoped) ------ 实际业务逻辑

↓ @PersistenceContext

EntityManager / JPA

当前存在的问题

┌────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────┐

│ 问题 │ 说明 │

├────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤

│ 无接口契约 │ Facade 和 Service 都是具体类,没有抽象接口,调用方直接依赖实现 │

├────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤

│ 耦合泄露 │ RoleFacade 的方法签名暴露了 RoleService.PermissionAssignment、RoleService.RoleDiff 等 Service 内部类 │

├────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤

│ 不一致的职责 │ UserFacade 有些方法委托给 Service,有些直接操作 EntityManager(如 searchUsers()、assignRoleToUser()) │

├────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤

│ 覆盖不完整 │ AuthorizationService、AuthorizationEngine 等没有 Facade 包装,Web 层直接注入 │

├────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤

│ 无法导出 API │ 没有接口定义,无法基于接口自动生成 REST API 或 OpenAPI 文档 │

├────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤

│ Agent 无法操作 │ Agent 需要明确的服务契约(输入/输出/语义),当前只能通过方法签名猜测 │

└────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────┘


建议的改进方向

我建议分三个维度来讨论:

  1. 引入接口层 --- 建立清晰的业务契约

IUserService (接口)

↓ implements

UserService (EJB @Stateless)

UserFacade 不再需要,或者 Facade 就是 REST 适配层

每个业务模块定义接口,接口 = 业务能力的声明。好处:

  • 调用方依赖抽象而非实现

  • 方便做单元测试(mock 接口)

  • 接口本身就是 API 文档

  1. API 导出策略

有了接口后,有两种路线:

  • REST 适配层:在接口之上加 JAX-RS 资源类,自动映射到 REST 端点

  • 直接 EJB Remote:通过 @Remote 接口暴露 EJB,由应用服务器处理远程调用

考虑到你要支持 Agent 操作,REST + OpenAPI 更合适,Agent 可以消费 OpenAPI spec。

  1. Agent 支持

Agent 需要的是:

  • 声明式 API 描述(OpenAPI / 自定义注解描述每个操作的前置条件、副作用、参数约束)

  • 统一的调用入口(一个 Agent Gateway 接收自然语言意图,路由到具体的业务方法)

  • 操作审计(Agent 的每次调用都需要记录到 AuditLog)


你怎么看这个方向?我特别想确认几点:

  1. 接口的粒度 --- 是按模块一个接口(如 IUserService),还是更细?

  2. API 导出的优先级 --- 是先做接口抽象再考虑 REST,还是一步到位?

  3. Agent 的形态 --- 是内部 Agent(同进程调用 EJB),还是通过 REST 的外部 Agent?

✻ Churned for 2m 25s

❯ 我考虑的是安全就完全不动了,因为安全只有一个user需要用API取做。我考虑的是其它CRM/HR/财务。

● 明白,安全模块基本定型不动了,重点是即将开始的 CRM、HR、财务等业务模块。让我确认一下目前是否有这些模块的任何代码。

Searched for 1 pattern, listed 1 directory (ctrl+o to expand)

● 确认了 --- 除了安全模块,CRM/HR/财务等业务代码完全是空白。这是建立架构的最佳时机。


新业务模块架构讨论

从安全模块可以提炼出好的部分(Facade 分层、EJB 封装),同时补上缺失的部分(接口抽象、API 导出、Agent 契约)。

我建议的分层模型

┌─────────────────────────────────────────────┐

│ REST API 层 (JAX-RS) │ JSF Web 层 │ ← 两种前端通道

├─────────────────────────────────────────────┤

│ Facade (@Stateless) │ ← 统一入口,事务边界

│ 实现业务接口 (IBizService) │

├─────────────────────────────────────────────┤

│ Service (@Stateless) │ ← 核心业务逻辑

│ 实现同一业务接口 │

├─────────────────────────────────────────────┤

│ JPA Entity / Repository │ ← 数据持久化

└─────────────────────────────────────────────┘

关键差异:

  • Facade 和 Service 都实现同一个接口 --- Facade 是 Service 的代理,不只是简单委托

  • Facade 是事务边界 + 安全拦截点 --- 不做业务逻辑,但负责 @Transactional、参数校验、审计日志

  • Service 是纯业务逻辑 --- 可独立单元测试,不依赖容器

  • REST 层直接调用 Facade,不经过 JSF

需要你确认的几个设计决策

在讨论具体的 CRM/HR/财务之前,我想先确认三个方向性问题:

  1. 项目结构 --- 单模块 vs 多模块 Maven?

当前是一个 openbusiness-security WAR。后续是:

  • A) 一个大的 openbusiness 多模块项目(openbusiness-common、openbusiness-crm、openbusiness-hr、openbusiness-finance)

  • B) 每个业务域独立 Maven 项目,各自独立部署

  1. 接口粒度 --- 接口怎么划分?
  • A) 粗粒度:每个聚合根一个接口(如 ICustomerService、IOrderService)

  • B) 中粒度:按功能域划分(如 ICustomerCommandService + ICustomerQueryService,CQRS 风格)

  • C) 按你的业务场景来定

  1. Agent 支持的程度 --- 你期望 Agent 怎么操作业务?
  • A) Agent 调用 REST API(外部 Agent,通过 OpenAPI spec 发现能力)

  • B) Agent 直接注入 EJB Facade(内部 Agent,同 JVM 进程)

  • C) 两者都要支持,通过统一接口抽象

这些选择会影响接口设计、异常模型、以及 DTO 的边界定义。你的想法是什么?

❯ 讨论:1 除非部署文件非常大,暂时是一个比较大的部署在一起(比如销售、服务和市场营销组成的CRM) ,2 、结构粒度,一个业务组件一个接口,比如用户,角色,(客户)账户,商机,线索等 3、Agent

调用 REST API;对我上面的决定有什么意见? 我其实不是很专业,至少没有真正干过。

● 你的三个决定都很合理,说实话不像"没真正干过"的人做的判断。逐个说:


对你三个决定的意见

  1. CRM 作为一个部署单元 → 完全同意

销售、服务、市场营销共享客户数据,拆成三个微服务反而会带来分布式事务和数据同步问题。这叫 modular monolith------部署是单体,内部是模块化的。很多团队拆微服务拆早了,最后又合回来。

唯一需要警惕的是:WAR 包内按 package 做好模块隔离,不要让销售代码直接调服务代码的内部类。

  1. 一个业务组件一个接口 → 粒度刚好

账户(Account)、商机(Opportunity)、线索(Lead) 在 DDD 里叫"聚合根",每个都是一个自然的业务边界。一个接口一个组件,维护和理解成本都低。

  1. Agent 调 REST API → 正确方向

这是最灵活的选择。Agent 可以是 Python/Node.js/任何语言写的外部进程,通过 OpenAPI spec 发现能力,完全解耦。


我真正想提醒的三件事

这三件事安全模块做得不好,新模块应该从一开始就做对。

问题一:不要把 JPA Entity 直接暴露到 API 层

当前安全模块的 UserFacade 直接返回 User 实体给 Web 层。做 REST API 时这会有三个坑:

  • 懒加载陷阱:Entity 离开事务边界后,调用 user.getRoles() 直接抛 LazyInitializationException

  • 敏感字段泄露:passwordHash 绝不能出现在 API 响应里

  • 数据库变更影响 API 契约:加个数据库字段,API 就变了,Agent 就坏了

应该做:Facade 返回 DTO,Entity ↔ DTO 转换在 Facade 层完成。

// 不好的做法(当前安全模块)

public User findById(Long userId) {

return em.find(User.class, userId); // 暴露了 Entity

}

// 应该的做法

public UserDto findById(Long userId) {

User user = em.find(User.class, userId);

return UserDto.from(user); // DTO 只包含对外需要的字段

}

问题二:Facade 应该是事务和安全的边界,而不是透明代理

当前 UserFacade.createUser 只是 return userService.createUser(...) 一行委托。这层太薄了,没发挥价值。

Facade 的真正职责应该是:

┌─────────────────────────┬─────────┬────────────────────────────────────┐

│ 职责 │ 放哪层 │ 原因 │

├─────────────────────────┼─────────┼────────────────────────────────────┤

│ @Transactional 事务控制 │ Facade │ 一个 API 调用 = 一个事务 │

├─────────────────────────┼─────────┼────────────────────────────────────┤

│ 参数校验 │ Facade │ 在边界上就拦截非法请求 │

├─────────────────────────┼─────────┼────────────────────────────────────┤

│ 权限检查 │ Facade │ @CheckPermission("account:create") │

├─────────────────────────┼─────────┼────────────────────────────────────┤

│ 审计日志 │ Facade │ 谁、何时、调了什么方法 │

├─────────────────────────┼─────────┼────────────────────────────────────┤

│ 业务逻辑 │ Service │ 纯逻辑,可测试 │

├─────────────────────────┼─────────┼────────────────────────────────────┤

│ 数据访问 │ Service │ 通过 EntityManager │

└─────────────────────────┴─────────┴────────────────────────────────────┘

问题三:Agent 不只是调 API,还需要元数据

Agent 调用 REST API 时,它需要知道:

  • 这个操作是读还是写?(GET/POST?)

  • 参数怎么填?(字段含义、必填/可选、格式约束)

  • 出错怎么办?(错误码含义)

  • 调用链是什么?(创建账户 → 关联联系人 → 创建商机)

这些信息如果靠人工写文档,很快就会和代码脱节。应该从接口定义自动生成。推荐的做法:

接口 (@Contract 注解描述)

实现类 (EJB)

REST 资源类 (JAX-RS)

OpenAPI 文档 (自动生成)

Agent 消费 OpenAPI spec

可以在接口上加自定义注解描述业务语义,Agent 通过 OpenAPI + 这些注解理解每个操作的含义。


总结

三个方向决定都对。接下来需要确定的细节是:

  1. DTO 要不要和 Entity 一一对应,还是按 API 场景定制(列表 DTO vs 详情 DTO)?

  2. 权限注解是放在 Facade 接口上还是实现类上?

  3. 要不要我先画一个 CRM 模块(比如"客户账户")的完整接口-Facade-Service-REST 示例代码,你看了再调整?

❯ 关于DTO和权限注解我都没法给出我认为正确的决定,我以前只知道同一个实体可以创建一个或多个DTO,关于 按 API 场景定制(列表 DTO vs 详情 DTO) 完全不清楚;我以前理解的Facade

接口就是为了更好解耦的技术,没有关注权限的细节;关于第三个 如果 要编写示例代码,我可以提供一个线索的操作步骤文档,根据使用的属性编写示例代码:1. Navigate to Sales > Leads.

  1. Click the Create Lead (or + icon) button on the top right.

  2. Fill in the required fields in the creation drawer:

o Name (Text): A descriptive title for the lead (e.g., 50x Cloud Licenses - TechCorp).

o Lead Status (Dropdown): Select Unqualified or New.

o Deal Size (Number & Currency): Estimated monetary value (e.g., 50,000 USD).

o Contact - First Name / Last Name (Text): The primary contact person's name at the prospect company.

o Company (Text/Search): Enter the company name. If it exists in the system as an account, search and link it; otherwise, type the new name to create a prospect.

o Email / Phone (Text): Contact details for the prospect.

● 好的,我先解释这两个概念,然后用你给的线索创建流程来写完整示例。


DTO 设计解释

"列表 DTO vs 详情 DTO"其实很直观。看一个例子:

列表页显示线索表格,你需要展多少字段?可能就 6 个:

| 名称 | 状态 | 金额 | 公司 | 联系人 | 创建日期 |

详情页打开一个线索的完整信息,可能 15-20 个字段,还包括关联对象。

如果列表和详情用同一个 DTO:

  • 列表页加载了 15 个不需要的字段 → 浪费

  • 详情页需要关联对象数据,列表页不需要 → 要么 N+1 查询,要么少加载导致详情页缺数据

所以按场景定制 DTO:

┌───────────────────┬──────────────┬──────────────────────────────────────────────────────────────┐

│ DTO 类型 │ 用途 │ 包含内容 │

├───────────────────┼──────────────┼──────────────────────────────────────────────────────────────┤

│ LeadListItem │ 表格/列表 │ id, name, status, dealSize, companyName, createdAt (6个字段) │

├───────────────────┼──────────────┼──────────────────────────────────────────────────────────────┤

│ LeadDetail │ 详情/编辑 │ 全部字段 + 嵌套的 Contact 信息 + Account 信息 │

├───────────────────┼──────────────┼──────────────────────────────────────────────────────────────┤

│ CreateLeadRequest │ 创建表单提交 │ 表单需要的可填字段 + 校验注解 │

├───────────────────┼──────────────┼──────────────────────────────────────────────────────────────┤

│ UpdateLeadRequest │ 编辑表单提交 │ 可修改的字段子集 │

└───────────────────┴──────────────┴──────────────────────────────────────────────────────────────┘

这不是过度设计------每个 DTO 只包含对应场景真正需要的数据,性能和安全都更好。


权限注解放哪里

放在 Facade 接口上。原因很简单:

接口方法上声明 → 谁实现的都要遵守,不会漏

接口上声明 → 写单元测试只需要 mock 接口,不需要启动容器

Facade 做检查 → Service 是纯逻辑,测试时完全不用管权限

Service 不应该知道"权限"这个概念------它只管业务规则。一个方法到了 Service,说明调用者已经通过了权限检查。


示例代码

我来根据你的线索创建流程写一套完整代码。先确认一下实体关系:

  • Lead(线索):一个潜在商机,关联一个 Account(公司)和一个 Contact(联系人)

  • Account(客户/账户):存在系统中的公司,可能是已有客户,也可能是新创建的 prospect

  • Contact(联系人):人的信息

我先写好,然后你看了再调整方向。

● 先创建目录结构。

● Bash(mkdir -p /home/clauder/projects/openbusiness/src/main/java/openlabx/org/cn/crm/{entity,dto,service,facade,rest} && mkdir -p /home/clauder/projects/openbusiness/...)

⎿ Done

● Now 写所有示例文件。先从底层开始 --- 实体、枚举、通用类。

....................................

....................................

....................................

全部修改完成。验证一下最终的文档结构。

Searched for 1 pattern (ctrl+o to expand)

● 文档结构完整。快速抽查几处关键修改。

Read 1 file (ctrl+o to expand)

SKILL.md 更新完成。828 行 → 1094 行,改动汇总:


修改明细

┌───────────────────┬──────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐

│ 节 │ 操作 │ 内容 │

├───────────────────┼──────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤

│ §2 Facade 模式 │ 重写 │ 接口 + Facade + Service 三层职责;Facade = 事务+权限+审计+DTO映射;Service = 纯业务逻辑 │

├───────────────────┼──────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤

│ §2 新增 DTO │ 新增 │ 四种场景 DTO(ListItem/Detail/CreateRequest/UpdateRequest);不可变约束;禁止 Entity 外泄 │

├───────────────────┼──────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤

│ §3 数据持久 │ 追加 │ JPA Entity 禁止暴露到 EJB 层之外 │

├───────────────────┼──────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤

│ §6.4.1 声明式权限 │ 新增 │ @RequirePermission 注解定义 + PermissionInterceptor CDI 拦截器 + 使用约束 │

├───────────────────┼──────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤

│ §7 包命名 │ 更新 │ 新增 sales/service/marketing/hcm/finance;新增 common 包;子包改为 entity/dto/service/facade/rest/web;加职责速查表 │

├───────────────────┼──────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤

│ §8 REST API │ 新增 │ JAX-RS Resource 标准;与 Facade 的关系;Agent 消费 OpenAPI 流程;URL 路径规范;POST/GET/DELETE 约定 │

├───────────────────┼──────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤

│ §9 生成代码 │ 原 §8 重编号 │ 内容不变 │

└───────────────────┴──────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

没有改动的部分

  • §4 日志规范(JUL)

  • §5 密码哈希

  • §6.1-6.3/6.5-6.10 安全认证体系

  • 安全模块现有包结构(security.ejb 保留不变)

现在可以用这个更新后的 SKILL 来规范后续 Sales/Service/Marketing 等模块的开发了。

相关推荐
西山创罪梦不觉3 小时前
PCA主成分分析1--(矿相定向重构、高效协同浸出)
重构
Urbano4 小时前
跳出服装赛道:智能模板机如何重构扫地机清洁耗材量产新标准
人工智能·重构·自动化
VIP_CQCRE4 小时前
把 Ace Data Cloud 接入 AI 助手:MCP 平台管理与文档检索实战
ai·大模型·api·mcp·acedatacloud
世界很奇妙塔1 天前
大模型轻量化技术攻坚:从千亿参数到端侧部署,重构AI落地底层路径
人工智能·重构
EasyDSS1 天前
视频直播点播/音视频点播/云点播/云直播EasyDSS智慧校园:一屏直播,全场景重构“教、学、练、测、评”
重构·音视频
2601_956865771 天前
# 2026年AI API中转平台选型指南:高并发能力、协议兼容与白盒计费体系深度解析
人工智能·api
QiLinkOS1 天前
QiLink OS的失败数据共享平台的运作模式是否适用于所有行业?
android·开发语言·人工智能·算法·重构·开源
VIP_CQCRE1 天前
用 Ace Data Cloud 快速接入 Sora 2 API:把视频生成变成可落地的业务能力
api·ai视频·sora·ace data cloud
VIP_CQCRE2 天前
用 Ace Data Cloud 快速接入 OpenAI 图像生成 API:GPT-Image-2 与 Nano Banana 统一调用
ai·openai·api·ace data cloud·image generation