Nastavil bych demo na apex.oracle.com, ale protože potřebujete povolení k provedení na dbms_alert, bude muset být pouze textové.
S celým nastavením můžete jít docela daleko, takže bych to považoval za základ, na kterém lze stavět. Například jsem pracoval pouze s jedním upozorněním. Ve vaší ukázce můžete chtít použít více událostí k zachycení různých výstrah o průběhu. Je to z prostého důvodu, že aby bylo možné něco vrátit klientovi (odpověď ajax), musí se zpětné volání ajaxu „zavřít“. Takže když zachytíte výstrahu a chcete ji vrátit, musíte zapsat do vyrovnávací paměti a je třeba ji vrátit. To znamená, že také přestanete poslouchat událost (čtěte:v apexu, měli byste!).
Zvažte tok takto:provedete volání ajax a budete mít proces zpětného volání ajax, který zaregistruje zájem o událost. Poté čekáte, až se objeví upozornění. Zachytíte jej a vrátíte jej zapsáním do http bufferu (htp.p
). To je konec kódu a apex vyprázdní vyrovnávací paměť, volání ajaxu pak vyzvedne odpověď a vy budete moci tento návrat spravovat.
Nezapomeňte však:apex používá sdružování připojení a databázi relace nejsou propojeny přímo, ale jsou stále znovu používány. Nechcete 'zanechat' databázovou relaci 'špinavou'. Budete také muset zrušit registraci svého zájmu o upozornění. To také umožňuje použití jedinečných ID pro výstrahy – výstrahy lze registrovat v různých (databázových) relacích, takže pokud by se jednalo o stránku, kterou může více uživatelů používat ke sledování průběhu postupu svého procesu, nemusíte chcete, aby zasahovali do upozornění ostatních uživatelů.
Tato pomíjivá povaha zájmu však také znamená, že mezi různými hovory ajaxu dojde k „přerušením“. Pokud chcete poslouchat více upozornění a tato upozornění mohou být zabalena velmi těsně vedle sebe, existuje šance, že jedno přehlédnete. Řekněme, že 2 upozornění jsou od sebe vzdálena 1 ms:první bude zachyceno a nahlášeno hovoru ajax, který by musel okamžitě zahájit nový hovor, aby naslouchal dalším upozorněním. Ale protože během této krátké doby nebyl žádný aktivní posluchač, mohlo se stát, že další upozornění bylo přehlédnuto. Nyní – pravděpodobně se jedná pouze o problém, kdy spustíte více výstrah pod stejným obslužným nástrojem. Pokud byste použili více obslužných programů a spustili volání ajaxu pro všechny současně, budou všechny zpracovány včas. Pro obojí samozřejmě existují řešení. Představuji si, že při použití pouze jednoho handleru byste mohli zachytit všechna upozornění ve sbírce a zkontrolovat, zda jste již odeslali odpověď na určité upozornění nebo ne a zda pokračovat v přihlašování nebo ne. S více obslužnými rutinami můžete použít jedinečné id a doplnit je různými stavy.
Zde je tedy nějaký skutečný kód, který jsem použil ve svém místním POC.
Přehled:Mám 3 tlačítka:1 pro generování ID upozornění, pro které jsem použil sekvenci. Další tlačítko pro zahájení poslechu události a další tlačítko pro odeslání upozornění.
Kód JS pro tlačítko NEW_ALERT_ID:
apex.server.process("NEW_ALERT").done(function(pdata){
$s("P1_ALERT_ID",pdata.alertId);
})
Kód JS pro tlačítko START_LISTEN:
apex.server.process("LISTEN_ALERT",{x01:$v("P1_ALERT_ID")},{timeout:(31*1000)})
.done(function(pdata){
if (pdata.success ){
alert('Caught alert: ' + pdata.message);
} else {
alert("No alerts caught during wait on database. You may want to continue listening in...")
}
})
.fail(function(jqXHR, textStatus){
if(textStatus === 'timeout')
{
alert('Call should have returned by now...');
//do something. Try again perhaps?
}
});
Kód JS pro tlačítko SEND_ALERT:
apex.server.process("SEND_ALERT",{x01:$v("P1_ALERT_ID")},{dataType:"text"});
Procesy zpětného volání AJAX:
NEW_ALERT:
htp.p('{"alertId":'||alert_seq.nextval()||'}');
LISTEN_ALERT:
declare
alert_id number := apex_application.g_x01;
msg varchar2(2000);
stat pls_integer;
keep_looping boolean := true;
insurance binary_integer := 0; -- prevent an infinite loop
onecycle binary_integer := 3; -- one cycle of waiting, in seconds
maxcycles binary_integer := 10; -- in this session, the max amount of cycles to wait
begin
dbms_alert.register(alert_id);
while keep_looping
loop
insurance := insurance + 1;
dbms_alert.waitone(alert_id, msg, stat, onecycle);
if stat = 1 then
apex_debug.message('timeout occured, going again');
else
apex_debug.message('alert: '||msg);
keep_looping := false;
end if;
exit when insurance = maxcycles;
end loop;
if keep_looping then
-- we waited a really long time now. It may be a good idea to return this info to the client and let it start a new call
htp.p('{"success":false,"message":"No alert during wait on database"}');
else
htp.p('{"success":true,"message":"'||msg||'"}');
end if;
end;
SEND_ALERT:
declare
alert_id number := apex_application.g_x01;
begin
dbms_alert.signal(alert_id, 'alert sent at '||to_char(systimestamp, 'HH24:MI:SS FF6'));
end;
Nejprve bych tedy dostal ID výstrahy, pak bych začal naslouchat a v určitém okamžiku bych poslal výstrahu (nebo ne). Je to však kostra a bude potřebovat další vylepšení ve vašem skutečném nastavení.