APEX实战第3篇:如何完善项目基础功能
上一篇《APEX实战第2篇:构建自己第一个APEX程序》虽然有了程序,但实在是太单薄!
本篇将会介绍一些数据库的基础知识,演示如何通过函数、触发器、存储过程、视图等来完善项目的一些基础功能。
没有编程经验也完全没关系,笔者其实也从来都没做过程序员,但可以借助APEX结合一些数据库基础知识,就能让我们也能轻松构建属于自己的应用程序。
比如这里举例,我想构建一个学习平台,所谓活到老学到老,这里就叫小鲸鱼终身学习平台吧,嗯,让它看起来像个真正的项目,这样介绍起来也会有趣些。
项目名称:小鲸鱼终身学习平台
嗯。。做戏做全套,干脆正式一点,把上篇的名字都改掉,重定义下:
英文:Little Whale Lifelong Learning Platform
Logo:WhaleStudy
- 1.构建验证用户登录的函数
- 2.利用触发器自动维护历史记录
- 3.使用存储过程处理重复数据问题
- 4.巧用视图构建DIY数据
1.构建验证用户登录的函数
基础功能先搞简单些,我只需要实现不同用户登录系统,能且只能看到自己的学习进度,可以通过登录用户加以判断。
举实际例子吧,我这里先假设已有3个用户:duoduo、manman、test;
- 多多小朋友 username=duoduo
- 满满小朋友 username=manman
- 测试人员兼管理员 username=test
要求用户登录只能看到自己的数据,管理员登录可以有权限看到一些额外的管理菜单和子项。
首先构建一张用户表,就三列,用户、密码、是否管理员:
--新建表 T_USERS
create table T_USERS (
username varchar2(30) primary key,
password varchar2(50) not null,
is_admin number default 0
);
然后创建一个函数,专门用于验证用户登录:
--新建函数 F_LOGIN
create or replace function F_LOGIN(
p_username in varchar2,
p_password in varchar2
) return boolean is
l_cnt number;
l_result boolean;
begin
--判断用户密码
select count(*) into l_cnt from t_users
where username = p_username
and password = p_password;
--判断
IF l_cnt=1 THEN
l_result := true;
--htp.p('Welcome,' || p_username);
ELSE
l_result := false;
--htp.p('Error!!!' || p_username);
END IF;
return l_result;
--异常处理
exception
WHEN OTHERS THEN
RETURN false;
end;
/
手工测试:
--ORACLE 23ai可以不用再写from dual,当然,写也不会报错,还能更好向下兼容,看个人习惯
--正确返回True
select f_login('test','test');
--错误返回False
select f_login('test','123');
在APEX界面,找到你的程序进入到验证方案,比如:Application 102 -> Shared Components -> Authentication Schemes,新建一个账号密码登录的验证方案,编辑时选择 Authentication Function Name 指定为上面创建的函数名。
不过登录测试还存在问题,因为我这里用户表中都是小写的用户名,但是网上搜索发现APEX登录界面会默认自动转为大写,这是因为账号大小写敏感设置问题。
这点参考了网上公开资料,可以这样修改,亲测有效,在登录页面Login部分插入一段PL/SQL Code:
apex_authentication.login(
p_username => :P9999_USERNAME,
p_password => :P9999_PASSWORD,
p_uppercase_username => FALSE);
再次测试使用小写账号登录成功。
OK,登录搞定,也学会了简单函数的使用。
关于只能看到自己的数据?
- 可以通过配置APEX界面,数据库where条件为:
username = :APP_USER,这里的:APP_USER就是当前登录的用户变量。
关于管理员登录可以有权限看到一些额外的管理菜单和子项?
- 可以通过
Application 102 -> Shared Components -> Authorization Schemes配置一个管理权限,Scheme Type选择Exists SQL Query,SQL Query内容为:select 1 from t_users where username = :APP_USER and IS_ADMIN = 1,然后在导航菜单等地方就可以选择这个管理权限。
2.利用触发器自动维护历史记录
我这里设计一个稍复杂的场景,就是之前的T_CURRENT表,在进行更新修改都没有任何记录,无法分析历史数据,所以现在我就需要搞一张历史表专门用于存储历史信息,这里就通过新建一个触发器来实现这个功能,如下:
create or replace TRIGGER TRI_T_CURRENT
AFTER INSERT OR UPDATE OR DELETE ON "T_CURRENT"
FOR EACH ROW
DECLARE
v_current_date DATE := SYSDATE; -- 当前系统日期
BEGIN
IF INSERTING THEN
-- 插入操作,将插入的数据和当前日期插入到T_HISTORY表
INSERT INTO t_history (type, week, day, content, username, history_date)
VALUES (:new.type, :new.week, :new.day, :new.content, :new.username, v_current_date);
ELSIF UPDATING THEN
-- 更新操作,先尝试更新已有的记录,如果找不到,则插入新记录
-- 我这样设计,是因为想随时添加新的content内容,而不让历史表记录零碎信息
MERGE INTO t_history h
USING (SELECT :new.type AS type, :new.week AS week, :new.day AS day, :new.username AS username FROM dual) src
ON (h.type = src.type AND h.week = src.week AND h.day = src.day AND h.username = src.username)
WHEN MATCHED THEN
UPDATE SET h.content = :new.content, h.history_date = v_current_date
WHEN NOT MATCHED THEN
INSERT (type, week, day, content, username, history_date)
VALUES (:new.type, :new.week, :new.day, :new.content, :new.username, v_current_date);
ELSIF DELETING THEN
-- 删除操作,将被删除的数据和当前日期插入到T_HISTORY表
INSERT INTO t_history (type, week, day, content, username, history_date)
VALUES (:old.type, :old.week, :old.day, :old.content, :old.username, v_current_date);
END IF;
END;
/
其实,我主要用到的场景就是更新,只不过更新的要求稍多一点,因为我不想太多垃圾记录存在,详见上面代码注释部分说明。
3.使用存储过程处理重复数据问题
存储过程,用于做些啥呢,容笔者现编一下应用场景。。干脆就用于删除历史遗留的数据重复问题吧:
--新建存储过程 P_CLEAN_DUP_HISTORY
CREATE OR REPLACE PROCEDURE P_CLEAN_DUP_HISTORY
IS
BEGIN
DELETE FROM t_history h
WHERE h.history_date < (
SELECT MAX(h2.history_date)
FROM t_history h2
WHERE h.type = h2.type
AND h.week = h2.week
AND h.day = h2.day
AND h.username = h2.username
);
COMMIT;
END;
/
注意,我这里定义的重复数据,是根据我这个程序的业务场景来决定,我认为同一用户,在同一天(history_date),同一课程类型(type)、相同分片(week和day都一样),只能有一条,如果存在多条,一定是之前的记录CONTENT内容不完整,可以删除掉这样的垃圾条目,只保留最新的完整记录行。

额,自己说起来都感觉好绕,如果不理解可以多读几遍。。就是类似上面这种重复数据,还不理解也没关系,这里主要就是刷一下存储过程的存在感。
这样执行存储过程:
begin
P_CLEAN_DUP_HISTORY;
end;
之后再去查数据发现已实现这个去重数据的功能。
4.巧用视图构建DIY数据
那就搞一张视图来专门展示CONTENT中的内容吧!
create or replace view V_CONTENT as
select content from T_CURRENT
where content is not null;
嗯,看起来貌似有点没太大必要哈,是因为这个场景太简单了,我就是想展示一下可以这么玩,等以后遇到更复杂的场景就能看出巧用视图的优势了。
注意,细心的小伙伴应该已经发现了我这里的命名规范:
- 所有表以
T_开头 - 所有函数以
F_开头 - 所有过程以
P_开头 - 所有视图以
V_开头 - 所有触发器以
TRI_开头
...
职业病又犯了。。之前做DBA时还总是去给开发人员培训,让他们遵守一些开发规范,好利于排查维护。
当然你也可以构建你自己的一套命名规范,只要养成这个好习惯,以后的管理维护工作就会多一缕轻松愉快。
回到正题,是不是做过ORACLE DBA的小伙伴会觉得APEX这玩意儿简直是太好玩了,终于能比较容易的把一些内功给输出到前端了。
所以并不是做广告,笔者真觉得APEX这玩意儿,确实是蛮好玩儿的一个低码平台,请继续保持关注,后续还将有更多内容分享。
APEX实战第3篇:如何完善项目基础功能的更多相关文章
- R实战 第三篇:数据处理(基础)
数据结构用于存储数据,不同的数据结构对应不同的操作方法,对应不同的分析目的,应选择合适的数据结构.在处理数据时,为了便于检查数据对象,可以通过函数attributes(x)来查看数据对象的属性,str ...
- Jemter+Badboy实战经验一(Badboy录制及基础功能)
1. 使用工具: Apache Jemeter:http://jmeter.apache.org/download_jmeter.cgi (免费官网下载地址) BadBoy: http://www ...
- Nancy简单实战之NancyMusicStore(三):完善商品信息与管理
前言 上一篇,我们做了不少准备,并且还把我们NancyFx音乐商城的首页打造好了.这一篇主要是完善我们在首页的商品浏览问题和添加对商品的管理. 下面开始正题: 商品详情 首先是查看单个商品的详情: 先 ...
- Sping Boot入门到实战之入门篇(二):第一个Spring Boot应用
该篇为Spring Boot入门到实战系列入门篇的第二篇.介绍创建Spring Boot应用的几种方法. Spring Boot应用可以通过如下三种方法创建: 通过 https://start.spr ...
- Sping Boot入门到实战之入门篇(四):Spring Boot自动化配置
该篇为Sping Boot入门到实战系列入门篇的第四篇.介绍Spring Boot自动化配置的基本原理与实现. Spring Boot之所以受开发者欢迎, 其中最重要的一个因素就是其自动化配置特性 ...
- SpringCloud实战 | 第五篇:SpringCloud整合OpenFeign实现微服务之间的调用
一. 前言 微服务实战系列是基于开源微服务项目 有来商城youlai-mall 版本升级为背景来开展的,本篇则是讲述SpringCloud整合OpenFeign实现微服务之间的相互调用,有兴趣的朋友可 ...
- SpringCloud实战 | 第四篇:SpringCloud整合Gateway实现API网关
一. 前言 微服务实战系列是基于开源微服务项目 有来商城youlai-mall 版本升级为背景来开展的,本篇则是讲述API网关使用Gateway替代Zuul,有兴趣的朋友可以进去给个star,非常感谢 ...
- [Spring Cloud实战 | 第六篇:Spring Cloud Gateway+Spring Security OAuth2+JWT实现微服务统一认证授权
一. 前言 本篇实战案例基于 youlai-mall 项目.项目使用的是当前主流和最新版本的技术和解决方案,自己不会太多华丽的言辞去描述,只希望能勾起大家对编程的一点喜欢.所以有兴趣的朋友可以进入 g ...
- Spring Cloud实战 | 最八篇:Spring Cloud +Spring Security OAuth2+ Axios前后端分离模式下无感刷新实现JWT续期
一. 前言 记得上一篇Spring Cloud的文章关于如何使JWT失效进行了理论结合代码实践的说明,想当然的以为那篇会是基于Spring Cloud统一认证架构系列的最终篇.但关于JWT另外还有一个 ...
- Docker实战 | 第四篇:Docker启用TLS加密解决暴露2375端口引发的安全漏洞,被黑掉三台云主机的教训总结
一. 前言 在之前的文章中 IDEA集成Docker插件实现一键自动打包部署微服务项目,其中开放了服务器2375端口监听,此做法却引发出来一个安全问题,在上篇文章评论也有好心的童鞋提示,但自己心存侥幸 ...
随机推荐
- Dynamic CRM插件中获取Entity属性值问题
插件中获取Entity不同类型字段时稍有区别,一般用如下两种方式: Entity targetEntity = (Entity)context.InputParameters["Target ...
- MYSQL查询7天内、7月内的所有日期
select DATE_SUB(CURDATE(), INTERVAL 6 DAY) ; SELECT date_add( date_sub( ( SELECT DATE_SUB( curdate( ...
- 聊一聊 操作系统蓝屏 c0000102 的故障分析
一:背景 1. 讲故事 今年以来不知道为啥总有些朋友加我微信,让我帮忙分析下操作系统蓝屏问题,我也觉得挺好奇的,就问了其中一位朋友,说是B站来的,我就在拼命回忆,为啥会找我分析蓝屏?突然想到了去年好像 ...
- Linux软连接与硬链接的概念
- Hetemit pg walkthrough Intermediate
nmap ┌──(root㉿kali)-[~] └─# nmap -p- -A 192.168.157.117 Starting Nmap 7.94SVN ( https://nmap.org ) a ...
- wireshark抓包学习
ip 过滤 ip.src_host ip.dst_host ip.addr mac 过滤 eth.src eth.dst eth.addr 端口过滤 tcp.port tcp.srcport tcp. ...
- java重载-构造方法也存在重载-数据类型的提升
重载 1.一个类中不能声明多个相同的方法,属性. 2.上面的相同指的是方法名,参数列表相同.和返回值类型无关. 3.如果方法名相同,但是参数列表(个数,顺序,类型)不相同,会认为是不同的方法,在jav ...
- 独立开发经验谈:我是如何借助 Docker 环境变量让客户 1 分钟上线客服系统的
我在业余时间开发了一款自己的独立产品:升讯威在线客服与营销系统.陆陆续续开发了几年,从一开始的偶有用户尝试,到如今线上环境和私有化部署均有了越来越多的稳定用户,在这个过程中,我也积累了不少如何开发运营 ...
- 刚刚!百度搜索“换脑”引爆AI圈,正式接入DeepSeek R1满血版
一.今天发现百度搜索出现已接入DeepSeek的提示,再也不用担心使用DeepSeek时出现"服务器繁忙,请稍后再试."的问题了. 在百度搜索首页出现[即刻体验AI搜索Deep ...
- CH340区别
CH340区别 CH340G USB转串⼝,推出时间最早,需外挂晶振,应⽤最⼴SOP16 CH340C USB转串⼝,内置晶振,引脚兼容CH340G SOP16 CH340E USB转串⼝,内置 ...