270 likes | 467 Views
网站计数器. 学习目标. 掌握网站计数器的概念 掌握网站计数器的不同设计技术 掌握 PL/SQL 动态区域的用法. 任务背景. 网站计数器是 Web 应用程序的一项基本功能 用于统计使用网站或应用程序的人次 可反应网站或应用程序的使用频率或受欢迎程度 你的任务是设计一网站计数器,要求 同一用户刷新页面显示时,计数不变 同一用户再次打开浏览器访问程序时, 计数加 1 不同用户打开浏览器访问程序时, 计数加 1 服务器重新启动时, 计数不能够丢失. 设计思路 ( 3-1 ). 网站计数器应设计在网站或应用程序的首页 应通过某种方式保存当前网站被访问次数
E N D
学习目标 • 掌握网站计数器的概念 • 掌握网站计数器的不同设计技术 • 掌握 PL/SQL 动态区域的用法
任务背景 • 网站计数器是 Web 应用程序的一项基本功能 • 用于统计使用网站或应用程序的人次 • 可反应网站或应用程序的使用频率或受欢迎程度 • 你的任务是设计一网站计数器,要求 • 同一用户刷新页面显示时,计数不变 • 同一用户再次打开浏览器访问程序时, 计数加1 • 不同用户打开浏览器访问程序时, 计数加1 • 服务器重新启动时, 计数不能够丢失
设计思路 (3-1) • 网站计数器应设计在网站或应用程序的首页 • 应通过某种方式保存当前网站被访问次数 • 在用户访问首页时对访问次数加1 • 应能够判断是否为同一用户同次访问网站时多次打开首页,这种情况访问次数应当不变 • 在首页显示时,显示最新访问次数
设计思路 (3-2) • Web 应用处理分类 • 页面生成(Page Rendering ) • 用户在浏览器中输入 URL 或通过链接请求页面,服务器响应用户请求,显示网页的过程 • 服务器显示静态页面或执行程序,用程序动态生成一 HTML 页面,显示给用户 • 页面处理(Page Processing ) • 用户完成数据输入并提交页面 • 服务器获取用户输入并作出相关处理,如修改数据库或打开其他页面 • 网站计数器应在页面生成中完成
设计思路 (3-3) • 访问次数可能存储的方法 • 局部变量 • 页面项(变量) • 应用程序项(变量) • 数据表 • 序列 • 访问次数显示方法 • 在页面添加Text 项, Displayed As Text (Does not save state) • 在页面添加PL/SQL 动态区域,用代码动态生成显示文本
创建应用程序 • 创建 counter 应用程序 • 添加 blank 页面 • 选择 One Level of Tabs • 选择 No Authentication • 运行结果如图所示 • 下面就在此页面实现网站计数器
方案一 • 通过页面项显示网站计数 • 添加 HTML 区域 • 添加Text 项 P1_COUNTER1 , Displayed As Text (Does not save state) • 用局部变量计数 • 在 Page Rendering 栏增加 PL/SQL 处理 count1,代码如下 DECLARE i NUMBER := 0; BEGIN i := i + 1; :P1_COUNTER1 := '你是第 ' || i || ' 位访客 ' ; END; • 测试 • 刷新页面,重新打开浏览器,计数不变,为什么? • 提示:局部变量的生命周期
方案二 • 通过页面项显示网站计数 • 用页面变量计数 • 添加隐藏项 P1_I (Hidden and protected) • 修改处理 count1 代码如下: DECLARE i NUMBER := 0; BEGIN IF V('P1_I') IS NULL THEN i := 0; ELSE i := TO_NUMBER(V('P1_I'),'999999999'); END IF; i := i + 1; :P1_COUNTER1 := '你是第 ' || i || ' 位访客 ' ; :P1_I := i; END;
方案二 • 测试 • 刷新页面,计数增加 • 切换页面,计数增加(可增加一页面做切换实验) • 重新打开浏览器,计数归 0 • 现象分析 • 页面变量记录会话状态 • 会话从用户连接网站开始,到断开连接如关闭浏览器结束 • 服务器为会话分配唯一数字标识 Session ID 用以区分不同会话 • :P_I 生命周期为会话存在时间,所以重新打开浏览器,计数归 0 • 代码没有对 Session ID 进行判断,所以刷新、切换页面,计数增加
方案三 • 通过页面项显示网站计数 • 用 Application Item 计数 • Application Item 不显示,并不属于特定的页面,就像全局变量,在所有页面中可用,生命周期同会话,也可用于记录会话状态 • 在共享组件的 Logic 部分创建项 F116_I ,修改处理 count1 代码如下: DECLARE i NUMBER := 0; BEGIN IF V('F116_I') IS NULL THEN i := 0; ELSE i := TO_NUMBER(V('F116_I'),'999999999'); END IF; i := i + 1; :P1_COUNTER1 := '你是第 ' || i || ' 位访客 ' ; :F116_I := i; END;
方案三 • 测试 • 刷新页面,计数增加 • 切换页面,计数增加 • 重新打开浏览器,计数归 0 • 现象分析 • 同方案二
方案四 • 通过页面项显示网站计数 • 用 数据表计数 • 创建表 CREATE TABLE t_jishu(c NUMBER); INSERT INTO t_jishu VALUES(0); COMMIT; • 修改处理 count1 代码如下: DECLARE i NUMBER := 0; BEGIN SELECT c INTO i FROM t_jishu; i := i + 1; :P1_COUNTER1 := '你是第 ' || i || ' 位访客 ' ; UPDATE t_jishu SET c = i; COMMIT; END;
方案四 • 测试 • 刷新页面,计数增加 • 切换页面,计数增加 • 重新打开浏览器,计数保持 • 重新启动服务器,计数保持 • 现象分析 • 因为访问次数保存在数据库中不会丢失
方案五 • 通过页面项显示网站计数 • 用 序列计数 • 创建序列 CREATE SEQUENCE seq_jishu START WITH 1 INCREMENT BY 1 MINVALUE 1 NOCACHE; • 修改处理 count1 代码如下: DECLARE i NUMBER := 0; BEGIN SELECT seq_jishu.NEXTVAL INTO i FROM t_jishu; :P1_COUNTER1 := '你是第 ' || i || ' 位访客 ' ; END;
方案五 • 测试 • 刷新页面,计数增加 • 切换页面,计数增加 • 重新打开浏览器,计数保持 • 重新启动服务器,计数保持 • 现象分析 • 因为访问次数保存在数据库中不会丢失 • 注意 必须用NOCACHE,如果用CACHE,则因内存中缓存一定的序列数,关机、掉电或停止服务器时会出现计数不连续现象
方案六 • 通过页面项显示网站计数 • 用 序列计数,同方案五 • 用页面项 P1_I 暂存计数 • 增加会话是否为新会话判断,修改代码为 BEGIN IF :P1_I IS NULL THEN SELECT seq_jishu.NEXTVAL INTO :P1_I FROM t_jishu; END IF; :P1_COUNTER1 := '你是第 ' || :P1_I || ' 位访客 ' ; END;
方案六 • 测试 • 刷新页面,不变 • 切换页面,不变 • 重新打开浏览器,计数保持 • 重新启动服务器,计数保持 • 现象分析 • 因为访问次数保存在数据库中不会丢失 • 只有新会话 :P1_I 才是空值 null • 这是一种满足要求的方案
方案七 • 通过PL/SQL 动态区域显示网站计数 • 用 序列计数,页面项 P1_I 暂存计数,同方案六 • 删除处理 count1 和项 P1_COUNTER1 • 添加一PL/SQL 动态区域 count
方案七 • PL/SQL 动态区域代码如下: BEGIN IF :P1_I IS NULL THEN SELECT seq_jishu.NEXTVAL INTO :P1_I FROM t_jishu; END IF; htp.p('你是第 ' || :P1_I || ' 位访客 ' ); END; • 说明: • 过程 htp.p(string) 向将要发送给客户端的 HTML 文件中输出一行文本 • 灵活运用,可用程序生成网页内容
方案七 • 测试 • 刷新页面,不变 • 切换页面,不变 • 重新打开浏览器,计数保持 • 重新启动服务器,计数保持 • 现象分析 • 因为访问次数保存在数据库中不会丢失 • 只有新会话 :P1_I 才是空值 null • 这是一种满足要求的方案
PL/SQL 动态区域显示报表 • 关于表格 • 由 成 对 标 记 <table> </table>标 识 • 常用参 数 有 • 对 齐 方 式 align=left/right/center • 表 格 宽 度 width = n/n% • 表 格 边 界 宽 度 border = n • 表 格 中 元 素 分 隔 线 宽 度 cellspacing = n • 元 素 与 分 隔 线 之 间 的 距 离 cellpadding=n • 标 记<tr> <th> <td> • <tr> 说 明 了 表 格 的 一 行 • <th> 说 明 表 格 的 列 标 题 • <td> 说 明 表 格 的 元 素
PL/SQL 动态区域显示报表 • 创建表 ALTER TABLE "DEPARTMENTS" DROP CONSTRAINT "DEPT_MGR_FK"; ALTER TABLE "EMPLOYEES" DROP CONSTRAINT "EMP_DEPT_FK"; ALTER TABLE "EMPLOYEES" DROP CONSTRAINT "EMP_MANAGER_FK"; DROP TABLE "EMPLOYEES" ; DROP TABLE "DEPARTMENTS"; CREATE TABLE "DEPARTMENTS" ( "DEPARTMENT_ID" NUMBER(4,0), "DEPARTMENT_NAME" VARCHAR2(30) CONSTRAINT "DEPT_NAME_NN" NOT NULL ENABLE, "MANAGER_ID" NUMBER(6,0), "LOCATION_ID" NUMBER(4,0), CONSTRAINT "DEPT_ID_PK" PRIMARY KEY ("DEPARTMENT_ID") ENABLE ) / CREATE TABLE "EMPLOYEES" ( "EMPLOYEE_ID" NUMBER(6,0), "FIRST_NAME" VARCHAR2(20), "LAST_NAME" VARCHAR2(25) CONSTRAINT "EMP_LAST_NAME_NN" NOT NULL ENABLE, "EMAIL" VARCHAR2(25) CONSTRAINT "EMP_EMAIL_NN" NOT NULL ENABLE, "PHONE_NUMBER" VARCHAR2(20), "HIRE_DATE" DATE CONSTRAINT "EMP_HIRE_DATE_NN" NOT NULL ENABLE, "JOB_ID" VARCHAR2(10) CONSTRAINT "EMP_JOB_NN" NOT NULL ENABLE, "SALARY" NUMBER(8,2), "COMMISSION_PCT" NUMBER(2,2), "MANAGER_ID" NUMBER(6,0), "DEPARTMENT_ID" NUMBER(4,0), CONSTRAINT "EMP_SALARY_MIN" CHECK (salary > 0) ENABLE, CONSTRAINT "EMP_EMAIL_UK" UNIQUE ("EMAIL") ENABLE, CONSTRAINT "EMP_EMP_ID_PK" PRIMARY KEY ("EMPLOYEE_ID") ENABLE ) / insert into DEPARTMENTS VALUES(10,'Administration',200,1700); insert into DEPARTMENTS VALUES(20,'Marketing',201,1800); insert into DEPARTMENTS VALUES(50,'Shipping',124,1500); insert into DEPARTMENTS VALUES(60,'IT',103,1400); insert into DEPARTMENTS VALUES(80,'Sales',149,2500); insert into DEPARTMENTS VALUES(90,'Executive',100,1700); insert into DEPARTMENTS VALUES(110,'Accounting',205,1700); insert into DEPARTMENTS VALUES(190,'Contracting',NULL,1700); insert into EMPLOYEES VALUES(100,'Ellen','Abel','AHUNOLD','515.123.4444','17-9月 -87','AC_ACCOUNT',4400,NULL,101,10); insert into EMPLOYEES VALUES(101,'Curtis','Davies','BERNST','515.123.5555','17-2月 -96','AC_MGR',13000,NULL,100,20); insert into EMPLOYEES VALUES(102,'Lex','De Haan','CDAVIES','603.123.6666','17-8月 -97','AD_ASST',6000,NULL,201,20); insert into EMPLOYEES VALUES(103,'Bruce','Ernst','DLORENTZ','515.123.8080','07-6月 -94','AD_PRES',12000,NULL,101,110); insert into EMPLOYEES VALUES(104,'Pat','Fay','EABEL','515.123.8181','07-6月 -94','AD_VP',8300,NULL,205,110); insert into EMPLOYEES VALUES(107,'William','Gietz','EZLOTKEY','515.123.4567','17-6月 -87','AD_VP',24000,NULL,NULL,90); insert into EMPLOYEES VALUES(124,'Kimberely','Grant','JTAYLOR','515.123.4568','21-9月 -89','IT_PROG',17000,NULL,100,90); insert into EMPLOYEES VALUES(141,'Michael','Hartstein','JWHALEN','515.123.4569','13-1月 -93','IT_PROG',17000,NULL,100,90); insert into EMPLOYEES VALUES(142,'Shelley','Higgins','KGRANT','590.423.4567','03-1月 -90','IT_PROG',9000,NULL,102,60); insert into EMPLOYEES VALUES(143,'Alexander','Hunold','KMOURGOS','590.423.4568','21-5月 -91','MK_MAN',6000,NULL,103,60); insert into EMPLOYEES VALUES(144,'Steven','King','LDEHAAN','590.423.5567','07-2月 -99','MK_REP',4200,NULL,103,60); insert into EMPLOYEES VALUES(149,'Neena','Kochhar','MHARTSTE','650.123.5234','16-11月-99','SA_MAN',5800,NULL,100,50); insert into EMPLOYEES VALUES(174,'Diana','Lorentz','NKOCHHAR','650.121.8009','17-10月-95','SA_REP',3500,NULL,124,50); insert into EMPLOYEES VALUES(176,'Randall','Matos','PFAY','650.121.2994','29-1月 -97','SA_REP',3100,NULL,124,50); insert into EMPLOYEES VALUES(178,'Kevin','Mourgos','PVARGAS','650.121.2874','15-3月 -98','SA_REP',2600,NULL,124,50); insert into EMPLOYEES VALUES(200,'Trenna','Rajs','RMATOS','650.121.2004','09-7月 -98','ST_CLERK',2500,NULL,124,50); insert into EMPLOYEES VALUES(201,'Jonathon','Taylor','SHIGGINS','011.44.1344.429018','29-1月 -00','ST_CLERK',10500,.2,100,80); insert into EMPLOYEES VALUES(202,'Peter','Vargas','SKING','011.44.1644.429267','11-5月 -96','ST_CLERK',11000,.3,149,80); insert into EMPLOYEES VALUES(205,'Jennifer','Whalen','TRAJS','011.44.1644.429265','24-3月 -98','ST_CLERK',8600,.2,149,80); insert into EMPLOYEES VALUES(206,'Eleni','Zlotkey','WGIETZ','011.44.1644.429263','24-5月 -99','ST_MAN',7000,.15,149,NULL); ALTER TABLE "DEPARTMENTS" ADD CONSTRAINT "DEPT_MGR_FK" FOREIGN KEY ("MANAGER_ID") REFERENCES "EMPLOYEES" ("EMPLOYEE_ID") ENABLE / ALTER TABLE "EMPLOYEES" ADD CONSTRAINT "EMP_DEPT_FK" FOREIGN KEY ("DEPARTMENT_ID") REFERENCES "DEPARTMENTS" ("DEPARTMENT_ID") ENABLE / ALTER TABLE "EMPLOYEES" ADD CONSTRAINT "EMP_MANAGER_FK" FOREIGN KEY ("MANAGER_ID") REFERENCES "EMPLOYEES" ("EMPLOYEE_ID") ENABLE /
PL/SQL 动态区域显示报表 • 将方案七中动态区域中代码改为: DECLARE cursor mycur is select * from employees; BEGIN htp.p('<html>'); htp.p('<head><title> emp table </title></head>'); htp.p('<body BGCOLOR=cyan>'); htp.p('<FONT Size=4>'); htp.p('<h1 align="Center">员工表</h1>'); htp.p('<Table align="Center" Border>'); htp.p('<TR width=400>'); htp.p('<TH Align="Center">工号</TH>'); htp.p('<TH Align="Center">姓名</TH>'); htp.p('<TH Align="Center">工资</TH>'); htp.p('</TR>'); for rsc in mycur loop htp.p('<TR width=400>'); htp.p('<TH Align="Center">' || rsc.employee_id || '</TH>'); htp.p('<TH Align="Center">' || rsc.last_name || '</TH>'); htp.p('<TH Align="Center">' || rsc.salary || '</TH>'); htp.p('</TR>'); end loop; htp.p('</Table>'); htp.p('</body>'); htp.p('</html>'); END;
PL/SQL 动态区域显示报表 • 页面运行显示结果如图
PL/SQL 动态区域显示报表 • 代码分析 • HTML 标签,生成表格 • <Table align="Center" Border> • HTML 标签,生成表格一行 • <TR width=400> • HTML 标签,生成表格一列 • <TH Align="Center">工号</TH> • 代码拼出了一个 HTML 网页,可通过查看网页源代码找到这部分内容
总结 • 掌握网站计数器的概念 • 掌握网站计数器的不同设计技术 • 掌握 PL/SQL 动态区域的用法