资讯详情

资讯详情

Oracle APEX数据库内低代码开发与EBS集成实战

简介《Oracle APEX深入浅出》是一份面向Oracle APEX初中级开发者与企业应用搭建者的系统学习文档围绕基于Web快速构建企业级应用这一目标梳理从环境准备到部署集成的完整知识链路。内容覆盖APEX系统探究、账户与权限管理、开发概要、页面布局美化、常用控件、Report增删改、文件上传下载、CSS与JS运用、图表报表、插件使用及APEX部署并延伸到调试技巧、常用API与EBS集成等进阶主题便于读者建立从页面设计到数据可视化的整体认知。压缩包共1个doc文件约8.11MB适合作为案头手册按章节查阅也可跟随目录进行阶段性练习。已有1592人学习说明其在APEX入门与实战参考方面具有一定认可度。读者可从中获取较完整的开发流程框架、控件与报表的落地思路以及部署和EBS集成的衔接方法。1. 从一次 ADMIN 登录被拒说起Oracle APEX 到底跑在哪一层装完 Oracle APEX浏览器能打开登录页ADMIN 密码改了三遍还是进不去——这个场景我遇到过最后发现不是密码错是数据库里还留着上一代版本的用户。这类“页面起来了但进不去门”的故障恰好说明 APEX 的定位它不是一台独立的中间件整个开发环境和运行时都压在 Oracle 数据库里页面是数据表里的元数据渲染是 PL/SQL 调htp.p拼出来的 HTML。这份《Oracle APEX 深入浅出》要走的正是这条线从 11g 上重装 4.2.5、Workspace 与 Schema 的账户映射到 Grid Layout 布局、控件与 Dynamic Action、Tabular Form 多行增删改、文件上传下载再到与 EBS 页面互调。适合已经在写 PL/SQL、要给业务快速搭一套 Web 录入和报表界面的开发者也适合被 Form 个性化拖慢节奏、想换一种交付方式的人。2. 从 11g 自带 3.0 到 4.2.5重装、网关与 Workspace 的完整命令链2.1 页面是元数据、渲染是 PL/SQL先看懂这条请求链很多人第一次接触 APEX 会把它当成 PHP 那类部署在 Web 服务器上的框架于是习惯性地去找 war 包、找 Tomcat 目录找不到就开始怀疑安装包不全。实际情况是浏览器发出的 URL 请求先到 HTTP 监听程序如果是 11g 自带的嵌入式 PL/SQL 网关这一步就在数据库监听里完成请求被解析成一次 PL/SQL 调用数据库里的 APEX 引擎接手做会话状态还原、认证、授权、页面流控制、校验、渲染最后用sys.htp.p把 HTML 刷回浏览器缓冲区。理解这条链路的价值很直接备份 APEX 应用等于备份数据库里的那批对象迁移应用等于在另一个库上导入导出性能调优先看数据库会话和 SQL 而不是看 Web 容器线程数。页面本身是无状态的每次请求都是新的数据库会话所以“为什么我在页面上改了一个值另一个区域没跟着变”这类问题答案通常在会话状态Session State什么时候被提交而不是在浏览器缓存。下面这段过程能说明“页面”在数据库眼里是什么样子它不依赖 APEX 引擎只靠 PL/SQL 网关就能跑通-- 一个能被 DAD 映射到的存储过程就是一张最原始的“页面” create or replace procedure hello_apex as begin htp.p(htmlbody); htp.p(h1server time: || to_char(sysdate, yyyy-mm-dd hh24:mi:ss) || /h1); htp.p(/body/html); end; /htp.p往输出缓冲区写一段文本网关在过程结束后把缓冲区一次性刷给浏览器这就是 APEX 页面最终呈现的机制。区别只在于APEX 的这段“过程”不是人手写的而是根据存在表里的页面元数据动态拼出来的。2.2 卸载旧版本别让两代内部用户并存11g 自带 APEX 3.0直接装 4.2.5 会出现两套内部用户共存元数据视图的前缀不一样APEX_030200与APEX_040200认证链路可能仍然指向旧的那一套。这就是开头那个“密码怎么改都进不去”的根因。所以安装顺序必须是先卸干净再装新版而不是覆盖。动手前先把现状摸清楚这一步花两分钟能省掉后面两小时-- 1) 当前有哪些 APEX 相关账户状态如何 select username, account_status from dba_users where username like APEX% or username in (ANONYMOUS, APEX_PUBLIC_USER) order by username; -- 2) 当前注册的 APEX 版本视图不存在说明版本更老 select version_no from apex_release; -- 3) 组件在注册表里的状态VALID 才算装完整 select comp_id, comp_name, version, status from dba_registry where comp_id APEX;第一条查询的输出要重点看有没有APEX_030200这类旧版本用户第二条如果报“表或视图不存在”说明库里的版本比你能查到的视图还老卸载脚本更要跑。确认之后执行卸载# 卸载脚本必须在 APEX 安装目录下执行用 SYSDBA 连接 cd $ORACLE_HOME/apex sqlplus / as sysdba apxremov.sql # 卸载脚本跑完后把残留的安装文件清空避免新旧脚本混在一起 # 注意清空前确认当前目录确实是 $ORACLE_HOME/apex这条命令不可恢复 pwd rm -rf *apxremov.sql会删除 APEX 内部用户及其全部对象不可回退务必先在测试库走一遍。清空目录那一步原文是直接rm -rf *.*我建议先pwd确认路径血泪经验在$ORACLE_HOME根目录下敲这条命令的代价不是重装 APEX 能解决的。2.3 表空间、解压与安装脚本给 APEX 单独建一个表空间好处是引擎对象和业务数据分开日后做表空间级备份、迁移、配额控制都方便。生产环境我不建议直接用 SYSAUX虽然默认安装允许这么做-- APEX 引擎对象独立表空间初始 100M按 100M 自动扩封顶 1G CREATE TABLESPACE APEX01 DATAFILE /u01/app/oracle/oradata/ORCL/apex01.dbf SIZE 100M AUTOEXTEND ON NEXT 100M MAXSIZE 1000M;把安装包上传到$ORACLE_HOME下解压然后跑安装脚本# 解压到 $ORACLE_HOME/apex unzip apex_4.2.5.zip -d $ORACLE_HOME cd $ORACLE_HOME/apex # 四个参数引擎表空间、文件表空间、临时表空间、静态资源虚拟路径 sqlplus / as sysdba apxins.sql APEX01 SYSAUX TEMP /i/参数逐个说明第一个APEX01是 APEX 引擎对象包、视图、元数据表存放的位置第二个SYSAUX是用户上传文件APEX_APPLICATION_TEMP_FILES之外的持久文件所用表空间第三个TEMP是排序和临时段第四个/i/是静态资源CSS、JS、图片在数据库里的虚拟目录前缀浏览器请求/i/...时由网关从这里取文件。四个参数写错任何一个脚本跑到一半会停报错信息一般很直白按提示换参数重跑即可不需要重新卸载。装完立刻解锁账户并设置口令这是最容易被跳过、又最容易导致“登录不了”的一步-- 匿名用户负责登录页本身的渲染不解锁就打不开登录界面 ALTER USER ANONYMOUS ACCOUNT UNLOCK; -- 网关连接池使用的用户不解锁 EPG 连不进 APEX 引擎 ALTER USER APEX_PUBLIC_USER ACCOUNT UNLOCK; -- 4.2.5 的内部用户名称随版本变化按实际查到的用户名替换 ALTER USER APEX_040200 ACCOUNT UNLOCK; -- ADMIN 口令大写小写数字特殊字符长度 8 位以上 -- 特殊字符必须用双引号包住否则 sqlplus 会当成语法符号 ALTER USER ADMIN IDENTIFIED BY Apex#Dev_2024;注意ADMIN 是 APEX 应用层的超级管理员和数据库的 SYS、SYSTEM 完全不是一回事。改 ADMIN 口令不会影响数据库账户反过来用数据库账户去登 APEX 登录页也永远登不进去。2.4 嵌入式网关端口、监听与 40411g 自带嵌入式 PL/SQL 网关EPG不用装 Apache 也不用装独立监听器配置成本最低。默认端口常常和已有服务冲突我一般直接改成 8888-- 查看当前 EPG 端口 select dbms_xdb.gethttpport() from dual; -- 改成 8888改完必须重启监听才会重新注册 HTTP 端口 exec dbms_xdb.sethttpport(8888);# 重启监听让新端口生效 lsnrctl stop lsnrctl start # 确认 HTTP 端口已经出现在监听列表里 lsnrctl status | grep -i http改完端口不重启监听是 404 的高频原因之一。另一个高频原因是安装脚本没跑完静态资源目录没建/apex/apex_admin这种带路径的地址就会返回 404。验证顺序建议固定下来# 先探登录页返回 200 或 302 说明网关和引擎都通了 curl -I http://127.0.0.1:8888/apex/apex_admin-- 仍然是 404 就回到数据库里确认组件状态 select comp_id, version, status from dba_registry where comp_id APEX;status不是VALID说明安装中断过重新跑apxins.sql比到处猜要快得多。2.5 建 Workspace把 Schema 挂到工程上APEX 的账户模型是三层ADMIN 在最上面负责创建和删除 WorkspaceWorkspace 是一个“工程”对应数据库里的一个 SchemaWorkspace 内部再分管理员、开发者和最终用户三种角色。原文里把 Workspace 类比成项目、把 Application 类比成 EBS 里的一个 Form这个类比是准确的后续做权限隔离时全靠这一层。以 ADMIN 登录后创建 Workspace 时会让你选“使用已有 Schema”还是“新建 Schema”。这里有个选型判断纯 APEX 开发给 APEX 单独建一个 Schema比如APEX_DEV权限边界清楚要和 EBS 集成、直接读写apps下的对象才挂到apps上但同时要接受一个事实——开发者在 APEX 里能碰到的对象范围等于apps的权限范围。-- 建完 Workspace 后核对映射关系需要 DBA 权限 -- 视图名带版本前缀不同版本前缀不同先 desc 确认再查 select workspace_name, schema_name? from APEX_040200.APEX_WORKSPACES;如果这条查询报视图不存在不要怀疑装错了先select view_name from all_views where view_name like APEX%WORKSPACE%找到实际视图名。版本前缀APEX_040200是 APEX 内部用户的命名规则升级大版本时会变这一点在写运维脚本时要注意别把前缀硬编码进去。3. Grid Layout 翻译成 TABLE/TR/TD布局、控件与 Dynamic Action3.1 主题定骨架Body 是 TABLEPosition 是 DIVAPEX 自带二十来个主题选中主题之后页面的整体布局和 CSS 基本就定了剩下能动的部分是主题开放出来的几个占位区域。原文提到的Body1、Body2、Body3和Position1到Position4是其中常用的几个理解它们的关键是看渲染出来的 HTML 标签Body 系列区域最终渲染成tablePosition 系列渲染成div。这个差异决定了布局方式。放在 Body 区域里的子区域是按表格单元格排列的你配置的每一个“列号”最终都会变成一个td放在 Position 区域里的子区域是块级元素靠主题的 CSS 做浮动或弹性排布。所以看到设计稿上“三块内容一行排开、中间那块更宽”时先判断它属于哪种容器再决定是调 Grid Layout 还是改主题 CSS。4.1.1 时代最让人难受的一点是Column 属性在同一个 Body 内是全局的子区域想重新排布几乎做不到。4.2.5 之后每个子区域都有独立的 Grid Layout 配置可以重新起表、重新分行这就是“页面布局变得相当 Easy”的实际含义。3.2 三个开关Start New Grid、Start New Row、ColumnGrid Layout 只有三个配置项但组合出来的行为足够覆盖大部分布局需求。先把它们和 HTML 的对应关系钉死配置项对应 HTML实际含义Start New Grid Yes新的table当前区域另起一张表列号从 1 重新计算Start New Row Yestr当前区域换到新的一行Column N第 N 个td当前区域落在本行第 N 个单元格原文那个六区域实例配置抄下来是这样区域Start New GridStart New RowColumnSearch1YesYes1Search2NoNo2Search3NoYes2New Search1YesYes1New Search2NoNo2New Search3NoNo3重点看 Search2 和 Search3两者 Column 都是 2但 Search3 的 Start New Row 是 Yes所以它换到了下一行落在第二列视觉上就是“缩进了一格”。很多人在这里翻车以为 Column 是绝对坐标其实它只在当前行内有效换行之后列号重新算。提示布局调不出来时别在浏览器里反复刷新猜直接看页面源码里那几个table和td的嵌套关系比对着 Grid Layout 的配置看一次就能定位是哪一层的 Row 没设对。3.3 控件、事件、校验各管一段APEX 的控件文本框、下拉框、值列表、日期选择、报表本身没有太多玄学真正需要建立心智模型的是它周围那三组配置属性管“长什么样、能不能空、什么时候显示”事件管“用户操作之后发生什么”校验管“提交之前拦不拦”。属性里最常用的几个Form Element Width控制控件宽度Value Required是否必输Condition Type决定控件是否显示比如只有某个角色登录才显示审批按钮Read Only Condition Type决定是否只读Default Value设默认值Format Mask做格式掩码日期、金额。这组配置的价值在于大量业务规则不用写代码配一下就落地了这也是 APEX 声明式开发的核心卖点。事件的主体是 Dynamic Action它最实用的能力是执行 PL/SQL 而不刷新页面效果上等价于一次 Ajax 回调。配置结构是三层When什么时候触发事件类型、选择类型、具体元素、条件、True Actions条件为真时做什么、False Actions条件为假时做什么。常见的动作包括显示/隐藏区域、设值、刷新区域、执行 PL/SQL。校验的配置项是另一组When Button Pressed指定哪个按钮触发Condition Type加Condition Expression决定这次校验要不要执行比如只有表里有数据才校验Validation写具体逻辑Error message display location决定错误提示显示在页面顶部还是字段旁边Associated Item把错误关联到具体控件上用户一眼能看到是哪一栏填错了。3.4 从零复现一个页面必填校验、日期默认值、区域联动把上面三组配置串起来做一个能跑的页面点查询按钮时校验文本框非空但只有参照表里存在user_id123这条记录时才校验页面加载时日期控件默认今天第二个文本框有值时隐藏一个区域清空时再显示出来。先建参照表和测试数据-- 参照表校验条件用的字段结构照原样保留 create table demo_test ( user_id varchar2(50), resp_id varchar2(50), resp_appl_id varchar2(50), login_name varchar2(50), login_count number, login_date date ); insert into demo_test (user_id, login_name) values (123, demo); commit;第一步校验。在P1_X_TEXT上建一个 Validation类型选Function Returning Boolean触发按钮选SEARCH2_BTN条件类型选Exists (SQL query returns at least one row)-- Condition Expression只有这条查询有结果校验才生效 select 1 from demo_test t where t.user_id 123-- Validation Expression返回 true 表示通过false 表示拦截 begin if :P1_X_TEXT is not null then return true; end if; return false; end;这里有个容易忽略的点Function Returning Boolean的返回值语义是“校验是否通过”返回false才会触发错误提示错误信息配在Error message里。写成“值为空返回 true”就完全反了页面会表现为“填了才报错”。第二步页面加载时给日期控件赋当天日期。建一个 Page Load 类型的 Dynamic Action动作选Set ValueSet Type选SQL Statement-- 返回必须是一行一列多行会报错多列只取第一列 select sysdate from dualAffected Elements选Item(s)目标填P2_DATA。用 SQL 而不是固定值的好处是默认值随数据库时间走不受客户端时区影响。第三步文本框联动显隐。建一个 Change 事件的 Dynamic ActionSelection Type选Item(s)元素是P2_X_TEXTCondition选is not nullTrue Action 配Hide RegionFalse Action 配Show Region目标都是new search2那个区域。When : Event Change, Selection Type Item(s), Item P2_X_TEXT, Condition is not null True : Hide Region - new search2 False : Show Region - new search2跑起来之后输入内容区域消失清空内容区域回来整个过程没有页面刷新。真正要在生产里用还得补一件事被隐藏区域里的必填项仍然参与提交校验用户会看到“明明没显示的字段报错了”。处理方式是在该字段的校验上加Condition Type Item is not null或者在隐藏的同时用另一个 Set Value 动作把它清空。4. Tabular Form 与文件、EBS 集成多行提交怎么写才不出 ORA 错4.1 数据源为什么选视图APEX 的 Tabular Form 允许在一个页面里批量编辑多行记录一次提交完成多条更新交互上非常接近 EBS 的块式 Form。原文强调它“基于视图去开发”这不是风格偏好而是由 APEX 的提交机制决定的Tabular Form 提交时APEX 会按报表的列生成一批 DML如果数据源是基表你能改的列就是基表的列如果是视图你能改的范围就被视图定义约束住了多表关联场景下反而更安全。代价是视图必须可更新。Oracle 对可更新视图的要求是 key-preserved视图里参与连接的那个基表连接列上必须有主键或唯一约束。否则提交时报ORA-01779: cannot modify a column which maps to a non key-preserved table这个错误在 APEX 里不会告诉你哪张表缺约束只能自己回推。-- 基表用户与班级 create table demo_class ( class_id number, class_name varchar2(50) ); create table demo_user ( user_id varchar2(50), login_name varchar2(50), class_id number ); -- 关键连接列上必须有主键否则视图不可更新 alter table demo_class add constraint pk_demo_class primary key (class_id); alter table demo_user add constraint pk_demo_user primary key (user_id); -- 可更新视图作为 Tabular Form 的数据源 create or replace view demo_user_v as select u.user_id, u.login_name, c.class_name from demo_user u, demo_class c where c.class_id u.class_id;视图定义里只暴露了user_id、login_name、class_name三列class_id这类内部字段不出现在界面上这是用视图的第二个好处界面和数据模型解耦日后改表结构不影响已发布的页面。4.2 Process 里遍历 g_f 数组的正确姿势Tabular Form 提交后的数据不在普通页面项里而在APEX_APPLICATION.G_F01到G_F50这组数组里每个数组对应报表的一列数组元素是该列每一行的值。这里有个必须记住的规则数组编号按报表列的先后顺序分配不是按字段名也不是按你在数据源里写的顺序。所以第一步不是写业务逻辑而是确认编号。在 Process 里临时打一行调试信息跑一次看 Debug 输出-- 临时调试确认每一列对应哪个 g_f 编号 declare l_idx number; begin for i in 1 .. nvl(apex_application.g_f01.count, 0) loop apex_debug.message(f01[%s] %s, i, apex_application.g_f01(i)); end loop; for i in 1 .. nvl(apex_application.g_f02.count, 0) loop apex_debug.message(f02[%s] %s, i, apex_application.g_f02(i)); end loop; end;确认完编号再写正式逻辑。下面这个 Process 挂在 Apply 按钮上执行时机选On Submit - After Computations and Validations做的事情是逐行读取提交上来的班级名先查班级是否存在不存在就报错存在就更新用户名并把记录写入一张日志表declare l_user_id varchar2(50); l_class_name varchar2(50); l_class_id number; begin -- 编号按实际调试结果替换这里假设 f02 是 user_id、f03 是 class_name for i in 1 .. nvl(apex_application.g_f02.count, 0) loop l_user_id : apex_application.g_f02(i); l_class_name : apex_application.g_f03(i); -- 空行直接跳过Tabular Form 会提交整表包括没改动的行 if l_user_id is null then continue; end if; begin select class_id into l_class_id from demo_class where class_name l_class_name; exception when no_data_found then -- 用 raise_application_error 才能中断提交并回滚普通 raise 在 APEX 里行为不一样 raise_application_error(-20001, 班级不存在: || l_class_name); end; update demo_user set class_id l_class_id where user_id l_user_id; insert into demo_user_log (user_id, class_name, log_time) values (l_user_id, l_class_name, sysdate); end loop; end;几个参数和写法上的说明。nvl(..., 0)不能省报表没有数据时g_f02.count是空值for 1 .. null在某些情况下会报错。raise_application_error与普通raise的区别很关键前者会把错误信息推到页面并让整个提交失败后者在 APEX 的 Process 上下文里可能被吞掉表现为“点了按钮没反应也没报错”这是排查起来最费时间的一类问题。日志表的插入放在 update 之后、同一个循环里保证要么都成功要么都失败不会出现“主表改了日志没写”的半截状态。4.3 文件上传下载BLOB 存表与 wpg_docload文件上传在 APEX 里由“文件浏览”类型的页面项完成用户选完文件点提交文件内容不会直接进入你的表而是先落在APEX_APPLICATION_TEMP_FILES这个会话级临时视图里你在 Process 里把它读出来再决定是写进 BLOB 表还是别的存储。-- 文件表主键用序列生成11g 没有 identity 列 create sequence demo_files_seq; create table demo_files ( file_id number primary key, file_name varchar2(255), mime_type varchar2(255), blob_data blob );-- 上传 Process从临时文件视图取内容写入 BLOB 表 declare l_file apex_application_temp_files%rowtype; begin select * into l_file from apex_application_temp_files where name :P3_FILE_ITEM; insert into demo_files (file_id, file_name, mime_type, blob_data) values (demo_files_seq.nextval, l_file.filename, l_file.mime_type, l_file.blob_content); end;where name :P3本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →