Sprechende Adressen für APEX-Anwendungen

Häufig hat man den Wunsch, einer APEX-Anwendung anstelle der "f?p=..."-Syntax eine "sprechende" Adresse zu geben. Dies ist mit Hilfe eines Apache-Moduls recht einfach machbar. Die Konfiguration erfolgt allerdings nicht in APEX selbst, sondern im Apache Web Server, über den die APEX-Seiten ausgeliefert werden. Nutzern des PL/SQL Embedded Gateway in Oracle11g bringt das allerdings nicht viel, denn hier wird gerade kein Apache Webserver verwendet. Allerdings gibt es auch hier eine Möglichkeit: Mit einem speziellen Java-Servlet, welches in der Datenbank hinterlegt wird, kann auch in diesen Umgebungen URL Rewriting stattfinden. In OracleXE kann der Tipp jedoch nicht angewendet werden, da hier keine Java-Engine vorhanden ist.

Sprechende URL mit dem Apache Webserver

Das Apache-Modul mod_rewrite kann in den Browser eingegebene URLs beliebig umschreiben. Welche Eingaben wie umgeschrieben werden, wird mit Hilfe von regulären Ausdrücken festgelegt. Die Konfiguration erfolgt in der Apache-Konfigurationsdatei httpd.conf. Die Arbeitsweise sei anhand eines Beispiels beschrieben.

LoadModule rewrite_module modules/mod_rewrite.so

RewriteEngine On
RewriteRule ^/Anwendung-1$ http://myserver.de/pls/htmldb/f?p=4711:1 [R=301]
RewriteRule ^/Systeme/Administration$ http://myserver.de/pls/htmldb/f?p=85:20 [R=301]

Zunächst muss sichergestellt sein, dass das mod_rewrite beim Starten des Apache geladen wird. Die nächste Direktive RewriteEngine On schaltet das Modul ein. Jede abgerufene Seite wird von nun zunächst anhand der folgenden Ausdrücke überprüft.

Wenn die URL http://myserver.de/Anwendung-1 eingegeben wird, so passt sie genau auf den regulären Ausdruck in der ersten RewriteRule-Direktive. Tatsächlich ausgeführt wird demnach die URL http://myserver.de/pls/htmldb/f?p=4711:1. Diese ruft die Seite 1 der HTML DB-Anwendung 4711 auf. Mit dem HTTP-Code 301 wird dem Browser diese Umleitung mitgeteilt. Mehr zum Apache-Modul mod_rewrite finden Sie in der Dokumentation.

Sprechende URL mit dem Oracle11g PL/SQL Embedded Gateway

Achtung: Dieser Tipp funktioniert nicht in OracleXE, da hier die Java-Engine der Datenbank verwendet wird. In OracleXE ist diese nicht vorhanden.

Das PL/SQL Embedded Gateway bringt out-of-the-box keine Möglichkeit zum Umschreiben von URL mit. Nimmt man jedoch die in der Datenbank enthaltene Java-Engine zu Hilfe, so stellt man fest, das alles nötige vorhanden ist:

  • Die Rewrite-Regeln müssen gespeichert werden - dazu nehmen wir eine normale Datenbanktabelle.
  • Es wird eine Schnittstelle zum Hinzufügen der Löschen von Regeln benötigt. Ein PL/SQL Package übernimmt das.
  • Und schließlich wird ein "Stück Software" benötigt, welche die eigentliche Umleitung übernimmt. Dazu wird ein Java Servlet in die Datenbank hinterlegt und im Protokollserver registriert.

Führen Sie das folgende Skript (Download) in Ihrer Datenbank als SYS aus. Es legt die Tabelle, das PL/SQL-Paket und das Java-Servlet an und vergibt die nötigen Privilegien.

create table tab_epg_urlrewrite(
  rule_name    varchar2(100) not null,
  rewrite_rule varchar2(4000) not null,
  rewrite_to   varchar2(4000) not null,
  constraint pk_epgurlrewrite primary key (rule_name)
)
/

create or replace view rewrite_rule as
select rule_name, rewrite_rule, rewrite_to from tab_epg_urlrewrite
with read only
/

create or replace package rewrite_rule_mgr is
  procedure add_rule(
    p_name   in tab_epg_urlrewrite.rule_name%type,
    p_regexp in tab_epg_urlrewrite.rewrite_rule%type,
    p_tourl  in tab_epg_urlrewrite.rewrite_to%type
  );
  procedure delete_rule(
    p_name   in tab_epg_urlrewrite.rule_name%type
  );
end rewrite_rule_mgr;
/
sho err

create or replace package body rewrite_rule_mgr as
  procedure add_rule(
    p_name   in tab_epg_urlrewrite.rule_name%type,
    p_regexp in tab_epg_urlrewrite.rewrite_rule%type,
    p_tourl  in tab_epg_urlrewrite.rewrite_to%type
  ) is 
  begin
    insert into tab_epg_urlrewrite (
      rule_name, rewrite_rule, rewrite_to
    ) values (
      p_name, p_regexp, p_tourl
    );
  end add_rule;

  procedure delete_rule(
    p_name   in tab_epg_urlrewrite.rule_name%type
  ) is 
  begin
    delete from tab_epg_urlrewrite where rule_name = p_name;
  end delete_rule;
end rewrite_rule_mgr;
/
sho err

create public synonym rewrite_rule_mgr for sys.rewrite_rule_mgr
/

create public synonym rewrite_rule for sys.rewrite_rule
/

grant execute on rewrite_rule_mgr to public
/

grant select on rewrite_rule to public
/

begin
  rewrite_rule_mgr.add_rule(
    p_name => 'APEX_TEST_RULE',
    p_regexp =>  '^(/a)(.[0-9]*)(p)(.[0-9]*)',
    p_tourl => '/apex/f?p=\2:\4'
  );
end;
/
sho err

commit
/

create or replace and compile java source named APEX_URL_REWRITER as
import javax.servlet.http.*;  
import javax.servlet.*;  
import java.util.*;  
import java.io.*;  
import javax.naming.*;  
import oracle.xml.parser.v2.*;  
import oracle.sql.*;  
import java.sql.*;  
import oracle.jdbc.*;  

public class UrlRewriteServlet extends HttpServlet
{
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    doPost(req, resp);
  }
  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
  {
    Connection        con   = null;
    PreparedStatement pstmt = null;
    ResultSet         rs    = null;

    String            sNewUrl = null;
    String            sError  = null;
    boolean           bSuccess = false;

    try {
  
      con = DriverManager.getConnection("jdbc:default:connection");
      pstmt = con.prepareStatement(
        "select regexp_replace(?, rewrite_rule, rewrite_to) "+
        "from rewrite_rule "+
        "where regexp_LIKE(?, rewrite_rule) and rownum <= 1"
      );
      pstmt.setString(1, req.getPathInfo());
      pstmt.setString(2, req.getPathInfo());
      rs = pstmt.executeQuery();
      if (rs.next()) {
        sNewUrl = rs.getString(1); 
        bSuccess = true;
      } else {
        bSuccess = false;
        sError = "No rewrite rule for " + req.getPathInfo() + " available.";
      }
      rs.close();
      pstmt.close();
      con.close();
    } catch (Exception e) {
      sError = e.getMessage();
      bSuccess = false;
    }

    if (bSuccess) {
      resp.sendRedirect(sNewUrl);
    } else {
      resp.sendError(404, sError);
    }
  }
}
/
sho err

grant execute on  "UrlRewriteServlet" to public  
/  

declare
  v_config xmltype;
begin
  /* 
   * Load XML DB configuration into variable V_CONFIG ...
   */
  select dbms_xdb.cfg_get() into v_config from dual;

  /* 
   * Delete existing servlet declaration
   */
  select deletexml(
     v_config,
     '/xdbconfig/sysconfig/protocolconfig/httpconfig/webappconfig/servletconfig/servlet-mappings/servlet-mapping[servlet-name/text()="UrlRewriteServlet"]'
  ) into v_config from dual;
  select deletexml(
     v_config, 
     '/xdbconfig/sysconfig/protocolconfig/httpconfig/webappconfig/servletconfig/servlet-list/servlet[servlet-name/text()="UrlRewriteServlet"]'
  ) into v_config from dual;

  /* 
   * Declare the servlet ...
   */
  select appendchildxml(
    v_config,
    '/xdbconfig/sysconfig/protocolconfig/httpconfig/webappconfig/servletconfig/servlet-list',
    xmltype('<servlet xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd">
              <servlet-name>UrlRewriteServlet</servlet-name>
              <servlet-language>Java</servlet-language>
              <display-name>Servlet for DBMS_METADATA</display-name>
              <servlet-class>UrlRewriteServlet</servlet-class>
              <servlet-schema>SYS</servlet-schema>
              <security-role-ref>
                <role-name>anonymousServletRole</role-name> 
                <role-link>anonymousServletRole</role-link> 
              </security-role-ref>
             </servlet>')
  ) into v_config from dual;

  /* 
   * Declare URL pattern /metadata/*  ...
   */
  select appendchildxml(
    v_config,
    '/xdbconfig/sysconfig/protocolconfig/httpconfig/webappconfig/servletconfig/servlet-mappings',
    xmltype('<servlet-mapping xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd">
              <servlet-pattern>/u/*</servlet-pattern>
              <servlet-name>UrlRewriteServlet</servlet-name>
             </servlet-mapping>'
    )
  ) into v_config from dual;

  /* 
   * save and activate the configuration
   */
  dbms_xdb.cfg_update(v_config);
end;
/
sho err

commit
/

Mit dem PL/SQL-Paket REWRITE_RULE_MGR können Sie nun Regeln hinzufügen oder löschen und mit der View REWRITE_RULE können Sie die bestehenden ansehen. Eine Regel ist bereits hinterlegt. Sie schreibt eine URL im Format aXXXpYYYY, wobei "a" die Applikation und "p" die Seitennummer ist, ins "richtige" APEX-Format um. Probieren Sie es aus.

http://localhost:8080/u/a102p2

Beachten Sie das /u/, mit dem alle URL beginnen müssen. Im Gegensatz zum Apache Webserver muss das Umleitungs-Servlet an einer bestimmten Stelle registriert werden. Im Beispiel werden alle URL, die mit /u/ beginnen, vom Servlet bearbeitet. Das ist die einzige Einschränkung - ansonsten lässt sich mit dem Servlet genauso arbeiten wie mit dem Rewrite-Modul des Apache Webserver. Wenn Sie einen anderen URL-Präfix verwenden möchten (bspw. "app"), dann ändern Sie das Skript (recht weit unten) wie folgt um:

    :
    xmltype('<servlet-mapping xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd">
              <servlet-pattern>/app/*</servlet-pattern>
              <servlet-name>UrlRewriteServlet</servlet-name>
             </servlet-mapping>'
    :

Auf diese Weise können auch für APEX-Anwendungen URL "nach Wunsch" vergeben werden.

Zurück zur Community-Seite