Servicios web en Oracle



Servicios webampliamente utilizado para la integración entre componentes de un sistema o entre sistemas diferentes. La popularidad de los servicios web como una forma de integración se debe a su versatilidad, así como a la facilidad de implementación y depuración. La versatilidad está asociada con la transferencia de datos a través de Internet y el protocolo HTTP. Los servicios web hacen que sea relativamente fácil crear integraciones entre componentes escritos en diferentes idiomas que se ejecutan en diferentes sistemas operativos y plataformas. La facilidad de implementación de servicios web se logra a través de herramientas y componentes integrados en muchos IDE que le permiten desarrollar rápidamente tanto el servicio web (lado del proveedor) como el código necesario para llamar al servicio en el lado del cliente. Los servicios de depuración se simplifican mediante el uso de formatos de intercambio de datos legibles por humanos: XML y JSON. Además,Existen muchas utilidades para los servicios de depuración y prueba, incluida la carga.

En este artículo, consideraremos varias formas de crear servicios web directamente desde Oracle DBMS, es decir, sin utilizar herramientas de terceros.

Contenido

Native Oracle XML DB Web Services
    
    
         Oracle XML DB HTTP server
         HTTP
         -
         Access List (ACL)
     -
    
Oracle REST Data Service
    
    
        
        
        
        
     1: POST-
         WS
        
        
         HTTP-
        
        
        CGI-
     2: ORDS
        
         ORDS
        
        
        
    

    Java Servlet
    Database Access Descriptor (PL/SQL Servlet)

Antecedentes


Dado: sistema de negocios de información de una gran red de distribución (alrededor de mil tiendas minoristas), que consta de muchos componentes y subsistemas. Dentro de cada tienda hay un servidor principal: una base de datos Oracle con la lógica comercial principal. Los nodos de efectivo son administrados por un software separado de su base de datos local. Este software recopila periódicamente datos del servidor principal (a través de WS SOAP) y devuelve los resultados de la venta (intercambio de archivos).

El progreso no se detuvo y aparecieron nuevos equipos en las tiendas. Los datos de este equipo deben enviarse periódicamente al servidor principal de la tienda (período, cada pocos minutos), la integración debe pasar necesariamente por el servicio web, el mensaje debe tener un cierto formato, no se necesita autenticación. Analizamos los contratos de intercambio de datos y descubrimos que la tecnología utilizada de los servicios web no permitirá la integración de edificios con dichos equipos. Y comenzó la búsqueda de una solución ...

Como resultado, se consideraron varias opciones para implementar el servicio web deseado, hasta escribir un componente separado que abriría una ventana para la base de datos Oracle para la base de datos HTTP: por un lado, proporcionaría un servicio web, por otro, interactuaría con la base de datos a través de JDBC. La dificultad es que el nuevo componente, en primer lugar, tendría que instalarse en mil tiendas y, en segundo lugar, habría aparecido otro enlace que tendría que estar acompañado. Por lo tanto, la prioridad seguía siendo la opción de implementar un servicio web con herramientas integradas de Oracle.

Como resultado de las búsquedas, encontramos cuatro formas que consideraremos en este artículo:

  1. Servicios web nativos de Oracle XML DB
  2. Servicio de datos REST de Oracle
  3. Servlet Java
  4. Descriptor de acceso a la base de datos (servlet PL / SQL)

Las dos primeras opciones se considerarán con más detalle. Los servicios web nativos de Oracle XML DB se utilizaron inicialmente en nuestro sistema, es decir, se heredaron, por así decirlo. ORDS se convirtió en un reemplazo de esta tecnología obsoleta (a pesar de que todavía tenía que trabajar duro e instalar ORDS en miles de tiendas).

Otros dos métodos, Java Servlet y PL / SQL Servlet, lo consideramos junto con ORDS al buscar una alternativa a Native Oracle WS, pero no lo utilizamos en el proyecto. Por lo tanto, no consideraremos estos enfoques en detalle y nos limitaremos a una breve referencia.

El artículo presentará algunos ejemplos prácticos de implementación de servicios web con instrucciones que ayudarán a crear un servicio que funcione.

Servicios web nativos de Oracle XML DB


Capacidades


Le permite organizar el acceso a la base de datos Oracle a través de HTTP utilizando WS SOAP (versión 1.1):

  • SQL- XQuery- SOAP.
  • ( ).



  • - : , HTTP-.
  • - (WSDL), , -.
  • -. , — , — .
  • XML-. , , XML, - — Oracle . , WS- Oracle — , - .



  • WSDL , , - . — WSDL, WSDL , .
  • ( 50 ). , — , . , - — , , .

Vale la pena señalar que se requiere autenticación para todas las solicitudes al servicio web (de la documentación : Autenticación básica: Oracle XML DB admite la Autenticación básica, donde un cliente envía el nombre de usuario y la contraseña en texto claro en el encabezado de Autorización). En Oracle, puede configurar el acceso anónimo a los recursos del servidor a través de HTTP, utilizando la configuración del servidor de protocolo XML XML de Oracle , pero de hecho funciona solo para solicitudes GET, y se requiere autenticación para las solicitudes POST. Dado que Native Oracle WS solo funciona a través de solicitudes POST, no hay forma de configurar el acceso anónimo para esta tecnología.

Personalización


Para usar Native Oracle WS necesitará:

  1. Configure el servidor HTTP incorporado en Oracle.
  2. Configure el acceso dentro de la base de datos Oracle (abra el puerto HTTP).
  3. Crea un servlet.
  4. Configure ACL (Lista de acceso).

Configurar el servidor HTTP Oracle XML DB


El servidor HTTP ya debería funcionar de manera predeterminada, pero en algunos casos puede ser necesaria una configuración de escucha adicional, agregando el siguiente bloque a DESCRIPTION_LIST:

(DESCRIPTION=
  (ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=8080))(Presentation=HTTP)(Session=RAW)
)

Después de eso, debe reiniciar el oyente.

Configurar acceso HTTP


  1. Comprobando el puerto actual para HTTP.

    SELECT dbms_xdb.gethttpport() AS http_port FROM dual;

    Un valor de "0" significa que el acceso HTTP está deshabilitado.
  2. Configuración de puerto.

    BEGIN
        --    web-services
        dbms_xdb.setHttpPort(8080);
        COMMIT;
    END;
    /

Crear un servlet para un servicio web


Para que el servicio web funcione, se requiere el registro del servlet en la configuración de la base de datos.

Script para crear un servlet
--   SYS
DECLARE
    l_servlet_name      VARCHAR2(32)  := 'orawsv';
BEGIN
    --   orawsv   Native Web Services
    DBMS_XDB.deleteServletMapping(l_servlet_name);
    DBMS_XDB.deleteServlet(l_servlet_name);
 
    DBMS_XDB.addServlet( NAME     => l_servlet_name
                       , LANGUAGE => 'C'
                       , DISPNAME => 'Oracle Query Web Service'
                       , DESCRIPT => 'Servlet for issuing queries as a Web Service'
                       , SCHEMA   => 'XDB');
 
    DBMS_XDB.addServletSecRole( SERVNAME => l_servlet_name
                              , ROLENAME => 'XDB_WEBSERVICES'
                              , ROLELINK => 'XDB_WEBSERVICES');
 
    DBMS_XDB.addServletMapping( PATTERN => '/orawsv/*'
                              , NAME    => l_servlet_name);
    COMMIT;
END;
/

Configurar lista de acceso


Para acceder a Oracle a través de HTTP, debe agregar reglas en la configuración de DBMS. Esto se hace utilizando las utilidades DBMS incorporadas.

Para configurar la ACL, necesitará:

  • script que edita la configuración de la base de datos (a continuación);
  • esquema de base de datos para el que se realiza la configuración.

Es decir, el esquema de base de datos para el que se está configurando ACL ya debe estar creado. En los ejemplos a continuación, habrá referencias a esta sección, en aquellos lugares donde necesita crear nuevos esquemas de base de datos, para ellos deberá configurar la ACL.

En el esquema SYS, ejecutamos el script de configuración de ACL:
--   SYS
DECLARE
    l_ws_user       VARCHAR2(32)  := 'WS_SOAP_TEST'; --    ,        WS
    l_acl           VARCHAR2(250) := 'acl_allow_all.xml';
    l_tmp           VARCHAR2(250);
BEGIN
    EXECUTE IMMEDIATE 'GRANT XDB_WEBSERVICES TO "'||l_ws_user||'"';
    EXECUTE IMMEDIATE 'GRANT XDB_WEBSERVICES_OVER_HTTP TO "'||l_ws_user||'"';
    EXECUTE IMMEDIATE 'GRANT XDB_WEBSERVICES_WITH_PUBLIC TO "'||l_ws_user||'"';
 
    --       PL/SQL 
    BEGIN
        dbms_network_acl_admin.drop_acl(acl => '/sys/acls/'||l_acl);
    EXCEPTION
        WHEN dbms_network_acl_admin.acl_not_found THEN
            NULL;
    END;
 
    --  ACL
    dbms_network_acl_admin.create_acl( acl         => l_acl
                                     , description => 'Allow all connections'
                                     , is_grant    => TRUE
                                     , start_date  => SYSTIMESTAMP
                                     , end_date    => NULL
                                     , principal   => 'SYS'
                                     , privilege   => 'connect');
 
    dbms_network_acl_admin.assign_acl( acl        => l_acl
                                     , host       => '*'
                                     , lower_port => NULL
                                     , upper_port => NULL);
 
    --    (resolve) 
    dbms_network_acl_admin.add_privilege( acl        => l_acl
                                        , principal  => l_ws_user
                                        , is_grant   => TRUE
                                        , privilege  => 'resolve'
                                        , POSITION   => NULL
                                        , start_date => SYSTIMESTAMP
                                        , end_date   => NULL);
 
    COMMIT;
END;
/

Debe notarse de inmediato que se requiere la configuración de ACL cuando se utiliza no solo Native Oracle WS, sino también todos los demás métodos de creación de servicios web que se analizan en este artículo.

Ejemplo de servicio web utilizando un procedimiento por lotes


Necesitaremos:

  • El esquema de la base de datos en el que se ubicarán los objetos para procesar las solicitudes de servicios web.
  • Tabla para el registro.
  • Paquete con procedimiento / función.
  • Cualquier herramienta que le permita enviar solicitudes web. En este caso, se utilizó la aplicación SOAP UI , pero puede elegir cualquier otra herramienta, hasta la línea de comando.

caracteristicas:

  • Los parámetros de procedimiento deben tener tipos simples u objetos. De lo contrario, el procedimiento no se percibirá como un método de servicio web y no se incluirá en la lista de métodos de servicio.
  • Para implementar estructuras complejas de datos de entrada o salida, debe usar tipos de objeto (no se pueden usar tipos de lote).

Creamos los objetos de base de datos necesarios:

  1. Esquema WS_TEST:

    CREATE USER WS_SOAP_TEST IDENTIFIED BY ws_soap_test QUOTA 200M ON USERS;
    GRANT CREATE SESSION, RESOURCE TO ws_soap_test;

    Añada inmediatamente un nuevo esquema a la ACL. El guión en la sección anterior.
  2. En el nuevo esquema, cree una tabla para iniciar sesión T_WS_REQ_LOG:

    CREATE TABLE T_WS_REQ_LOG
    (
      id_log      NUMBER GENERATED ALWAYS AS IDENTITY,
      message     VARCHAR2(2000),
      proc        VARCHAR2(128),
      dtm_request TIMESTAMP(6) DEFAULT SYSTIMESTAMP
    );
    COMMENT ON TABLE T_WS_REQ_LOG IS ' HTTP-';
    COMMENT ON COLUMN T_WS_REQ_LOG.id_log IS '';
    COMMENT ON COLUMN T_WS_REQ_LOG.message IS '';
    COMMENT ON COLUMN T_WS_REQ_LOG.proc IS '';
    COMMENT ON COLUMN T_WS_REQ_LOG.dtm_request IS '/ ';
  3. Paquete con un procedimiento simple:

    
    CREATE OR REPLACE PACKAGE PK_NATIVE_WS_TEST IS
     
    PROCEDURE proc_simple
        ( a_id      INTEGER
        , a_data    VARCHAR2
        , o_result  OUT VARCHAR2
        );
     
    END PK_NATIVE_WS_TEST;
    /
    CREATE OR REPLACE PACKAGE BODY PK_NATIVE_WS_TEST IS
     
    PROCEDURE proc_simple
        ( a_id      INTEGER
        , a_data    VARCHAR2
        , o_result  OUT VARCHAR2
        )
    AS
    BEGIN
        INSERT INTO t_ws_req_log (message, proc)
        VALUES ('ID='||a_id||'; DATA='||a_data, 'proc_simple')
        RETURNING id_log INTO o_result;
    END proc_simple;
     
    END PK_NATIVE_WS_TEST;
    /

El servicio web más simple está creado y listo para funcionar.

Para acceder al servicio, debe utilizar la URL en el siguiente formato:

http://[server]:[port]/[servlet_name]/[DB_SCHEMA]/[WS_OBJ]?wsdl

Donde:

[servidor] - nombre de dominio o dirección IP del servidor de la base de datos Oracle
[puerto] - puerto de acceso a través de HTTP especificado en la sección "Configuración del acceso a través de HTTP"
[nombre_servlet] - nombre del servlet especificado en la sección "Creación de un servlet para web servicio ”
[DB_SCHEMA] - nombre del esquema de la base de datos (en mayúsculas)
[WS_OBJ] - nombre del servicio (en mayúsculas), que es igual al nombre del objeto de la base de datos, en nuestro caso - el nombre del paquete ¡

Tenga en cuenta que la URL es importante!

Ejemplo de enlace:

http://my.server:8080/orawsv/WS_SOAP_TEST/PK_NATIVE_WS_TEST?wsdl

Si hacemos clic en este enlace en el navegador, seremos creados automáticamente según nuestro paquete WSDL:

Wsdl
<definitions name="PK_NATIVE_WS_TEST"
    targetNamespace="http://xmlns.oracle.com/orawsv/WS_SOAP_TEST/PK_NATIVE_WS_TEST"
    xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:tns="http://xmlns.oracle.com/orawsv/WS_SOAP_TEST/PK_NATIVE_WS_TEST"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
  <types>
    <xsd:schema targetNamespace="http://xmlns.oracle.com/orawsv/WS_SOAP_TEST/PK_NATIVE_WS_TEST"
     elementFormDefault="qualified">
      <xsd:element name="PROC_SIMPLEInput">
        <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="A_DATA-VARCHAR2-IN" type="xsd:string"/>
              <xsd:element name="A_ID-NUMBER-IN" type="xsd:integer"/>
            </xsd:sequence>
          </xsd:complexType>
      </xsd:element>
 
      <xsd:element name="PROC_SIMPLEOutput">
        <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="O_RESULT" type="xsd:string"/>
            </xsd:sequence>
          </xsd:complexType>
      </xsd:element>
   </xsd:schema>
  </types>
 
  <message name="PROC_SIMPLEInputMessage">
    <part name="parameters" element="tns:PROC_SIMPLEInput"/>
  </message>
 
  <message name="PROC_SIMPLEOutputMessage">
    <part name="parameters" element="tns:PROC_SIMPLEOutput"/>
  </message>
 
  <portType name="PK_NATIVE_WS_TESTPortType">
  <operation name="PROC_SIMPLE">
      <input message="tns:PROC_SIMPLEInputMessage"/>
      <output message="tns:PROC_SIMPLEOutputMessage"/>
    </operation>
  </portType>
 
  <binding name="PK_NATIVE_WS_TESTBinding"
           type="tns:PK_NATIVE_WS_TESTPortType">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="PROC_SIMPLE">
      <soap:operation
 soapAction="PROC_SIMPLE"/>
      <input>
        <soap:body parts="parameters" use="literal"/>
      </input>
      <output>
        <soap:body parts="parameters" use="literal"/>
      </output>
    </operation>
  </binding>
 
  <service name="PK_NATIVE_WS_TESTService">
    <documentation>Oracle Web Service</documentation>
    <port name="PK_NATIVE_WS_TESTPort" binding="tns:PK_NATIVE_WS_TESTBinding">
       <soap:address 
             location="http://******:8080/orawsv/WS_SOAP_TEST/PK_NATIVE_WS_TEST"/>
     </port>
  </service>
 
</definitions>

Para probar el servicio, cree un nuevo proyecto SOAP en la interfaz de usuario SOAP. Como URL, especifique la dirección del ejemplo anterior.

Al abrir, Request 1vemos que la plantilla de solicitud ya es generada automáticamente por el WSDL especificado.

Agregue inmediatamente la autorización básica para la solicitud: el inicio de sesión y la contraseña son los mismos que cuando se conecta a la base de datos.



Ejemplo de solicitud y respuesta. Tenga en cuenta que se ha agregado una línea a la solicitud generada automáticamente <pk:O_RESULT-VARCHAR2-OUT/>. El hecho es que hay un error en Oracle 12c: las variables OUT no se agregan al WSDL para Native Oracle WS).



El resultado de la llamada es visible en la tabla de registro.



recomendaciones


La tecnología nativa de Oracle XML DB Web Services se puede utilizar como una solución industrial siempre que no haya una gran carga en este servicio web (una solicitud en unos segundos). Esta opción es adecuada cuando los consumidores no tienen requisitos estrictos para un servicio web (sus atributos, estructuras de datos, lógica de procesamiento) y no hay un contrato predeterminado estricto. Si necesita crear un servicio web de acuerdo con un WSDL predefinido (como en nuestro caso con nuevos equipos), entonces la tecnología Native Oracle WS no será adecuada.

Servicio de datos REST de Oracle


A partir de la versión 11.1, Oracle introdujo el soporte RESTful completo en forma de un módulo separado llamado Oracle REST Data Service (ORDS).

ORDS es una aplicación Java que le permite crear una API RESTful para una base de datos Oracle utilizando SQL y PL / SQL. Es una alternativa al uso de Oracle HTTP Server y mod_plsql. En esencia, ORDS es una interfaz HTTP entre el mundo exterior y una base de datos Oracle. Esta interfaz le permite cerrar las solicitudes HTTP entrantes a cualquier objeto de la base de datos: una tabla o un procedimiento PL / SQL.

Todo lo que debe hacerse es instalar, configurar y ejecutar ORDS para la base de datos requerida. El proceso posterior de creación de servicios REST se reduce a escribir código en PL / SQL (o incluso haciendo clic en el IDE si el código es demasiado vago para escribir).

No se requieren licencias adicionales para instalar ORDS.

Requisitos:

  • Java JDK 8 o superior;
  • Oracle 11.1 o posterior (también se admite Oracle 11 XE Release 2).

Se admiten varias opciones de implementación de ORDS:

  • modo independiente;
  • en el servidor de aplicaciones (Oracle WebLogic Server, Apache Tomcat).

Capacidades


ORDS le permite:

  • Organice el acceso a los recursos en un estilo RESTful.
  • Cree una interacción al estilo de "Llamada a procedimiento remoto" (interacción de estilo RPC).

En pocas palabras, usando ORDS, puede abrir el acceso a través de HTTP a ciertos objetos de la base de datos: tablas, procedimientos, funciones, paquetes.

En el primer caso, estamos tratando con recursos en el sentido de que se entienden en el estilo arquitectónico RESTful. Cada recurso está definido por un URI único, y las operaciones con recursos (CRUD - crear, leer, modificar, eliminar) están determinadas por las operaciones de la solicitud HTTP: PUT, POST, GET, DELETE. Por ejemplo, si el recurso es una entrada en la tabla de empleados, esta entrada estará disponible mediante un URI del formulario:

GET https://server:port/ords/workspace/hr/employees/7369

Aquí, en el URI, se indican el nombre del esquema de la base de datos, el nombre de la tabla y la ID del registro en la tabla. Por lo tanto, esta solicitud HTTP realmente realiza una operación SELECT de la tabla especificada. Con otras operaciones (agregar, cambiar, eliminar), el principio de comunicación es el mismo: la ruta al recurso se indica en el URI, y los parámetros adicionales se indican en el cuerpo de la solicitud, por ejemplo, valores de campo para insertar un registro en la tabla.

En el segundo caso, en lugar de acceder al recurso, se usa directamente una llamada a procedimiento, que puede hacer todo lo mismo que en el primer caso (CRUD), así como ejecutar cualquier otra lógica que implemente el proceso comercial necesario. Se puede realizar una llamada a procedimiento desde un paquete utilizando una solicitud HTTP de este formato:

http://localhost:8080/ords/my_schema/my_pkg/MY_PROC

Los parámetros para el procedimiento se transfieren en el cuerpo de la solicitud en forma de estructuras de formato JSON {"param" : "value"}. Se usa el mismo enfoque cuando se usa el Oracle Oracle nativo, descrito anteriormente, pero en el caso de los servicios REST no hay restricciones impuestas por el protocolo SOAP.

pros

  • Un mecanismo flexible que le permite implementar servicios web de cualquier complejidad.
  • Simplicidad de implementación: para convertir un procedimiento PL / SQL en un servicio web, solo necesita ejecutar algunos comandos típicos. Y usando SQL Developer, crear una API REST se convierte en un clic del mouse con un mínimo de escritura de código.
  • La capacidad de implementar un servicio web sin autenticación.

Menos

  • ORDS no está incluido en el paquete estándar de Oracle; debe instalarse por separado para cada servidor (no se requieren licencias adicionales, como ya se mencionó). Esto puede ser un problema si tiene miles de servidores de bases de datos.

Personalización


ORDS se puede iniciar en dos modos: a través del servidor de aplicaciones o en modo independiente.

Este artículo solo analiza la opción de ejecutarse en modo independiente.

Para que ORDS funcione, necesita:

  1. Configure los ajustes antes de la instalación.
  2. Complete la instalación de ODRS.
  3. Lanzar ORDS.
  4. Configure ACL (para el esquema de base de datos deseado).

Configuraciones


La distribución ORDS tiene un archivo con parámetros que se ve así por defecto:

db.hostname=
db.port=
db.servicename=
db.sid=
db.username=APEX_PUBLIC_USER
migrate.apex.rest=false
rest.services.apex.add=
rest.services.ords.add=true
schema.tablespace.default=SYSAUX
schema.tablespace.temp=TEMP
standalone.http.port=8080
standalone.static.images=
user.tablespace.default=USERS
user.tablespace.temp=TEMP

Se puede encontrar una descripción de los parámetros en la documentación

Parámetros para el modo independiente:
ParámetroDescripción
db.hostnameNombre o dirección IP del servidor de base de datos Oracle
db.portPuerto DB (por ejemplo, 1521)
db.servicenameServicename Database
db.usernameEl nombre de usuario de la puerta de enlace PL / SQL. Predeterminado = APEX_PUBLIC_USER, pero el ejemplo no planea usar APEX, por lo que puede dejar este parámetro en blanco
db.passwordContraseña de usuario (tampoco completar)
migrate.apex.restTransición de servicios APEX RESTful a ORDS. Establecer en falso si no se utiliza APEX.
rest.services.apex.addConfigurar ORDS para usar en APEX
rest.services.ords.addEstablezca el esquema de la base de datos para ORDS (ORDS_PUBLIC_USER y ORDS_METADATA). El valor debe ser verdadero
schema.tablespace.defaultEspacio de tabla predeterminado para el esquema ORDS_METADATA
schema.tablespace.tempEspacio de tabla temporal para el esquema ORDS_METADATA
standalone.http.portEl puerto en el que se ejecutará ORDS. Este puerto se usará en el URI para acceder a WS.
user.tablespace.defaultEspacio de tabla predeterminado para el esquema ORDS_PUBLIC_USER
user.tablespace.tempEspacio de tabla temporal para el esquema ORDS_PUBLIC_USER
Como resultado, el contenido del archivo debería verse así:

db.hostname=your_server_host_name
db.port=1521
db.servicename=your_db_servicename
migrate.apex.rest=false
rest.services.apex.add=false
rest.services.ords.add=true
schema.tablespace.default=SYSAUX
schema.tablespace.temp=TEMP
standalone.http.port=8888
standalone.static.images=
user.tablespace.default=USERS
user.tablespace.temp=TEMP

Una vez completada la configuración necesaria, puede continuar con la instalación.

Instalación


Ejecutamos el comando en el sistema operativo:

java -jar ords.war

Por defecto, el archivo de configuración se toma del directorio paramsubicado al lado de ords.war. Puede especificar explícitamente la ruta a este archivo utilizando el parámetro --parameterFile:

java -jar ords.war --parameterFile /path/to/params/myown_params.properties

En el cuadro de diálogo de instalación, haga lo siguiente:

  1. Indicamos la ruta al directorio para guardar la configuración (en el ejemplo se indica conf , como resultado, en el mismo directorio donde se encuentra el archivo ords.war, se creará un directorio en el que se crearán conflos archivos con la configuración ORDS).
  2. Después de que aparezca el comando Ingrese la contraseña de la base de datos para ORDS_PUBLIC_USER, ingresamos la contraseña para el esquema ORDS_PUBLIC_USER. Bajo este usuario, ORDS se conectará a la base de datos.
  3. Después de que aparezca el mensaje Ingrese 1 si desea usar PL / SQL Gateway o 2 para omitir este paso, respondemos "2", ya que no vamos a usar APEX y no necesitamos migrar mod_plsql.
  4. Después de la instrucción Ingrese 1 si desea comenzar en modo independiente o aparece 2 para salir [1], respondemos “1”.
  5. Después de la instrucción Ingrese 1 si usa HTTP o 2 si usa HTTPS [1] aparece, respondemos 1.

Diálogo de instalación
D:\ords-19.2.0.199.1647>java -jar ords.war install
This Oracle REST Data Services instance has not yet been configured.
Please complete the following prompts


Enter the location to store configuration data: conf
Enter the database password for ORDS_PUBLIC_USER:
Confirm password:
03, 2019 2:47:49 PM oracle.dbtools.rt.config.setup.SchemaSetup getInstallOrUpgrade
WARNING: Failed to connect to user ORDS_PUBLIC_USER jdbc:oracle:thin:@//***YOUR_HOST_NAME.DOMAIN***:1521/***YOUR_SERVICE_NAME.DOMAIN***

Enter 1 if you want to use PL/SQL Gateway or 2 to skip this step.
If using Oracle Application Express or migrating from mod_plsql then you must enter 1 [1]:2
03, 2019 2:48:32 PM
INFO: reloaded pools: []
Enter 1 if you wish to start in standalone mode or 2 to exit [1]:
Enter 1 if using HTTP or 2 if using HTTPS [1]:
2019-09-03 14:48:49.754:INFO::main: Logging initialized @4276887ms to org.eclipse.jetty.util.log.StdErrLog
03, 2019 2:48:49 PM
INFO: HTTP and HTTP/2 cleartext listening on port: 8082
03, 2019 2:48:50 PM
INFO: Disabling document root because the specified folder does not exist: D:\ords-19.2.0.199.1647\conf\ords\standalone\doc_root
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at oracle.dbtools.jarcl.Entrypoint.invoke(Entrypoint.java:66)
at oracle.dbtools.jarcl.Entrypoint.main(Entrypoint.java:89)
Caused by: java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Unknown Source)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(Unknown Source)
at java.lang.AbstractStringBuilder.append(Unknown Source)
at java.lang.StringBuilder.append(Unknown Source)
at java.lang.StringBuilder.append(Unknown Source)
at java.util.AbstractMap.toString(Unknown Source)
at java.lang.String.valueOf(Unknown Source)
at java.lang.StringBuilder.append(Unknown Source)
at oracle.dbtools.jarcl.zip.ZipIndex.toString(ZipIndex.java:166)
at java.lang.String.valueOf(Unknown Source)
at java.lang.StringBuilder.append(Unknown Source)
at oracle.dbtools.jarcl.JarClassLoader.toString(JarClassLoader.java:51)
at org.eclipse.jetty.server.ClassLoaderDump.dump(ClassLoaderDump.java:67)
at org.eclipse.jetty.util.component.Dumpable.dumpObjects(Dumpable.java:225)
at org.eclipse.jetty.util.component.ContainerLifeCycle.dumpObjects(ContainerLifeCycle.java:746)
at org.eclipse.jetty.server.handler.ContextHandler.dump(ContextHandler.java:259)
at org.eclipse.jetty.util.component.Dumpable.dumpObjects(Dumpable.java:162)
at org.eclipse.jetty.util.component.ContainerLifeCycle.dumpObjects(ContainerLifeCycle.java:746)
at org.eclipse.jetty.util.component.ContainerLifeCycle.dump(ContainerLifeCycle.java:701)
at org.eclipse.jetty.util.component.Dumpable.dump(Dumpable.java:62)
at org.eclipse.jetty.util.component.ContainerLifeCycle.dump(ContainerLifeCycle.java:684)
at oracle.dbtools.standalone.StandaloneConfiguration.start(StandaloneConfiguration.java:241)
at oracle.dbtools.standalone.Standalone.execute(Standalone.java:508)
at oracle.dbtools.cmdline.DefaultCommand.execute(DefaultCommand.java:137)
at oracle.dbtools.cmdline.Commands.execute(Commands.java:207)
at oracle.dbtools.cmdline.Commands.main(Commands.java:163)
at oracle.dbtools.cmdline.Commands.main(Commands.java:368)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at oracle.dbtools.jarcl.Entrypoint.invoke(Entrypoint.java:66)

Como resultado, se creará un directorio con la configuración ORDS y aparecerán esquemas de utilidad para ORDS en la base de datos.

Ver también: instale Oracle REST Data Services 3.0.X en menos de 5 minutos .

Lanzamiento


El inicio sin conexión se realiza mediante el comando:

java -jar ords.war standalone

Iniciar diálogo
D:\ords-19.2.0.199.1647>java -jar ords.war standalone
2019-09-03 15:52:45.825:INFO::main: Logging initialized @2079ms to org.eclipse.jetty.util.log.StdErrLog
03, 2019 3:52:45 PM
INFO: HTTP and HTTP/2 cleartext listening on port: 8082
03, 2019 3:52:45 PM
INFO: Disabling document root because the specified folder does not exist: D:\ords-19.2.0.199.1647\conf\ords\standalone\doc_root
2019-09-03 15:52:47.124:INFO:oejs.Server:main: jetty-9.4.z-SNAPSHOT; built: 2019-05-02T09:46:34.874Z; git: 14f32d50076f2b706f41a33066eb364d8492e199; jvm 1.8.0_221-b11
2019-09-03 15:52:47.179:INFO:oejs.session:main: DefaultSessionIdManager workerName=node0
2019-09-03 15:52:47.179:INFO:oejs.session:main: No SessionScavenger set, using defaults
2019-09-03 15:52:47.180:INFO:oejs.session:main: node0 Scavenging every 660000ms
03, 2019 3:52:48 PM
INFO: Configuration properties for: |apex|pu|
db.hostname=***YOUR_HOST_NAME.DOMAIN***
db.password=******
db.port=1521
db.servicename=***YOUR_SERVICE_NAME.DOMAIN***
db.username=ORDS_PUBLIC_USER
resource.templates.enabled=true

03, 2019 3:52:48 PM
WARNING: *** jdbc.MaxLimit in configuration |apex|pu| is using a value of 10, this setting may not be sized adequately for a production environment ***
03, 2019 3:52:48 PM
WARNING: *** jdbc.InitialLimit in configuration |apex|pu| is using a value of 3, this setting may not be sized adequately for a production environment ***
03, 2019 3:52:50 PM
INFO: Oracle REST Data Services initialized
Oracle REST Data Services version : 19.2.0.r1991647
Oracle REST Data Services server info: jetty/9.4.z-SNAPSHOT

2019-09-03 15:52:50.484:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@d56d67{/ords,null,AVAILABLE}
2019-09-03 15:52:50.658:INFO:oejs.AbstractConnector:main: Started ServerConnector@12325ad{HTTP/1.1,[http/1.1, h2c]}{0.0.
0.0:8082}
2019-09-03 15:52:50.659:INFO:oejs.Server:main: Started @6914ms

Después de eso, ORDS está en funcionamiento. La dirección del servicio web será http: // <hostname>: / ords / ..., donde <hostname> es el nombre de la computadora que ejecuta ORDS (no tiene que coincidir con el nombre del servidor de la base de datos, es decir, ORDS se puede ejecutar en otro host ), <puerto>: el puerto especificado en la configuración de ORDS.

Si lo desea, puede crear una secuencia de comandos para ejecutar ORDS automáticamente cuando se inicia el sistema operativo.

Configuración de acceso


Y el último paso es configurar la ACL. Los pasos son los mismos que con Native Oracle WS.

Debe completar este paso después de que se haya creado el esquema de la base de datos, por lo que los ejemplos a continuación le indicarán por separado cuándo debe realizar esta configuración. Hasta ahora, podemos suponer que se han completado todos los pasos preliminares y proceder con los ejemplos.

Ejemplo 1: controlador para una solicitud POST


Como ejemplo, considere la opción de implementación de interacción de estilo RPC, es decir, crearemos un método de servicio web, cuyo controlador será un procedimiento por lotes.

En realidad, fue en esta versión que el trabajo con ORDS se implementó en nuestro proyecto para la red de distribución, y el resultado cumplió con sus expectativas. Resultó una forma rápida y universal de crear nuevos métodos de servicios web para diferentes procesos comerciales, desde trabajar con equipos hasta la API para sitios.

Como se mencionó anteriormente, el soporte de ORDS también se incluye en SQL Developer (la base de datos IDE desarrollada por Oracle). En SQL Developer, la creación de servicios web está disponible directamente desde los elementos del menú o desde el menú contextual.

En este artículo, se hacen ejemplos usando SQL Developer (versión 18), pero también se incluye el código PL / SQL que se ejecuta en la base de datos como resultado de acciones en el IDE.

La versión de la base de datos en la que se realizaron los experimentos:

SQL> SELECT v.BANNER FROM v$version v;
 
BANNER
--------------------------------------------------------------------------------
Oracle DATABASE 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
PL/SQL Release 12.2.0.1.0 - Production
CORE	12.2.0.1.0	Production
TNS FOR Linux: Version 12.2.0.1.0 - Production
NLSRTL Version 12.2.0.1.0 - Production

Crear un usuario de prueba para WS


Por ejemplo, nuevamente necesitamos un nuevo esquema: créelo:

CREATE USER WS_TEST IDENTIFIED BY ws_test QUOTA 200M ON USERS;
GRANT CREATE SESSION, RESOURCE TO ws_test;

Configurar un esquema de base de datos


Después de crear el diagrama, es necesario hacerlo accesible a través de ORDS.

Para esto:

  1. En SQL Developer, cree una conexión para WS_TEST.
  2. En la lista de conexiones, llame al menú contextual para la nueva conexión. Elija Servicios REST → Habilitar servicios REST ... :


  3. En el cuadro de diálogo, marque la casilla junto a Habilitar esquema (aquí también puede cambiar el parámetro " Alias ​​de esquema " si desea que se muestre ws_testotro texto en el URI en lugar del nombre del esquema ):


  4. Al hacer clic en "Siguiente" , veremos el código PL / SQL que finalmente se ejecutará en la base de datos (y que puede escribir usted mismo sin usar el IDE):



Listado:

BEGIN
    ORDS.ENABLE_SCHEMA( p_enabled             => TRUE
                      , p_schema              => 'WS_TEST'
                      , p_url_mapping_type    => 'BASE_PATH'
                      , p_url_mapping_pattern => 'ws_test'
                      , p_auto_rest_auth      => FALSE);
 
    COMMIT;
END;
/

Crear un módulo y una plantilla


A continuación, debe crear un módulo y una plantilla para el recurso.

Un módulo es una unidad estructural que le permite agrupar varias plantillas de recursos relacionados lógicamente.

Una plantilla es un servicio web específico que sirve un conjunto específico de métodos para un recurso.

En la fuente :

Módulo de recursos: una unidad organizativa que se utiliza para agrupar plantillas de recursos relacionadas.

Plantilla de recursos: un servicio RESTful individual que puede atender solicitudes de algún conjunto de URI (identificadores universales de recursos). El conjunto de URI está definido por el patrón de URI de la plantilla de recursos.


Por ejemplo, para una tienda en línea, se puede llamar a un móduloshop - en este módulo se combinarán todas las API de la tienda. Las plantillas pueden ser recursos específicos, por ejemplo, un pedido (plantilla order), catálogo de productos (plantilla item), pago (plantilla payment), etc.

Para crear un módulo y una plantilla, debe realizar los siguientes pasos:

  1. En el árbol de objetos, abra la sección Servicios de datos REST, llame al menú contextual en la sección Módulos , seleccione Nuevo módulo ... :


  2. En el cuadro de diálogo de creación del módulo, especifique el nombre del módulo ( shop), el prefijo URI (también indique shop : en el ejemplo a continuación, veremos inmediatamente cuál será la plantilla de dirección del servicio web), coloque un mensaje delante de Publicar , haga clic en "Siguiente>" :


  3. En el siguiente cuadro de diálogo, especifique el nombre de la plantilla, por ejemplo order, y vuelva a hacer clic en "Siguiente>" .

    En el último diálogo, vemos todos los parámetros ingresados ​​del módulo y la plantilla. En la pestaña SQL , puede ver el código PL / SQL que se ejecutará en la base de datos cuando haga clic en Finalizar :



Para crear un módulo shop , se puede añadir más patrones - también en el árbol de objetos, el menú contextual y seleccionando el agregar la plantilla ... .

Listado de código para crear un módulo y una plantilla
BEGIN
    ORDS.DEFINE_MODULE( p_module_name    => 'shop'
                      , p_base_path      => 'shop'
                      , p_items_per_page =>  25
                      , p_status         => 'PUBLISHED'
                      , p_comments       => NULL);
 
    ORDS.DEFINE_TEMPLATE( p_module_name    => 'shop'
                        , p_pattern        => 'order'
                        , p_priority       => 0
                        , p_etag_type      => 'HASH'
                        , p_etag_query     => NULL
                        , p_comments       => NULL);
 
    COMMIT;
END;
/

Crear un controlador de solicitud HTTP


Ahora necesitamos crear un controlador de solicitud HTTP para nuestro servicio.

Primero, necesitamos crear objetos de base de datos que contendrán la lógica de procesamiento de solicitudes.

Necesitamos una tabla para iniciar sesión y un paquete en el que habrá un código de controlador.

Crea una tabla usando un script:
CREATE TABLE T_WS_LOG
(
  id_log          NUMBER GENERATED ALWAYS AS IDENTITY,
  message         VARCHAR2(2000),
  request_header  VARCHAR2(2000),
  request_body    CLOB,
  response_header VARCHAR2(2000),
  response_body   CLOB,
  dtz_log         TIMESTAMP(6) WITH TIME ZONE DEFAULT SYSTIMESTAMP
);
COMMENT ON TABLE T_WS_LOG IS '  HTTP- (ORDS)';
COMMENT ON COLUMN T_WS_LOG.id_log IS '';
COMMENT ON COLUMN T_WS_LOG.message IS ' ';
COMMENT ON COLUMN T_WS_LOG.request_header IS ' ';
COMMENT ON COLUMN T_WS_LOG.request_body IS ' ';
COMMENT ON COLUMN T_WS_LOG.response_header IS ' ';
COMMENT ON COLUMN T_WS_LOG.response_body IS ' ';
COMMENT ON COLUMN T_WS_LOG.dtz_log IS '/  ';
ALTER TABLE T_WS_LOG ADD CONSTRAINT PK_T_WS_LOG PRIMARY KEY (ID_LOG) USING INDEX;

Crea un paquete:
CREATE OR REPLACE PACKAGE PK_ORDS_API IS
 
 
FUNCTION blob2clob
    ( a_blob            BLOB
    , a_from_charset    VARCHAR2  := 'AMERICAN_AMERICA.AL32UTF8'
    , a_to_charset      VARCHAR2  := 'AMERICAN_AMERICA.AL32UTF8'
    ) RETURN            CLOB;
 
 
PROCEDURE process_request
    ( a_request     CLOB
    );
 
 
END PK_ORDS_API;
/
 
CREATE OR REPLACE PACKAGE BODY PK_ORDS_API IS
 
 
FUNCTION blob2clob
    ( a_blob            BLOB
    , a_from_charset    VARCHAR2  := 'AMERICAN_AMERICA.AL32UTF8'
    , a_to_charset      VARCHAR2  := 'AMERICAN_AMERICA.AL32UTF8'
    ) RETURN            CLOB
AS
    l_clob      CLOB;
    l_amount    NUMBER := 2000;
    l_offset    NUMBER := 1;
    l_buffer    VARCHAR2(32767);
    l_length    PLS_INTEGER := dbms_lob.getlength(a_blob);
BEGIN
    dbms_lob.createtemporary(l_clob, TRUE);
    dbms_lob.OPEN(l_clob, dbms_lob.lob_readwrite);
    WHILE l_offset <= l_length LOOP
        l_buffer := UTL_RAW.cast_to_varchar2(UTL_RAW.convert( r            => dbms_lob.substr(a_blob, l_amount, l_offset)
                                                            , from_charset => a_from_charset
                                                            , to_charset   => a_to_charset));
        IF LENGTH(l_buffer) > 0 THEN
            dbms_lob.writeappend(l_clob, LENGTH(l_buffer), l_buffer);
        END IF;
        l_offset := l_offset + l_amount;
        EXIT WHEN l_offset > l_length;
    END LOOP;
    RETURN l_clob;
END blob2clob;
 
 
PROCEDURE process_request
    ( a_request     CLOB
    )
AS
    TYPE TStringHash IS TABLE OF VARCHAR2(256) INDEX BY VARCHAR2(256);
    lh_hdr              TStringHash;
    l_hdr               VARCHAR2(256);
    l_resp              CLOB;
    l_response_status   INTEGER := 200;
    l_ccontent_type     VARCHAR2(64) := 'application/json';
    l_in_headers        VARCHAR2(32767);
BEGIN
    --      
    lh_hdr('SERVER_SOFTWARE')       := OWA_UTIL.get_cgi_env('SERVER_SOFTWARE');
    lh_hdr('SERVER_NAME')           := OWA_UTIL.get_cgi_env('SERVER_NAME');
    lh_hdr('GATEWAY_INTERFACE')     := OWA_UTIL.get_cgi_env('GATEWAY_INTERFACE');
    lh_hdr('SERVER_PROTOCOL')       := OWA_UTIL.get_cgi_env('SERVER_PROTOCOL');
    lh_hdr('SERVER_PORT')           := OWA_UTIL.get_cgi_env('SERVER_PORT');
    lh_hdr('REQUEST_METHOD')        := OWA_UTIL.get_cgi_env('REQUEST_METHOD');
    lh_hdr('PATH_INFO')             := OWA_UTIL.get_cgi_env('PATH_INFO');
    lh_hdr('PATH_TRANSLATED')       := OWA_UTIL.get_cgi_env('PATH_TRANSLATED');
    lh_hdr('SCRIPT_NAME')           := OWA_UTIL.get_cgi_env('SCRIPT_NAME');
    lh_hdr('QUERY_STRING')          := OWA_UTIL.get_cgi_env('QUERY_STRING');
    lh_hdr('REMOTE_HOST')           := OWA_UTIL.get_cgi_env('REMOTE_HOST');
    lh_hdr('REMOTE_ADDR')           := OWA_UTIL.get_cgi_env('REMOTE_ADDR');
    lh_hdr('AUTH_TYPE')             := OWA_UTIL.get_cgi_env('AUTH_TYPE');
    lh_hdr('REMOTE_USER')           := OWA_UTIL.get_cgi_env('REMOTE_USER');
    lh_hdr('REMOTE_IDENT')          := OWA_UTIL.get_cgi_env('REMOTE_IDENT');
    lh_hdr('CONTENT-TYPE')          := OWA_UTIL.get_cgi_env('CONTENT-TYPE');
    lh_hdr('CONTENT-LENGTH')        := OWA_UTIL.get_cgi_env('CONTENT-LENGTH');
    lh_hdr('HTTP_ACCEPT')           := OWA_UTIL.get_cgi_env('HTTP_ACCEPT');
    lh_hdr('HTTP_ACCEPT_LANGUAGE')  := OWA_UTIL.get_cgi_env('HTTP_ACCEPT_LANGUAGE');
    lh_hdr('HTTP_USER_AGENT')       := OWA_UTIL.get_cgi_env('HTTP_USER_AGENT');
    lh_hdr('HTTP_COOKIE')           := OWA_UTIL.get_cgi_env('HTTP_COOKIE');
 
    l_hdr := lh_hdr.FIRST;
    WHILE l_hdr IS NOT NULL LOOP
        IF lh_hdr(l_hdr) IS NOT NULL THEN
            l_in_headers := l_in_headers||CHR(10)||l_hdr||': '||lh_hdr(l_hdr);
        END IF;
        l_hdr := lh_hdr.NEXT(l_hdr);
    END LOOP;
 
    l_resp := '{ "result" : "success" }';
 
    INSERT INTO t_ws_log
        ( message
        , request_header
        , request_body
        , response_header
        , response_body)
    VALUES
        ( NULL
        , l_in_headers
        , a_request
        , 'Content-Type: '||l_ccontent_type
        , l_resp
        );
 
    OWA_UTIL.STATUS_LINE(nstatus => l_response_status, bclose_header => FALSE);
    OWA_UTIL.MIME_HEADER(ccontent_type => l_ccontent_type, bclose_header => FALSE);
    OWA_UTIL.HTTP_HEADER_CLOSE();
    htp.p(l_resp);
END process_request;
 
END PK_ORDS_API;
/

Ahora, para la plantilla creada, debe agregar un controlador. Agregue un controlador para el método HTTP POST.

Para hacer esto, realice los siguientes pasos:

  1. Llamamos al menú contextual de la plantilla, seleccionamos Agregar controlador y luego seleccionamos el método HTTP:

  2. . SQL Worksheet PL/SQL-, HTTP- POST. , process_request . , bind- :body — ORDS, ( BLOB). . :body_text, CLOB. , , , ORDS . :body_text , «» . :body, CLOB . , :


  3. Save REST Handler — .

    POST-:

    DECLARE
        l_blob BLOB := :body;
    BEGIN
        PK_ORDS_API.process_request(a_request => PK_ORDS_API.blob2clob(l_blob));
    EXCEPTION
        WHEN OTHERS THEN
            OWA_UTIL.STATUS_LINE(nstatus => 500, bclose_header => FALSE);
            OWA_UTIL.MIME_HEADER(ccontent_type => 'application/json');
            htp.p('{ "result" : "error", "message" : "'||SQLERRM||'" }');
    END;

    Si es necesario, puede obtener el código PL / SQL para crear un controlador. Para hacer esto, en el menú contextual del módulo ORDS, seleccione Definición REST y luego especifique dónde generar el script de creación del módulo, por ejemplo, en el portapapeles:


El código resultante para crear el módulo.
-- Generated by Oracle SQL Developer REST Data Services 18.1.0.095.1630
-- Exported REST Definitions from ORDS Schema Version 18.4.0.r3541002
-- Schema: WS_TEST   Date: Wed Oct 23 20:19:54 MSK 2019
--
BEGIN
  ORDS.ENABLE_SCHEMA(
      p_enabled             => TRUE,
      p_schema              => 'WS_TEST',
      p_url_mapping_type    => 'BASE_PATH',
      p_url_mapping_pattern => 'ws_test',
      p_auto_rest_auth      => TRUE);    
 
  ORDS.DEFINE_MODULE(
      p_module_name    => 'shop',
      p_base_path      => '/shop/',
      p_items_per_page =>  25,
      p_status         => 'PUBLISHED',
      p_comments       => NULL);      
  ORDS.DEFINE_TEMPLATE(
      p_module_name    => 'shop',
      p_pattern        => 'order',
      p_priority       => 0,
      p_etag_type      => 'HASH',
      p_etag_query     => NULL,
      p_comments       => NULL);
  ORDS.DEFINE_HANDLER(
      p_module_name    => 'shop',
      p_pattern        => 'order',
      p_method         => 'POST',
      p_source_type    => 'plsql/block',
      p_items_per_page =>  0,
      p_mimes_allowed  => '',
      p_comments       => NULL,
      p_source         => 
'DECLARE
    l_blob BLOB := :body;
BEGIN
    PK_ORDS_API.process_request(a_request => PK_ORDS_API.blob2clob(l_blob));
EXCEPTION
    WHEN OTHERS THEN
        OWA_UTIL.STATUS_LINE(nstatus => 500, bclose_header => FALSE);
        OWA_UTIL.MIME_HEADER(ccontent_type => ''application/json'');
        htp.p(''{ "result" : "error", "message" : "''||SQLERRM||''" }'');
END;'
      );
 
 
  COMMIT; 
END;


Nota: si ORDS.DEFINE_MODULEvuelve a ejecutar el procedimiento de creación del módulo , todas las plantillas de este módulo se eliminarán automáticamente, ¡y no habrá ninguna advertencia al respecto!

Ejemplo de llamada


Aquí es donde nuestro servicio web está listo. Queda por comprobar su trabajo.

Para verificar, ejecutamos la solicitud:

POST http://****:8888/ords/ws_test/shop/order HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/json
Content-Length: 22
Host: ****:8888
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
 
{ "message" : "test" }

En respuesta, obtenemos:

HTTP/1.1 200 OK
Date: Wed, 23 Oct 2019 16:54:53 GMT
Content-Type: application/json
Transfer-Encoding: chunked
 
{ "result" : "success" }

El resultado de la ejecución del método es una entrada con el cuerpo de la solicitud y la respuesta en la tabla de registro:



Como puede ver, la solicitud HTTP enviada fue procesada con éxito por el procedimiento del paquete.

Parámetros de la solicitud.


Arriba, ya hemos visto el resultado de un servicio web simple. Ahora vamos a complicar un poco la tarea agregando parámetros adicionales a la solicitud.

Hay dos formas de pasar parámetros:

Vía URL. Los parámetros se establecen en la URL en la forma estándar:

http://...URI...?p1=val1&p2=val2

A través de HEADER. Los parámetros se establecen en el encabezado de la solicitud como p1: val1

En ORDS en el controlador de solicitudes, los parámetros se definen como variables de enlace.

Agregamos dos parámetros al ejemplo anterior: prm1- parámetro en el URI, prm2- parámetro en el encabezado de la solicitud.

Para procesar estos parámetros, PK_ORDS_API.process_request:agregamos el procedimiento, agregamos los parámetros a_prm_uriy a_prm_hdr, a los que vendrán los valores de nuestros parámetros de la solicitud.

Solicitar procedimiento de manejador con nuevos parámetros
PROCEDURE process_request
    ( a_request     CLOB
    , a_prm_uri     VARCHAR2 := NULL
    , a_prm_hdr     VARCHAR2 := NULL
    )
AS
    TYPE TStringHash IS TABLE OF VARCHAR2(256) INDEX BY VARCHAR2(256);
    lh_hdr              TStringHash;
    l_hdr               VARCHAR2(256);
    l_resp              CLOB;
    l_response_status   INTEGER := 200;
    l_ccontent_type     VARCHAR2(64) := 'application/json';
    l_in_headers        VARCHAR2(32767);
BEGIN
    --      
    lh_hdr('SERVER_SOFTWARE')       := OWA_UTIL.get_cgi_env('SERVER_SOFTWARE');
    lh_hdr('SERVER_NAME')           := OWA_UTIL.get_cgi_env('SERVER_NAME');
    lh_hdr('GATEWAY_INTERFACE')     := OWA_UTIL.get_cgi_env('GATEWAY_INTERFACE');
    lh_hdr('SERVER_PROTOCOL')       := OWA_UTIL.get_cgi_env('SERVER_PROTOCOL');
    lh_hdr('SERVER_PORT')           := OWA_UTIL.get_cgi_env('SERVER_PORT');
    lh_hdr('REQUEST_METHOD')        := OWA_UTIL.get_cgi_env('REQUEST_METHOD');
    lh_hdr('PATH_INFO')             := OWA_UTIL.get_cgi_env('PATH_INFO');
    lh_hdr('PATH_TRANSLATED')       := OWA_UTIL.get_cgi_env('PATH_TRANSLATED');
    lh_hdr('SCRIPT_NAME')           := OWA_UTIL.get_cgi_env('SCRIPT_NAME');
    lh_hdr('QUERY_STRING')          := OWA_UTIL.get_cgi_env('QUERY_STRING');
    lh_hdr('REMOTE_HOST')           := OWA_UTIL.get_cgi_env('REMOTE_HOST');
    lh_hdr('REMOTE_ADDR')           := OWA_UTIL.get_cgi_env('REMOTE_ADDR');
    lh_hdr('AUTH_TYPE')             := OWA_UTIL.get_cgi_env('AUTH_TYPE');
    lh_hdr('REMOTE_USER')           := OWA_UTIL.get_cgi_env('REMOTE_USER');
    lh_hdr('REMOTE_IDENT')          := OWA_UTIL.get_cgi_env('REMOTE_IDENT');
    lh_hdr('CONTENT-TYPE')          := OWA_UTIL.get_cgi_env('CONTENT-TYPE');
    lh_hdr('CONTENT-LENGTH')        := OWA_UTIL.get_cgi_env('CONTENT-LENGTH');
    lh_hdr('HTTP_ACCEPT')           := OWA_UTIL.get_cgi_env('HTTP_ACCEPT');
    lh_hdr('HTTP_ACCEPT_LANGUAGE')  := OWA_UTIL.get_cgi_env('HTTP_ACCEPT_LANGUAGE');
    lh_hdr('HTTP_USER_AGENT')       := OWA_UTIL.get_cgi_env('HTTP_USER_AGENT');
    lh_hdr('HTTP_COOKIE')           := OWA_UTIL.get_cgi_env('HTTP_COOKIE');
    lh_hdr('a_prm_uri')             := a_prm_uri;
    lh_hdr('a_prm_hdr')             := a_prm_hdr;
 
    l_hdr := lh_hdr.FIRST;
    WHILE l_hdr IS NOT NULL LOOP
        IF lh_hdr(l_hdr) IS NOT NULL THEN
            l_in_headers := l_in_headers||CHR(10)||l_hdr||': '||lh_hdr(l_hdr);
        END IF;
        l_hdr := lh_hdr.NEXT(l_hdr);
    END LOOP;
 
    l_resp := '{ "result" : "success" }';
 
    INSERT INTO t_ws_log
        ( message
        , request_header
        , request_body
        , response_header
        , response_body)
    VALUES
        ( NULL
        , l_in_headers
        , a_request
        , 'Content-Type: '||l_ccontent_type
        , l_resp);
 
    OWA_UTIL.STATUS_LINE(nstatus => l_response_status, bclose_header => FALSE);
    OWA_UTIL.MIME_HEADER(ccontent_type => l_ccontent_type, bclose_header => FALSE);
    OWA_UTIL.HTTP_HEADER_CLOSE();
    htp.p(l_resp);
END process_request;

Dentro del procedimiento, simplemente registramos los valores de los nuevos parámetros en el registro.

Agregue nuevos parámetros al manejador de solicitud POST, en forma de variables de enlace :prm_uriy :prm_hdr.

Manejador de la solicitud de solicitud POST con nuevos parámetros:

DECLARE
    l_blob BLOB := :body;
BEGIN
    PK_ORDS_API.process_request(a_request => PK_ORDS_API.blob2clob(l_blob), a_prm_uri => :prm_uri, a_prm_hdr => :prm_hdr);
EXCEPTION
    WHEN OTHERS THEN
        OWA_UTIL.STATUS_LINE(nstatus => 500, bclose_header => FALSE);
        OWA_UTIL.MIME_HEADER(ccontent_type => 'application/json');
        htp.p('{ "result" : "error", "message" : "'||SQLERRM||'" }');
END;

En el controlador, en la pestaña Parámetros , declare las variables:


en este formulario, el primer campo ( Nombre ) contiene el nombre del parámetro que se espera en la solicitud, el segundo campo ( Parámetro de enlace ), el nombre de la variable de enlace que se especificará en el controlador de esta solicitud.

Ejecutemos la solicitud con nuevos parámetros:



Resultado: los parámetros de la solicitud se guardaron en el registro:


tenga en cuenta que los parámetros del URI también se pueden recuperar de la variable CGI QUERY_STRING, es decir, para obtener los parámetros no es necesario iniciar las variables de enlace; puede analizarlos en el procedimiento del controlador solicitud.

Variables CGI


Cuando se trabaja con HTTP en Oracle, es posible obtener los valores de las variables de entorno que reflejan el contexto de la solicitud HTTP. Puede obtener los valores de las variables utilizando el procedimiento OWA_UTIL.get_cgi_env.

Lista de variables CGI disponibles en PL / SQL
APEX_LISTENER_VERSION
GATEWAY_INTERFACE
GATEWAY_IVERSION
HTTP_ACCEPT_ENCODING
HTTP_HOST
HTTP_PORT
HTTP_USER_AGENT
PATH_ALIAS
PATH_INFO
PLSQL_GATEWAY
QUERY_STRING
REMOTE_ADDR
REMOTE_USER
REQUEST_CHARSET
REQUEST_IANA_CHARSET
REQUEST_METHOD
REQUEST_PROTOCOL
REQUEST_SCHEME
SCRIPT_NAME
SERVER_NAME
SERVER_PORT
SERVER_PROTOCOL
SERVER_SOFTWARE
WEB_AUTHENT_PREFIX
host
user-agent
CONTENT-LENGTH
CONTENT-TYPE

Consulte también: Encabezados HTTP (OWA_UTIL) y variables de enlace específicas de ORDS

Ejemplo 2: acceder a una tabla a través de ORDS


En este ejemplo, consideramos la organización del acceso a un objeto de base de datos (a una tabla) a través de ORDS.

Como en el ejemplo anterior, hacemos acceso sin autorización. Vea cómo hacer un acceso seguro a los recursos en la documentación .

Para hacer que un objeto de base de datos sea accesible a través de ORDS, solo necesita realizar un paso: el comando ORDS.ENABLE_OBJECT. Después de eso, se puede acceder al objeto mediante un URI de la forma:

http://<HOST>:<PORT>/ords/<SchemaAlias>/<ObjectAlias>
.

Crea un patrón de prueba


Por ejemplo, crearemos la tabla "Pedidos".

Script de creación de tabla:

CREATE TABLE T_ORDER
(
  id_order   NUMBER NOT NULL,
  NUM        VARCHAR2(32),
  buyer_name VARCHAR2(256),
  dt_order   DATE,
  memo       VARCHAR2(2000)
);
 
COMMENT ON TABLE T_ORDER IS '';
COMMENT ON COLUMN T_ORDER.id_order IS ' ';
COMMENT ON COLUMN T_ORDER.num IS ' ';
COMMENT ON COLUMN T_ORDER.buyer_name IS ' ';
COMMENT ON COLUMN T_ORDER.dt_order IS '  ';
COMMENT ON COLUMN T_ORDER.memo IS '';
ALTER TABLE T_ORDER ADD CONSTRAINT PK_T_ORDER PRIMARY KEY (ID_ORDER) USING INDEX;

Apertura del acceso a la mesa a través de ORDS


  1. En SQL Developer invocar el menú contextual de la tabla sea necesario, seleccione el habilitar el servicio lo demás ... .



  2. En la ventana de configuración de acceso, marque la casilla de verificación Habilitar objeto , desactive la casilla de verificación Autorización requerida , haga clic en "Finalizar" (o "Siguiente" para ver el código PL / SQL recibido):



  3. Después de realizar estos pasos, la tabla T_ORDERestará disponible a través de HTTP, el URI base para acceder al recurso:

    http://<server>:<port>/ords/ws_test/t_order

    Lista de inclusión de tabla:

    DECLARE
      PRAGMA AUTONOMOUS_TRANSACTION;
    BEGIN
     
        ORDS.ENABLE_OBJECT(p_enabled => TRUE,
                           p_schema => 'WS_TEST',
                           p_object => 'T_ORDER',
                           p_object_type => 'TABLE',
                           p_object_alias => 't_order',
                           p_auto_rest_auth => FALSE);
     
        commit;
     
    END;
    /


Crear o editar un registro


El acceso a la tabla está abierto: verificamos cómo puede crear y editar registros en la tabla a través de ORDS.

Para crear un registro, ejecutamos la solicitud PUT.

En la documentación de ORDS, la siguiente descripción PUTse especifica en la descripción del método :

PUT http://<HOST>:<PORT>/ords/<SchemaAlias>/<ObjectAlias>/<KeyValues>

Es decir, el campo KeyValues(clave de registro) debe rellenarse incluso para crear un nuevo registro. La consulta en sí debe enumerar todos los campos de la tabla (pero el campo clave se puede omitir).

Investigación
PUT http://<server>:<port>/ords/ws_test/t_order/25 HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/json;charset=UTF-8
Content-Length: 157
Host: <server>:<port>
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
 
{
	"num" : "ords-3472634",
	"buyer_name" : "Buyer Name",
	"dt_order" : "2019-10-25T12:00:00Z",
	"memo" : "  1"
}

En respuesta, obtenemos todos los campos del registro recién creado:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Location: http://<server>:<port>/ords/ws_test/t_order/25
ETag: "..."
Transfer-Encoding: chunked
 
{
   "id_order": 25,
   "num": "ords-3472634",
   "buyer_name": "Buyer Name",
   "dt_order": "2019-10-25T12:00:00Z",
   "memo": "  1",
   "links":    [
            {
         "rel": "self",
         "href": "http://<server>:<port>/ords/ws_test/t_order/25"
      },
            {
         "rel": "edit",
         "href": "http://<server>:<port>/ords/ws_test/t_order/25"
      },
            {
         "rel": "describedby",
         "href": "http://<server>:<port>/ords/ws_test/metadata-catalog/t_order/item"
      },
            {
         "rel": "collection",
         "href": "http://<server>:<port>/ords/ws_test/t_order/"
      }
   ]
}

Observamos el contenido de la tabla: apareció nuestro nuevo registro:



para cambiar el registro, llamamos al mismo método PUT. Cambia la nota en nuestro pedido:

PUT http://<server>:<port>/ords/ws_test/t_order/25 HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/json;charset=UTF-8
Content-Length: 178
Host: <server>:<port>
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
 
{
	"num" : "ords-3472634",
	"buyer_name" : "Buyer Name",
	"dt_order" : "2019-10-25T12:00:00Z",
	"memo" : "  1.  "
}

En la respuesta obtenemos el mismo JSON con los parámetros del registro modificado. En la tabla, vemos que la nota se ha actualizado:



Recuperando registros de una tabla


Hay tres modos de consultar datos de una tabla:

  1. Solicitud de página:

    GET http://<HOST>:<PORT>/ords/<SchemaAlias>/<ObjectAlias>/?offset=<Offset>&limit=<Limit>
  2. Solicitud de condiciones:

     GET http://<HOST>:<PORT>/ords/<SchemaAlias>/<ObjectAlias>/?q=<FilterClause>
  3. Solicitud de clave principal:

    GET http://<HOST>:<PORT>/ords/<SchemaAlias>/<ObjectAlias>/<KeyValues>

Para obtener todos los registros, puede ejecutar la consulta sin especificar ningún parámetro:

GET http://<server>:<port>/ords/ws_test/t_order/

Responder
HTTP/1.1 200 OK
Date: Fri, 25 Oct 2019 15:39:58 GMT
Content-Type: application/json
ETag: "..."
Transfer-Encoding: chunked
 
{
   "items": [   {
      "id_order": 25,
      "num": "ords-3472634",
      "buyer_name": "Buyer Name",
      "dt_order": "2019-10-25T12:00:00Z",
      "memo": "ўµЃ‚ѕІ‹№ ·°є°· 1.  ·јµЅ‚Њ їЂјµ‡°Ѕµ",
      "links": [      {
         "rel": "self",
         "href": "http://<server>:<port>/ords/ws_test/t_order/25"
      }]
   }],
   "hasMore": false,
   "limit": 25,
   "offset": 0,
   "count": 1,
   "links":    [
            {
         "rel": "self",
         "href": "http://<server>:<port>/ords/ws_test/t_order/"
      },
            {
         "rel": "edit",
         "href": "http://<server>:<port>/ords/ws_test/t_order/"
      },
            {
         "rel": "describedby",
         "href": "http://<server>:<port>/ords/ws_test/metadata-catalog/t_order/"
      },
            {
         "rel": "first",
         "href": "http://<server>:<port>/ords/ws_test/t_order/"
      }
   ]
}

Cómo hacer que Oracle agregue una codificación al encabezado Content-Type es una pregunta abierta.

GET http://<server>:<port>/ords/ws_test/t_order/25

Responder
HTTP/1.1 200 OK
Date: Fri, 25 Oct 2019 15:44:35 GMT
Content-Type: application/json
ETag: "..."
Transfer-Encoding: chunked
 
{
   "id_order": 25,
   "num": "ords-3472634",
   "buyer_name": "Buyer Name",
   "dt_order": "2019-10-25T12:00:00Z",
   "memo": "ўµЃ‚ѕІ‹№ ·°є°· 1.  ·јµЅ‚Њ їЂјµ‡°Ѕµ",
   "links":    [
            {
         "rel": "self",
         "href": "http://<server>:<port>/ords/ws_test/t_order/25"
      },
            {
         "rel": "edit",
         "href": "http://<server>:<port>/ords/ws_test/t_order/25"
      },
            {
         "rel": "describedby",
         "href": "http://<server>:<port>/ords/ws_test/metadata-catalog/t_order/item"
      },
            {
         "rel": "collection",
         "href": "http://<server>:<port>/ords/ws_test/t_order/"
      }
   ]
}

Eliminar el registro


Para eliminar, use el método HTTP DELETE.

Investigación:

DELETE http://<server>:<port>/ords/ws_test/t_order/?q={"id_order":25}

La solicitud en su forma original:

DELETE http://<server>:<port>/ords/ws_test/t_order/?q=%7B%22id_order%22%3A25%7D

Responder:

HTTP/1.1 200 OK
Date=Fri, 25 Oct 2019 16:23:39 GMT
Content-Type=application/json
Transfer-Encoding=chunked
 
{"rowsDeleted":1}

recomendaciones


ORDS es un mecanismo bastante flexible y versátil para trabajar con servicios web, que le permite implementar REST completo. En términos de rendimiento, es muy superior a Native Oracle WS con su gran análisis interno de XML. Para implementar un sistema altamente cargado, este enfoque no es adecuado: en este caso, se necesita una pila de tecnología diferente: un servidor de aplicaciones separado, solicitudes de representación, uso de bases de datos agrupadas, etc. Sin embargo, para la implementación de sistemas con un número relativamente pequeño de solicitudes HTTP (hasta 10–20 por segundo), ORDS es el enfoque óptimo tanto en rendimiento como en flexibilidad. ORDS es inferior a Native Oracle WS solo en términos de generación de una especificación de servicio web: este último proporciona una especificación completamente terminada (WSDL), que se puede dar "tal cual" a los consumidores del servicio. ORDS también tiene la habilidadgeneración de una descripción, pero para el enfoque considerado en este artículo con un servicio totalmente universal (cuando existe un procedimiento de procesamiento común para todos los servicios), la generación automática de la especificación se vuelve imposible. Oracle solo generará una especificación de nivel superior, y las partes (modelos de datos) deberán describirse manualmente.

Aproximaciones alternativas


Servlet Java


Esta opción para crear servicios web en el método de configuración es similar a Native WS WS: también requiere el uso del servidor HTTP incorporado de Oracle, así como la configuración de ACL (así como todos los demás métodos). Pero, a diferencia de Native Oracle WS, esta opción funciona con HTTP puro. Los gestores dependientes en este caso están escritos en Java y se ven sólo en el tipo de petición de HTTP ( PUT, GET, POST, y así sucesivamente, a pesar de que se puede hacer y un controlador para todos los tipos), y el procesamiento de la lógica permanece completamente a discreción del desarrollador. Puede transferir el cuerpo de la solicitud "tal cual" a la lógica de la base de datos, y allí puede desmontarse y procesarse, puede dejar parte de la lógica en el lateral del controlador Java y, desde la base de datos, llamar al procedimiento necesario en función de los datos recibidos en la solicitud.

Este enfoque para la implementación de servicios web es bastante universal y tampoco requiere la instalación de ningún componente adicional. No logramos aplicarlo solo debido a los estrictos requisitos del servicio: necesitábamos un servicio web que no requiriera autenticación. Al implementar este enfoque, se requiere autenticación, y este requisito no se puede eludir.

Consulte la documentación de Oracle para obtener más detalles sobre este método .

Descriptor de acceso a la base de datos (PL / SQL Servlet)


Esta opción es completamente similar a la anterior, solo el procedimiento almacenado PL / SQL actúa como el manejador de solicitudes.

URL de ejemplo: se indican el nombre del paquete, el nombre del procedimiento, los parámetros (solicitud GET):

GET http://<server>:<port>/servlet_plsql/pi_test.test_serv?p_path=ppp 

En el caso de una solicitud POST, los nombres de los parámetros deben ingresarse directamente en el cuerpo de la solicitud a través del signo "=", lo cual es bastante inconveniente, ya que el tipo de contenido de la solicitud (ContentType) en este caso solo puede ser texto. Puede transferir una estructura xml o json solo de esta forma:

p_proc_param_name=<xml_data>…</xml_data>

Esta versión del servicio web es aplicable solo en los casos en que se trata de solicitudes muy simples: llamadas de procedimiento con tipos de datos simples. Transmitir cualquier estructura compleja de varios niveles en esta opción no funcionará.

Este enfoque se describe en detalle en el sitio web ORACLE-BASE.

Conclusión


Crear un servicio web en Oracle es una tarea bastante simple que no requiere escribir ningún tipo de código súper complejo. Al mismo tiempo, los desarrolladores de Oracle incorporan a su arsenal un mecanismo bastante poderoso que le permite integrar sistemas heterogéneos o partes de sistemas a través de HTTP.

En este artículo, examinamos cuatro enfoques para crear servicios web.

Native Oracle WS es una tecnología obsoleta que, sin embargo, tiene sus ventajas: WSDL generado automáticamente, análisis automático de XML, sin necesidad de instalar software adicional. El principal inconveniente es el bajo rendimiento y la limitación de los tipos de datos admitidos.

ORDENES- En mi opinión, la forma preferida de crear servicios web. Lo suficientemente flexible y versátil. De los inconvenientes de este método, solo podemos distinguir que no está incluido en el paquete estándar de Oracle, es decir, requiere una instalación por separado.

Java Servlet es una forma completamente universal que no requiere la instalación de software adicional. Sin embargo, todo debe hacerse de forma completamente manual, ya que no hay posibilidad de servicios de generación automática.

PL / SQL Servlet es el enfoque menos exitoso. De las ventajas, podemos distinguir que en esta opción tenemos la posibilidad de llamar a procedimientos almacenados a través de HTTP sin la necesidad de instalar software adicional, o sin escribir código adicional en otros idiomas: todo el código está escrito solo en PL / SQL.

¡Gracias a todos por su atención! Espero que el material del artículo sea útil para aquellos que de alguna manera están conectados con los productos de Oracle y están desconcertados por los problemas de integración entre sistemas e intersistemas.


All Articles