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.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:- Servicios web nativos de Oracle XML DB
- Servicio de datos REST de Oracle
- Servlet Java
- 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):- - : , 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á:- Configure el servidor HTTP incorporado en Oracle.
- Configure el acceso dentro de la base de datos Oracle (abra el puerto HTTP).
- Crea un servlet.
- 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
- 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. - Configuración de puerto.
BEGIN
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
DECLARE
l_servlet_name VARCHAR2(32) := 'orawsv';
BEGIN
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
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:
DECLARE
l_ws_user VARCHAR2(32) := 'WS_SOAP_TEST';
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||'"';
BEGIN
dbms_network_acl_admin.drop_acl(acl => '/sys/acls/'||l_acl);
EXCEPTION
WHEN dbms_network_acl_admin.acl_not_found THEN
NULL;
END;
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);
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:- 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. - 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 '/ ';
- 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 1
vemos 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:- Configure los ajustes antes de la instalación.
- Complete la instalación de ODRS.
- Lanzar ORDS.
- 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ónParámetros para el modo independiente: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 params
ubicado 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:- 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 conf
los archivos con la configuración ORDS). - 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. - 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
. - Después de la instrucción Ingrese 1 si desea comenzar en modo independiente o aparece 2 para salir [1], respondemos “1”.
- Después de la instrucción Ingrese 1 si usa HTTP o 2 si usa HTTPS [1] aparece, respondemos 1.
Diálogo de instalaciónD:\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álogoD:\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:- En SQL Developer, cree una conexión para
WS_TEST
. - En la lista de conexiones, llame al menú contextual para la nueva conexión. Elija Servicios REST → Habilitar servicios REST ... :

- 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_test
otro texto en el URI en lugar del nombre del esquema ):

- 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:- 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 ... :

- 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>" :

- 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 plantillaBEGIN
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:- Llamamos al menú contextual de la plantilla, seleccionamos Agregar controlador y luego seleccionamos el método HTTP:

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

- 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.
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_MODULE
vuelve 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_uri
y a_prm_hdr
, a los que vendrán los valores de nuestros parámetros de la solicitud.Solicitar procedimiento de manejador con nuevos parámetrosPROCEDURE 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_uri
y :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 / SQLAPEX_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 ORDSEjemplo 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
- En SQL Developer invocar el menú contextual de la tabla sea necesario, seleccione el habilitar el servicio lo demás ... .

- 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):

- Después de realizar estos pasos, la tabla
T_ORDER
estará 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 PUT
se 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ónPUT 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:- Solicitud de página:
GET http://<HOST>:<PORT>/ords/<SchemaAlias>/<ObjectAlias>/?offset=<Offset>&limit=<Limit>
- Solicitud de condiciones:
GET http://<HOST>:<PORT>/ords/<SchemaAlias>/<ObjectAlias>/?q=<FilterClause>
- 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/
ResponderHTTP/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
ResponderHTTP/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.