☰
Oracle APEX深入开发:环境搭建、页面布局与ERP集成
2026/10/27 11:29:03 网站建设 项目流程

简介:《Oracle APEX深入浅出》配套文档面向希望快速掌握 Oracle APEX 的企业级 Web 应用开发者与数据库从业人员,覆盖从入门认知到项目部署的完整知识链路。整包仅含1个 doc 文档,约8.11MB,以单份手册形式组织内容,便于集中阅读和按章节检索。文档从 APEX 简介、环境搭建与账户权限管理讲起,逐步展开页面布局美化、常用控件、Report 增删改、文件上传下载、CSS 与 JS 交互,以及图表报表等深入开发要点,并延伸到 Free Plugins、应用部署、调试技巧与常用 API。内容还涉及 EBS 中配置 APEX 页面调用等集成场景,可帮助读者理解开发流程、积累排错思路并对照实际项目查阅。已有1592人学习,适合作为 APEX 开发过程中的参考指南。

1. 为什么一套"页面都存在数据库里"的开发工具,值得你花一个下午装一遍

做 ERP 二次开发的人,多半被 Form 那套东西折腾过:改一个字段要编译、要打补丁、要搬环境,测试到生产的路径长得让人怀疑人生。第一次打开 Oracle APEX 的管理后台,我的反应是"这不就是一个网页版的 Form 个性化吗"。这个判断八九不离十:APEX 的页面不是磁盘上的文件,而是数据库里的行加一堆 PL/SQL 包,改布局等于改元数据,提交即生效,既没有编译步骤,也没有部署包。也正因为这一点,它的门槛和坑都集中在同一处——环境与元数据管理。这份《Oracle APEX 深入浅出》做的正是从装库、清旧版本、管账户,到 Grid Layout 排版、Dynamic Action、Tabular Form 增删改、再到与 ERP 套件集成的完整链路,讲的是 Oracle APEX 深入开发里那些"配一下就好"背后的原理。适合已经会写 SQL/PL/SQL、但不想在前后端框架上耗时间的后端同学,也适合接手老系统、需要快速给业务开查询或录入界面的人。

2. 环境搭建:从 11g 自带 3.0 升到 4.2.5,六个脚本按顺序跑

2.1 先搞懂运行机制,再决定用什么网关

APEX 引擎完全驻留在数据库里,由数据字典中的元数据表和大量 PL/SQL 对象组成。浏览器发来的 URL 请求被一个 HTTP 入口解析成 PL/SQL 调用,数据库处理完再用sys.htp.p把结果以 HTML 形式吐回去。每个页面请求都在新会话里处理,所以只有在渲染或处理页面那一刻才消耗数据库资源,这也是它能在一台普通数据库服务器上撑住不少轻量应用的原因。

这个"HTTP 入口"就是你安装时要做的选择题,常见三种:嵌入式 PL/SQL 网关(EPG)、基于 Apache 的 mod_plsql、独立的 APEX Listener。11g R1/R2 的 XDB 自带 EPG,dbms_xdb.sethttpport一行就能开端口,不用装 Apache、不用配 DAD 文件,装完即用,适合开发环境和内部系统;代价是性能和并发能力有限,真要上生产还得换独立监听器。10g 没有 EPG,就只能走 mod_plsql 或独立监听器。这份资料里选的是 EPG,我复现时也走的这条路,本文所有步骤都以 EPG 为准。

另一个绕不开的现实是版本。11g 出厂自带 APEX 3.0,你要装 4.2.5 就必须先卸掉旧的,否则同名同义词、老 schema 残留会一路把你带到登录失败上去。我的习惯是把整套东西装在虚拟机里,装完挂起,下次直接恢复,省得再对着端口和目录结构重来一遍。

2.2 卸载旧版本:脚本跑完只是第一步

官方给了卸载脚本,但它只负责删对象,不负责删干净用户。

# 1) 以 SYS 身份跑官方卸载脚本,清 APEX 3.0 的对象 cd $ORACLE_HOME/apex sqlplus / as sysdba @apxdevrm.sql # 2) 清掉旧的 apex 目录内容,避免版本混杂 cd $ORACLE_HOME/apex && rm -rf *

脚本跑完别急着往下走,先查用户。3.0 的 schema 通常叫APEX_030200(更早的还有FLOWS_030000),如果dba_users里还有它们,说明卸载没到根上。

-- 确认是否还有旧版本 schema 残留 select username, account_status from dba_users where username like 'APEX%' or username like 'FLOWS%'; -- 残留的旧版本用户逐个清掉,cascade 会连带对象一起删 drop user APEX_030200 cascade; -- 顺带看一眼有没有指向旧 schema 的失效同义词 select synonym_name, table_owner from dba_synonyms where table_owner like 'APEX%' or table_owner like 'FLOWS%';

这里的判断依据很简单:APEX_030200可以删,APEX_040200是你即将装出来的新引擎,绝对不能删。我在第 5 章会专门讲误删的后果,那是能让你重装一整天的操作。

2.3 建表空间、解压、跑 apexins

APEX 自己的元数据和索引建议单独放一个表空间,别和生产业务表混在一起,备份和迁移时你会感谢自己。

CREATE TABLESPACE APEX01 DATAFILE '/d01/oracle/ORCL/db/apps_st/data/apex01.dbf' SIZE 100M AUTOEXTEND ON NEXT 100M MAXSIZE 1000M;

数据文件路径按你库的实际目录改,ORCL换成自己的实例名。然后解压安装包到$ORACLE_HOME下,会得到一个apex目录,再执行核心安装脚本。

unzip -q apex_4.2.5.zip -d $ORACLE_HOME cd $ORACLE_HOME/apex # 四个参数:APEX 表空间 / 文件与索引表空间 / 临时表空间 / 图片虚拟路径 sqlplus / as sysdba @apexins.sql APEX01 APEX01 TEMP /i/

四个参数必须说清楚。第一个是元数据表空间,第二个放 BLOB 和索引,第三个用默认临时表空间就行,第四个/i/是静态图片的虚拟路径——它必须和后面apxldimg.sql加载图片时用的路径完全一致,否则你会得到一堆 404 的图标和裸奔的页面。整个脚本执行十几到几十分钟不等,中间是大量建表建包,屏幕上刷过去的东西不用逐行看。

2.4 设 ADMIN 密码、解锁公共用户、加载图片与中文

-- 交互式修改 ADMIN 密码,口令必须包含大写、小写、数字和特殊字符 @apxchpwd.sql -- 两个公共账号必须解锁,否则页面渲染直接报认证失败 ALTER USER ANONYMOUS ACCOUNT UNLOCK; ALTER USER APEX_PUBLIC_USER ACCOUNT UNLOCK; ALTER USER APEX_PUBLIC_USER IDENTIFIED BY "Your_Str0ng_Pwd";

APEX_PUBLIC_USER是 EPG 连库时用的账号,密码改了之后要在 DAD 配置里同步,apxconf.sql会帮你处理这一步。图片加载是新手最容易漏的一步,漏了的表现是页面结构正常但全部无样式、图标变成裂图。

# 把 images 灌进 XDB,脚本会提示输入 ORACLE_HOME 路径 sqlplus / as sysdba @apxldimg.sql # 可选:加载简体中文界面 sqlplus / as sysdba @builder/zh-cn/load_zh-cn.sql

2.5 配置 EPG、端口与对外访问授权

-- 创建 DAD 并把 /apex/* 映射到 APEX 引擎 @apxconf.sql -- 确认端口,8888 被占用时换一个 exec dbms_xdb.sethttpport(8888); commit; select dbms_xdb.gethttpport from dual;

如果应用里要调外部 Web 服务,11g 的网络 ACL 还得单独放行,别指望默认能通:

-- 给 APEX 引擎 schema 放行外部主机访问 begin dbms_network_acl_admin.create_acl( acl => 'apex_net.xml', description => 'APEX outbound access', principal => 'APEX_040200', is_grant => true, privilege => 'connect'); commit; end; /

访问http://server:8888/apex/apex_admin能出登录框,http://server:8888/apex能出工作空间登录页,基本就成了。如果 404,先别怀疑安装,按顺序查:端口有没有真的改上去、DAD 有没有建、监听有没有重启。

2.6 装完先过一遍验收清单

检查项命令 / SQL期望结果
EPG 端口select dbms_xdb.gethttpport from dual;返回 8888
DAD 映射select * from dba_epg_dad_authorization;存在/apex/*的 DAD 记录
APEX 版本select version_no from apex_release;4.2.x
公共账号select username, account_status from dba_users where username in ('APEX_PUBLIC_USER','ANONYMOUS');均为 OPEN
图片资源select any_path from resource_view where any_path like '/i/%' and rownum < 5;有记录返回

这五条全绿再往下走,后面所有问题都能排除"环境没装好"这个变量。

3. Workspace 与账户模型:四层身份、七种认证,选错了后面全白干

3.1 四层身份各管什么

APEX 的权限模型第一次看容易糊,其实就是四层:顶层的ADMIN是超级管理员,住在内部的 INTERNAL 工作空间里,负责创建、删除、修改 Workspace 及其管理员;下一层是 Workspace Admin,管自己这个工作空间里的人和应用;再往下是 Developer,负责建页面写逻辑;最末是 App End User,只能跑应用。

关键概念是 Workspace 和数据库 Schema 的对应关系。一个 Workspace 绑定一个 Schema,可以理解成一个工程,工程里可以有很多 Application。在和 ERP 套件集成时,一个 Application 大致相当于一个 Form,Form 里的多个窗口就是页面。所以绑定哪个 Schema,直接决定了你在 SQL Workshop 里能看见哪些表、建的对象落在谁家里。

3.2 建 Workspace 之前先把 Schema 准备好

最省事的做法是让 APEX 自己建 Schema,但接老系统时通常要复用已有的业务 Schema。两种都行,前提是 Schema 里该有的权限得给足,否则你在页面里写个 Process 就报权限不足。

-- 独立 Schema 方案:给 APEX 开发单独开一个用户,别直接往生产 schema 灌对象 create user demo_ws identified by "Your_Str0ng_Pwd" default tablespace APEX01 quota unlimited on APEX01; grant create session, create table, create view, create procedure, create sequence, create trigger to demo_ws;

创建 Workspace 时填这个 Schema 名,系统会要求再设一个 Workspace 管理员账号。之后用管理员进 Workspace,再建 Developer 和最终用户。三个角色别混用,开发阶段图省事全用管理员登录,到上线分配权限时一定返工。

提示:已经有生产 Schema 的情况下,我更倾向在它下面建同义词或授权给 APEX 专用 Schema,而不是让 APEX 直接登录生产 Schema。元数据表和业务表混在一起,导出迁移时会非常难受。

3.3 七种认证方案怎么挑

创建 Application 时会让你三选一,实际可选的认证方案一共有七种:Application Express Accounts、Database Accounts、HTTP Header Variable、LDAP、Oracle SSO、Open Door、Custom。用得最多的是前两种和第三种。

Application Express Accounts 是 APEX 自己的用户体系,登录页由 APEX 生成,用户名密码存在应用里,适合内部开发、测试和用户量不大的管理端。Database Accounts 直接验证数据库用户,好处是不用维护第二套账号,坏处是数据库账号密码策略和 Web 端要求经常打架。

HTTP Header Variable 是集成场景的常用解:应用不接管登录,只信任上游传过来的 header 里的用户名。ERP 套件挂一个 Function 指向 APEX 页面,由套件侧注入当前登录工号,用户点进去就是已登录状态,不用二次输入。这个方案有个硬前提——header 只能由可信的内网入口注入,如果客户端能直接构造请求,就等于谁都能冒充任何人。所以只在内网入口做转发、APEX 不对外暴露时用它。

3.4 Page 0:全局项和全局常量的落脚点

每个 Application 都有一个 0 号页,叫全局页,它在任何页面渲染之前执行,页上定义的项在整个应用里都可见。用途很实在:当前用户、当前日期、当前职责、一堆业务常量,都可以在这里算好,后面页面直接引用,省得每个页面重复写计算。

区域放在 Page 0 上是不会显示在界面上的,效果类似 HTML 里的 hidden 字段。我一般会把不同类型的变量分区域放,比如"会话信息"一个区域、"业务常量"一个区域,日后排查"这个值是哪来的"能省很多时间。

-- Page 0 上的计算项,类型选 PL/SQL Function Body -- 计算点选 "On New Instance",每个新会话算一次 declare l_name varchar2(100); begin select login_name into l_name from demo_user_ctx where user_id = :APP_USER; return l_name; exception when no_data_found then return :APP_USER; end;

:APP_USER是 APEX 内置的绑定变量,认证通过后自动有值。凡是页面上要用到"当前登录人"的地方,都从这个计算项取,别在每页各写一遍 SQL,改起来是灾难。

4. 页面布局与控件:Grid Layout 的 TABLE/TR/TD 映射与 Dynamic Action 三件套

4.1 主题定了,布局的骨架就定了

4.0 以后自带二十个左右的主题,都符合 XHTML 和 CSS 标准,页面可移植性更好、渲染也更快。选定主题后,页面的整体布局和 CSS 基本已经定死,它把若干常用槽位放开给开发者用:Body1、Body2、Body3 和 Position1 到 Position4。其中 Body 系列在 HTML 里是以<TABLE>渲染的,Position 系列是以<DIV>渲染的。

这个区别非常重要,直接决定了你的排版手段。想用表格对齐的,就把区域挂在 Body 上;想自由定位的,挂 Position。我在 4.1.1 上做页面时最难受的一点是:某个 Body 内的 Column 属性是全局的,改一处影响一片。4.2.5 之后每个子区域都有独立的 Grid Layout 可以配,这个问题才算解决,所以版本尽量别停在 4.1。

4.2 Grid Layout 三属性与 TABLE/TR/TD 的对应关系

看懂这张对应表,排版就不再是玄学:

Grid Layout 属性对应 HTML含义
Start New Grid新的<TABLE>当前区域是否另起一张表,不沿用上一个表格的列定义
Start New Row<TR>当前区域是否换行
Column<TD>序号当前区域落在本行的第几列
Column Spancolspan跨几列,4.2 才有

一份能直接抄的配置:Search1、Search2、Search3 放同一张表的一行,Column 依次填 1、2、2,Start New Grid 依次是 Yes、No、No,Start New Row 依次是 Yes、No、Yes;New Search1、New Search2、New Search3 另起一张表,Column 依次填 1、2、3,Start New Grid 是 Yes、No、No,Start New Row 是 Yes、No、No。

渲染出来的结构大致是这样,对照着看就明白了:

<!-- 第一张表:Search 行,第二列跨两格 --> <table> <tr> <td>Search1</td> <td colspan="2">Search2 + Search3</td> </tr> </table> <!-- 第二张表:New Search 行,三等分 --> <table> <tr> <td>New Search1</td> <td>New Search2</td> <td>New Search3</td> </tr> </table>

配完刷新页面,F12 看一眼 DOM,是 table 还是 div、colspan 对不对,比在后台反复猜快得多。复杂布局也是同一套原则堆出来的,无非是嵌套区域再加一层 Grid。

4.3 控件属性、事件、校验:一份配置清单

APEX 的控件(文本框、下拉框、LOV、日期选择、报表)本身没什么稀奇,价值在属性面板上。几个高频属性值得记牢:Form Element Width 控宽度,Horizontal / Vertical Alignment 和 Label 位置管对齐,Value Required 是必输,Condition Type 控制"满足条件才显示",Read Only Condition Type 控制"满足条件才只读",Default Value 给默认值,Format Mask 管日期和数字的格式掩码。这四类条件属性把大量本来要写 JS 的活变成了配置。

事件侧靠 Dynamic Action,核心是三个属性:Condition Type 决定这个动作在什么前提下被考虑,True Actions 和 False Actions 分别对应条件成立与不成立时干什么,When Condition 再在事件触发后做一次判断。校验侧则是另一套:When Button Pressed 指定由哪个按钮触发,Condition Type 选Exists (SQL query returns at least one row)这类前置条件,Condition Expression 写判定 SQL,Validation Expression 写返回布尔的 PL/SQL 函数体,Error message display location 和 Associated Item 决定错误信息显示在哪、关联到哪个字段。

-- 校验前置条件要用到的表,先建好并塞一条判定数据 create table demo_user_ctx( user_id varchar2(50) primary key, resp_id varchar2(50), resp_appl_id varchar2(50), login_name varchar2(50), login_count number, login_date date ); insert into demo_user_ctx values('123','','','',0,sysdate); commit;
-- Validation 的表达式:返回 true 表示校验通过 -- 只有在 demo_user_ctx 里存在 user_id='123' 时才触发这条校验 begin if :P2_X_TEXT is not null then return true; end if; return false; end;

Condition Expression 里写select 1 from demo_user_ctx where user_id = '123',只有返回行才继续走后面的表达式。这个组合的实战意义是:把校验的触发条件也数据化,同一个页面在不同职责下走不同的校验规则,不用改代码。

4.4 两个 Dynamic Action 实例:无刷新隐藏与页面加载赋值

第一个是交互式的。需求是:P2 上的文本框有值时,隐藏 New Search2 区域,为空时显示。

事件定义(Dynamic Action) Name : DA_HIDE_NEW_SEARCH2 Event : Change Selection Type : Item(s) Item(s) : P2_X_TEXT Condition : is not null True Actions : Hide Region -> New Search2 False Actions : Show Region -> New Search2

整个过程不发一次整页刷新,体验接近现代前端框架,而实现只是配置了几行。要注意 Condition 挂的位置:挂在 Dynamic Action 层是"事件触发前判断",挂在 True/False Actions 里是"事后分支",两者行为不同,配错了表现就是"有时候管用有时候不管用"。

第二个是页面加载时给日期项赋当前日期。

-- Set Value 动作的 SQL Statement,结果写进 DATA 项 select sysdate from dual;
事件定义 Name : DA_PAGE_LOAD_SET_DATE Event : Page Load Condition : No Condition True Action : Set Value Set Type : SQL Statement SQL Statement : select sysdate from dual; Selection Type : Item(s) Item(s) : DATA

这类"页面加载型"动作在开发期非常好用,能省掉一堆默认值计算。但要注意它在每次页面加载都会跑,放在 Page 0 上就是每个页面都跑,别在里面写重查询。

4.5 Tabular Form:基于视图的多行增删改与 Process 逻辑

常规做法是一条记录跳一个新页面去改,Tabular Form 则是在一个表格里对多行同时增删改,思路和 ERP 的 Form 块很像——底层基于视图开发。视图负责把要展示的多个表字段拼成一行,页面上的列和视图列一一对应。

-- 班级查找表 create table demo_class( class_id number primary key, class_name varchar2(50) ); -- 展示视图:把用户和班级拼在一起 -- 注意:多表 join 的视图默认不可更新,需要 INSTEAD OF 触发器兜住 DML create or replace view v_demo_class_user as select u.user_id, u.login_name, u.resp_id, c.class_id, c.class_name from demo_user_ctx u, demo_class c where c.class_id = u.resp_id; create or replace trigger trg_v_demo_class_user instead of update on v_demo_class_user begin update demo_user_ctx set login_name = :new.login_name where user_id = :new.user_id; end; /

页面侧:先建一个基于该视图的 Tabular Form 区域,再建一个Apply Change按钮,然后在按钮上挂 Process,处理"改登录名"和"校验班级是否存在"这两件事。多行一起提交时,页面上的数据是通过apex_application.g_f01到g_fNN这组数组传到后台的:g_f01通常是行选择器(复选框),后面依次对应各列,编号跟着列顺序走。

declare l_exists number; l_class varchar2(50); begin -- g_f01 是行选择器;g_f03/g_f05 对应视图里的 login_name / class_name 列 for i in 1 .. nvl(apex_application.g_f01.count, 0) loop if apex_application.g_f01(i) is not null then l_class := apex_application.g_f05(i); select count(*) into l_exists from demo_class where class_name = l_class; if l_exists = 0 then apex_error.add_error( p_message => l_class || ' 不在班级表中,请先维护', p_display_location => apex_error.c_inline_with_field_and_notif, p_page_item_name => ''); end if; end if; end loop; end;

逻辑说明两点。第一,循环上界必须用nvl(..., 0),没有勾选任何行时count为 0,直接for i in 1..count在某些版本上会抛异常。第二,g_f0x的编号是"位置编号"不是"列名编号",你在 Tabular Form 中间插一列,后面所有编号整体后移,昨天还能跑的 Process 今天就会读错字段——这是我在这个功能上翻车最多的地方,改列顺序时一定要回头对一遍 Process。

校验通过后要写回另一张表的,就在同一个循环里追加 insert,或者用一个独立的 Process,把When Button Pressed设成APPLY_CHANGE,靠按钮控制执行时机,别指望"页面一提交就执行"。

5. 避坑排查:五条现象、原因和收尾动作

5.1 ADMIN 密码改了三遍还是登不上

现象:apex_admin页面输入 ADMIN 和新密码,提示无效登录,改密码、重启数据库、重装前端都无效。

原因:库里还留着 3.0 时代的 schema 和同义词,登录校验链路走到旧对象上去了。这种情况在"卸载不彻底直接覆盖安装"之后出现概率极高。

解决:先确认残留,再清理,最后重设密码。

select username from dba_users where username like 'APEX%' or username like 'FLOWS%'; -- 确认是旧版本用户后 drop user APEX_030200 cascade; -- 回到 $ORACLE_HOME/apex 重设管理员口令 @apxchpwd.sql

5.2 手滑 drop 掉新引擎 schema,整站全挂

现象:所有 APEX 页面报 ORA-00942 或直接 500,数据库里其他应用不受影响。

原因:APEX_040200不是普通用户,它就是引擎本身,应用的元数据、页面定义、图片引用全在里面。执行drop user APEX_040200 cascade等于把引擎连数据一起删了,而且这个操作没有后悔药。

解决:只能重跑@apexins.sql重建引擎。重建后引擎能活,但之前做的应用和页面数据找不回来——除非你之前导出过应用(Application 级别的导出脚本)。所以我的固定动作是:任何涉及drop user的操作之前,先把应用导出成 SQL 脚本存一份,哪怕只是开发环境。

5.3 页面能打开,但样式全丢、图标全裂

现象:登录进工作空间,HTML 结构正常,CSS 完全没生效,浏览器控制台一堆/i/...的 404。

原因:apxldimg.sql没跑,或者跑的时候输入的ORACLE_HOME路径不对,又或者apexins.sql的图片虚拟路径参数和实际加载路径不一致。

解决:重跑图片加载脚本,输入正确的ORACLE_HOME,然后确认 XDB 里资源真的存在。

cd $ORACLE_HOME/apex sqlplus / as sysdba @apxldimg.sql
select any_path from resource_view where any_path like '/i/%' and rownum < <p> <a href="https://download.csdn.net/download/hero_518/7742009" style="color:#ec7500;font-size:14px;"> 本文还有配套的精品资源,点击获取 </a> <img alt="menu-r.4af5f7ec.gif" src="https://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif" style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;"> </p>

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询