Serviços Web no Oracle



Serviços webamplamente utilizado para integração entre componentes de um sistema ou entre sistemas diferentes. A popularidade dos serviços da Web como forma de integração se deve à sua versatilidade, bem como à facilidade de implementação e depuração. A versatilidade está associada à transferência de dados usando a Internet e o protocolo HTTP. Os serviços da Web facilitam a construção de integrações entre componentes escritos em diferentes idiomas, executados em diferentes sistemas operacionais e plataformas. A facilidade de implementar serviços da Web é obtida por meio de ferramentas e componentes integrados em muitos IDEs que permitem desenvolver rapidamente o serviço da Web (lado do provedor) e o código necessário para chamar o serviço no lado do cliente. Os serviços de depuração são simplificados pelo uso de formatos de troca de dados legíveis por humanos - XML ​​e JSON. Além disso,Existem muitos utilitários para serviços de depuração e teste, incluindo carga.

Neste artigo, consideraremos várias maneiras de criar serviços da Web diretamente do Oracle DBMS, ou seja, sem usar ferramentas de terceiros.

Conteúdo

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)

fundo


Dado: sistema de informações de negócios de uma grande rede de distribuição (cerca de mil lojas de varejo), composta por muitos componentes e subsistemas. Dentro de cada loja, há um servidor principal - um banco de dados Oracle com a principal lógica de negócios. Os nós de caixa são gerenciados por software separado do banco de dados local. Este software coleta periodicamente dados do servidor principal (via WS SOAP) e devolve os resultados da venda (troca de arquivos).

O progresso não parou e novos equipamentos apareceram nas lojas. Os dados deste equipamento devem ser enviados periodicamente ao servidor principal da loja (período - a cada poucos minutos), a integração deve necessariamente passar pelo serviço da web, a mensagem deve ter um determinado formato, a autenticação não é necessária. Analisamos os contratos de troca de dados e descobrimos que a tecnologia usada dos serviços da Web não permitirá a integração com esses equipamentos. E a busca por uma solução começou ...

Como resultado, foram consideradas várias opções para implementar o serviço da Web necessário, até escrever um componente separado que abriria uma janela para o banco de dados Oracle para o banco de dados Oracle: por um lado, forneceria um serviço da Web, por outro, interagiria com o banco de dados via JDBC. A dificuldade é que o novo componente, em primeiro lugar, teria que ser instalado em mil lojas e, em segundo lugar, teria surgido outro link que teria que ser acompanhado. Portanto, a prioridade ainda era a opção de implementar um serviço da Web com as ferramentas integradas da Oracle.

Como resultado das pesquisas, encontramos quatro maneiras que consideraremos neste artigo:

  1. Serviços da Web Oracle DB DB nativos
  2. Serviço de Dados REST Oracle
  3. Servlet Java
  4. Descritor de acesso ao banco de dados (servlet PL / SQL)

As duas primeiras opções serão consideradas em mais detalhes. O Oracle XML DB Web Services nativo foi usado em nosso sistema inicialmente, ou seja, foi herdado, por assim dizer. O ORDS se tornou um substituto para essa tecnologia desatualizada (apesar de eu ainda ter que trabalhar duro e instalar o ORDS em mil lojas).

Dois outros métodos - Java Servlet e PL / SQL Servlet - foram considerados junto com o ORDS ao procurar uma alternativa ao Native Oracle WS, mas não o usamos no projeto. Portanto, não consideraremos essas abordagens em detalhes e nos limitaremos a uma breve referência.

O artigo apresentará alguns exemplos práticos de implementação de serviços da Web com instruções que ajudarão a criar um serviço em funcionamento.

Serviços da Web Oracle DB DB nativos


Recursos


Permite organizar o acesso ao banco de dados Oracle via HTTP usando o WS SOAP (versão 1.1):

  • SQL- XQuery- SOAP.
  • ( ).



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



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

Vale ressaltar que a autenticação é necessária para todas as solicitações ao serviço da Web (da documentação : Autenticação básica: o Oracle XML DB suporta autenticação básica, em que um cliente envia o nome do usuário e a senha em texto não criptografado no cabeçalho da autorização). No Oracle, você pode configurar o acesso anônimo aos recursos do servidor via HTTP - usando a configuração do Oracle XML DB Protocol Server , mas, na verdade, funciona apenas para solicitações GET, e a autenticação é necessária para solicitações POST. Como o Oracle WS nativo funciona apenas com solicitações POST, não há como configurar o acesso anônimo para esta tecnologia.

Costumização


Para usar o Oracle WS nativo, você precisará de:

  1. Configure o servidor HTTP interno no Oracle.
  2. Configure o acesso dentro do banco de dados Oracle (abra a porta HTTP).
  3. Crie um servlet.
  4. Configure a ACL (lista de acesso).

Configurar o servidor HTTP do Oracle XML DB


O servidor HTTP já deve funcionar por padrão, mas em alguns casos pode ser necessária uma configuração adicional do ouvinte - adicionando o seguinte bloco ao DESCRIPTION_LIST:

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

Depois disso, você precisa reiniciar o ouvinte.

Configurar acesso HTTP


  1. Verificando a porta atual quanto a HTTP.

    SELECT dbms_xdb.gethttpport() AS http_port FROM dual;

    Um valor "0" significa que o acesso HTTP está desativado.
  2. Configuração de porta.

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

Criando um servlet para um serviço da web


Para que o serviço da Web funcione, é necessário o registro do servlet na configuração do banco de dados.

Script para criar um 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 acesso


Para acessar o Oracle por HTTP, você precisa adicionar regras na configuração do DBMS. Isso é feito usando os utilitários internos do DBMS.

Para configurar a ACL, você precisará de:

  • script editando a configuração do banco de dados (abaixo);
  • esquema do banco de dados para o qual a configuração é feita.

Ou seja, o esquema do banco de dados para o qual a ACL está sendo configurada já deve ser criado. Nos exemplos abaixo, haverá referências a esta seção, nos locais em que você precisará criar novos esquemas de banco de dados - para eles, será necessário configurar a ACL.

No esquema SYS, executamos o script de configuração da 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;
/

Deve-se notar imediatamente que a configuração da ACL é necessária ao usar não apenas o Oracle WS nativo, mas também todos os outros métodos de criação de serviços da web discutidos neste artigo.

Exemplo de serviço da Web usando um procedimento em lote


Nós vamos precisar:

  • O esquema do banco de dados no qual os objetos para processamento de solicitações de serviço da web serão localizados.
  • Tabela para registro.
  • Pacote com procedimento / função.
  • Qualquer ferramenta que permita enviar solicitações da web. Nesse caso, o aplicativo SOAP UI foi usado , mas você pode escolher qualquer outra ferramenta, até a linha de comando.

Recursos:

  • Os parâmetros do procedimento devem ter tipos simples ou de objeto. Caso contrário, o procedimento não será percebido como um método de serviço da web e não será incluído na lista de métodos de serviço.
  • Para implementar estruturas complexas de dados de entrada ou saída, você precisa usar tipos de objeto (os tipos de lote não podem ser usados).

Criamos os objetos de banco de dados necessários:

  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;

    Adicione imediatamente um novo esquema à ACL. O script na seção anterior.
  2. No novo esquema, crie uma tabela para log 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. Pacote com um procedimento simples:

    
    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;
    /

O serviço web mais simples é criado e pronto para ser usado.

Para acessar o serviço, você precisa usar o URL no seguinte formato:

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

Onde:

[servidor] - nome de domínio ou endereço IP do servidor de banco de dados Oracle
[porta] - porta para acesso via HTTP especificado na seção "Configurando o acesso via HTTP"
[servlet_name] - nome do servlet especificado na seção "Criando um servlet para a Web serviço ”
[DB_SCHEMA] - nome do esquema do banco de dados (em maiúsculas)
[WS_OBJ] - nome do serviço (em maiúsculas), que é igual ao nome do objeto de banco de dados, no nosso caso - o nome do pacote

Observe que o URL é importante!

Exemplo de link:

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

Se clicarmos neste link no navegador, seremos criados automaticamente com base em nosso pacote 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 testar o serviço, crie um novo projeto SOAP na interface do usuário SOAP. Como o URL, especifique o endereço do exemplo acima.

Após a abertura, Request 1vemos que o modelo de solicitação já é gerado automaticamente pelo WSDL especificado.

Adicione imediatamente a autorização básica para a solicitação - o login e a senha são os mesmos que ao conectar-se ao banco de dados.



Solicitação e resposta de exemplo. Observe que uma linha foi adicionada à solicitação gerada automaticamente <pk:O_RESULT-VARCHAR2-OUT/>. O fato é que há um erro no Oracle 12c: as variáveis ​​OUT não são adicionadas ao WSDL para o Oracle WS nativo).



O resultado da chamada é visível na tabela de log.



achados


A tecnologia nativa de serviços de banco de dados Oracle XML pode ser usada como uma solução industrial, desde que não haja carga pesada nesse serviço da web (uma solicitação em alguns segundos). Essa opção é adequada quando os consumidores não possuem requisitos estritos para um serviço da Web (seus atributos, estruturas de dados, lógica de processamento) e não há contrato estritamente predeterminado. Se você precisar criar um serviço da web de acordo com um WSDL predefinido (como no nosso caso com novos equipamentos), a tecnologia nativa do Oracle WS será inadequada.

Serviço de Dados REST Oracle


A partir da versão 11.1, a Oracle introduziu o suporte completo ao RESTful na forma de um módulo separado chamado Oracle REST Data Service (ORDS).

ORDS é um aplicativo Java que permite criar uma API RESTful para um banco de dados Oracle usando SQL e PL / SQL. É uma alternativa ao uso do Oracle HTTP Server e mod_plsql. Em essência, o ORDS é uma interface HTTP entre o mundo externo e um banco de dados Oracle. Essa interface permite fechar solicitações HTTP recebidas para qualquer objeto de banco de dados - uma tabela ou procedimento PL / SQL.

Tudo o que precisa ser feito é instalar, configurar e executar o ORDS para o banco de dados necessário. O processo adicional de criação de serviços REST se resume à gravação de código em PL / SQL (ou mesmo clicando no IDE se o código estiver com preguiça de gravar).

Nenhuma licença adicional é necessária para instalar o ORDS.

Requisitos:

  • Java JDK 8 ou superior;
  • Oracle 11.1 ou posterior (o Oracle 11 XE Release 2 também é suportado).

Várias opções de implantação do ORDS são suportadas:

  • modo autônomo;
  • no servidor de aplicativos (Oracle WebLogic Server, Apache Tomcat).

Recursos


O ORDS permite:

  • Organize o acesso aos recursos em um estilo RESTful.
  • Crie uma interação no estilo de "Chamada de procedimento remoto" (interação no estilo RPC).

Simplificando, com a ajuda do ORDS, você pode abrir o acesso via HTTP a certos objetos de banco de dados - tabelas, procedimentos, funções, pacotes.

No primeiro caso, estamos lidando com recursos no sentido de que eles são entendidos no estilo de arquitetura RESTful. Cada recurso é definido por um URI exclusivo, e as operações com recursos (CRUD - criar, ler, modificar, excluir) são determinadas pelas operações da solicitação HTTP: PUT, POST, GET, DELETE. Por exemplo, se o recurso for uma entrada na tabela de funcionários, essa entrada estará disponível por um URI do formulário:

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

Aqui, o nome do esquema do banco de dados, o nome da tabela e o ID do registro na tabela são indicados no URI. Portanto, essa solicitação HTTP realmente executa uma operação SELECT da tabela especificada. Com outras operações (adição, alteração, exclusão), o princípio da comunicação é o mesmo: o caminho para o recurso é indicado no URI e parâmetros adicionais são indicados no corpo da solicitação, por exemplo, os valores de campo para inserir o registro na tabela.

No segundo caso, em vez de acessar o recurso, uma chamada de procedimento é usada diretamente, o que pode fazer o mesmo que no primeiro caso (CRUD), além de executar qualquer outra lógica que implemente o processo de negócios necessário. Uma chamada de procedimento de um pacote pode ser feita usando uma solicitação HTTP deste formato:

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

Os parâmetros para o procedimento são transferidos no corpo da solicitação na forma de estruturas no formato JSON {"param" : "value"}. A mesma abordagem é usada ao usar o WS Oracle nativo, discutido acima, mas no caso de serviços REST, não há restrições impostas pelo protocolo SOAP.

profissionais

  • Um mecanismo flexível que permite implementar serviços da web de qualquer complexidade.
  • Simplicidade de implementação: para transformar um procedimento PL / SQL em um serviço da web, você precisa executar apenas alguns comandos típicos. E, usando o SQL Developer, a criação de uma API REST se transforma em um clique do mouse com o mínimo de código escrito.
  • A capacidade de implementar um serviço da web sem autenticação.

Menos

  • O ORDS não está incluído no pacote padrão do Oracle - ele deve ser instalado separadamente para cada servidor (licenças adicionais, como já mencionadas, não são necessárias). Isso pode ser um problema se você tiver milhares de servidores de banco de dados.

Costumização


O ORDS pode ser iniciado de dois modos: por meio do servidor de aplicativos ou no modo independente.

Este artigo descreve apenas a opção para executar no modo autônomo.

Para que o ORDS funcione, você precisa:

  1. Defina as configurações antes da instalação.
  2. Conclua a instalação do ODRS.
  3. Inicie o ORDS.
  4. Configure a ACL (para o esquema de banco de dados desejado).

Definições


A distribuição ORDS possui um arquivo com parâmetros parecidos com este por padrão:

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

Uma descrição dos parâmetros pode ser encontrada na documentação

Parâmetros para o modo autônomo:
ParâmetroDescrição
db.hostnameNome ou endereço IP do Oracle Database Server
db.portPorta do banco de dados (por exemplo, 1521)
db.servicenameBanco de dados de nome de serviço
db.usernameO nome de usuário do gateway PL / SQL. Padrão = APEX_PUBLIC_USER, mas o exemplo não planeja usar o APEX, portanto, você pode deixar esse parâmetro em branco
db.passwordSenha do usuário (também não preencha)
migrate.apex.restTransição de serviços RESTful APEX para ORDS. Defina como false se o APEX não for usado.
rest.services.apex.addConfigure o ORDS para uso no APEX
rest.services.ords.addDefina o esquema do banco de dados para ORDS (ORDS_PUBLIC_USER e ORDS_METADATA). O valor deve ser verdadeiro
schema.tablespace.defaultEspaço de tabela padrão para o esquema ORDS_METADATA
schema.tablespace.tempEspaço de tabela temporário para o esquema ORDS_METADATA
standalone.http.portA porta na qual o ORDS será executado. Essa porta será usada no URI para acessar o WS.
user.tablespace.defaultEspaço de tabela padrão para o esquema ORDS_PUBLIC_USER
user.tablespace.tempEspaço de tabela temporário para o esquema ORDS_PUBLIC_USER
Como resultado, o conteúdo do arquivo deve se parecer com isso:

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

As configurações necessárias estão concluídas, você pode prosseguir com a instalação.

Instalação


Executamos o comando no sistema operacional:

java -jar ords.war

Por padrão, o arquivo de configuração é obtido no diretório paramslocalizado ao lado de ords.war. Você pode especificar explicitamente o caminho para este arquivo usando o parâmetro --parameterFile:

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

Na caixa de diálogo de instalação, faça o seguinte:

  1. Indicamos o caminho para o diretório para salvar a configuração (no exemplo, é indicado conf - como resultado, no mesmo diretório em que o arquivo está localizado ords.war, será criado um diretório confno qual os arquivos com a configuração ORDS serão criados).
  2. Após o comando Digitar a senha do banco de dados para ORDS_PUBLIC_USER, inseriremos a senha do esquema ORDS_PUBLIC_USER. Sob esse usuário, o ORDS se conectará ao banco de dados.
  3. Após o prompt Digite 1 se você deseja usar o PL / SQL Gateway ou 2 para pular esta etapa, responderemos “2”, pois não usaremos o APEX e não precisamos migrar mod_plsql.
  4. Após a instrução Digite 1 se você deseja iniciar no modo autônomo ou 2 para sair [1] aparecer, nós respondemos “1”.
  5. Após a instrução Digite 1 se estiver usando HTTP ou 2 se estiver usando HTTPS [1], responderemos 1.

Diálogo de instalação
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, um diretório com a configuração do ORDS será criado e os esquemas de utilidade para o ORDS aparecerão no banco de dados.

Vejo também: Instale o Oracle REST Data Services 3.0.X em menos de 5 minutos .

Lançamento


O início no modo independente é realizado pelo comando:

java -jar ords.war standalone

Iniciar caixa de 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

Depois disso, o ORDS está em funcionamento. O endereço do serviço da web será http: // <hostname>: / ords / ..., em que <hostname> é o nome do computador que está executando o ORDS (ele não precisa corresponder ao nome do servidor de banco de dados, ou seja, o ORDS pode ser executado em outro host ), <port> - a porta especificada na configuração do ORDS.

Se desejar, você pode criar um script para executar automaticamente o ORDS quando o sistema operacional for iniciado.

Configuração de acesso


E o último passo é configurar a ACL. As etapas são as mesmas que o uso do Oracle Oracle nativo.

Você deve concluir esta etapa após a criação do esquema do banco de dados, para que os exemplos abaixo indiquem separadamente quando você precisa executar esta configuração. Até o momento, podemos assumir que todas as etapas preliminares foram concluídas e prosseguir com os exemplos.

Exemplo 1: Manipulador para uma solicitação POST


Como exemplo, considere a opção de implementação de interação no estilo RPC, ou seja, criaremos um método de serviço da Web, cujo manipulador será um procedimento em lote.

Na verdade, foi nessa versão que o trabalho com ORDS foi implementado em nosso projeto para a rede de distribuição, e o resultado atendeu às suas expectativas. Foi uma maneira rápida e universal de criar novos métodos de serviços da web para diferentes processos de negócios - desde o trabalho com o equipamento até a API dos sites.

Como mencionado acima, o suporte ao ORDS também está incluído no SQL Developer (o IDE do banco de dados desenvolvido pela Oracle). No SQL Developer, a criação de serviços da Web está disponível diretamente nos itens de menu ou no menu de contexto.

Neste artigo, exemplos são feitos usando o SQL Developer (versão 18), mas o código PL / SQL que é executado no banco de dados como resultado de ações no IDE também está incluído.

A versão do banco de dados no qual as experiências foram feitas:

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

Criando um usuário de teste para WS


Por exemplo, precisamos novamente de um novo esquema - crie-o:

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

Configurando um Esquema de Banco de Dados


Após a criação do diagrama, é necessário torná-lo acessível através do ORDS.

Por esta:

  1. No SQL Developer, crie uma conexão para WS_TEST.
  2. Na lista de conexões, chame o menu de contexto para a nova conexão. Escolha Serviços REST → Ativar Serviços REST ... :


  3. Na caixa de diálogo, marque a caixa ao lado de Habilitar esquema (você também pode alterar o parâmetro " Schema alias " aqui se desejar que ws_testoutro texto seja exibido no URI em vez do nome do esquema ):


  4. Ao clicar em "Avançar" , veremos o código PL / SQL que será executado no banco de dados (e você pode escrever sozinho sem usar o IDE):



Listagem:

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;
/

Criando um módulo e modelo


Em seguida, você precisa criar um módulo e modelo para o recurso.

Um módulo é uma unidade estrutural que permite agrupar vários modelos de recursos relacionados à lógica.

Um modelo é um serviço da web específico que atende a um conjunto específico de métodos para um recurso.

Na fonte :

Módulo de recursos: uma unidade organizacional usada para agrupar modelos de recursos relacionados.

Modelo de recurso: um serviço RESTful individual capaz de atender a solicitações de algum conjunto de URIs (Universal Resource Identifiers). O conjunto de URIs é definido pelo padrão de URI do modelo de recursos.


Por exemplo, para uma loja online, um módulo pode ser chamadoshop - neste módulo, todas as APIs da loja serão combinadas. Os modelos podem ser recursos específicos, por exemplo, um pedido (modelo order), catálogo de produtos (modelo item), pagamento (modelo payment) etc.

Para criar um módulo e um modelo, é necessário executar as seguintes etapas:

  1. Na árvore de objetos, abra a seção Serviços de Dados REST, chame o menu de contexto na seção Módulos , selecione Novo módulo ... :


  2. Na caixa de diálogo de criação do módulo, especifique o nome do módulo ( shop), prefixo URI (também especificamos shop - no exemplo abaixo, veremos imediatamente qual será o modelo de endereço de serviço da web), coloque um daw na frente do Publish , clique em "Next>" :


  3. Na próxima caixa de diálogo, especifique o nome do modelo, por exemplo order, e clique novamente em "Avançar>" .

    Na última caixa de diálogo, vemos todos os parâmetros inseridos do módulo e modelo. Na guia SQL , você pode ver o código PL / SQL que será executado no banco de dados quando você clicar em Concluir :



Para criar um módulo shop , você pode adicionar mais padrões - também na árvore de objetos, o menu de contexto e selecionando o Adicionar o modelo ... .

Listagem de código para criar um módulo e um modelo
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;
/

Criando um manipulador de solicitações HTTP


Agora precisamos criar um manipulador de solicitações HTTP para o nosso serviço.

Primeiro, precisamos criar objetos de banco de dados que conterão a lógica de processamento de solicitações.

Precisamos de uma tabela para registro e um pacote no qual haverá um código manipulador.

Crie uma tabela usando um 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;

Crie um pacote:
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;
/

Agora, para o modelo criado, você precisa adicionar um manipulador. Adicione um manipulador para o método HTTP POST.

Para fazer isso, execute as seguintes etapas:

  1. Chamamos o menu de contexto para o modelo, selecione Adicionar manipulador e, em seguida, selecione o 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;

    Se necessário, você pode obter o código PL / SQL para criar um manipulador. Para fazer isso, no menu de contexto do módulo ORDS, selecione Definição REST e especifique onde produzir o script de criação do módulo, por exemplo, para a área de transferência:


O código resultante para criar o 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: se você executar o procedimento de criação do módulo ORDS.DEFINE_MODULEnovamente, todos os modelos deste módulo serão excluídos automaticamente e não haverá aviso sobre isso!

Exemplo de chamada


É aqui que nosso serviço da web está pronto. Resta verificar seu trabalho.

Para verificar, executamos a solicitação:

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

Em resposta, obtemos:

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

O resultado da execução do método é um registro com o corpo da solicitação e resposta na tabela de log:



Como você pode ver, a solicitação HTTP enviada foi processada com êxito pelo procedimento do pacote.

Parâmetros da solicitação


Acima, já vimos o resultado de um simples serviço da web. Agora vamos complicar um pouco a tarefa adicionando parâmetros adicionais à solicitação.

Há duas maneiras de passar parâmetros:

Via URL. Os parâmetros são definidos no URL no formato padrão:

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

Via HEADER. Os parâmetros são definidos no cabeçalho da solicitação como p1: val1

No ORDS no manipulador de solicitações, os parâmetros são definidos como variáveis ​​de ligação.

Adicionamos dois parâmetros ao exemplo anterior: prm1- parâmetro no URI, prm2- parâmetro no cabeçalho da solicitação.

Para processar esses parâmetros, PK_ORDS_API.process_request:adicionamos o procedimento, adicionamos os parâmetros a_prm_urie a_prm_hdr, aos quais os valores de nossos parâmetros da solicitação virão.

Procedimento do manipulador de solicitação com novos 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 do procedimento, simplesmente registramos os valores dos novos parâmetros no log.

Adicione novos parâmetros ao manipulador de solicitações POST - na forma de variáveis ​​de ligação :prm_urie :prm_hdr.

Manipulador da solicitação POST com novos 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;

No manipulador, na guia Parâmetros , declare as variáveis:


Nesse formulário, o primeiro campo ( Nome ) contém o nome do parâmetro esperado na solicitação, o segundo campo ( Parâmetro de Ligação ) - o nome da variável de ligação que será especificada no manipulador dessa solicitação.

Vamos executar a solicitação com novos parâmetros:



Resultado - os parâmetros da solicitação foram salvos no log:


Observe que os parâmetros do URI também podem ser recuperados da variável CGI QUERY_STRING, ou seja, para obter os parâmetros, não é necessário iniciar as variáveis ​​de ligação - você pode analisá-las no próprio procedimento do manipulador solicitação.

Variáveis ​​CGI


Ao trabalhar com HTTP no Oracle, é possível obter os valores das variáveis ​​de ambiente que refletem o contexto da solicitação HTTP. Você pode obter os valores das variáveis, utilizando o procedimento OWA_UTIL.get_cgi_env.

Lista de variáveis ​​CGI disponíveis no 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 também: Cabeçalhos HTTP (OWA_UTIL) e variáveis ​​de ligação específicas do ORDS

Exemplo 2: Acessando uma Tabela Através do ORDS


Neste exemplo, consideramos a organização do acesso a um objeto de banco de dados (a uma tabela) por meio do ORDS.

Como no exemplo anterior, fazemos acesso sem autorização. Veja como tornar o acesso seguro aos recursos na documentação .

Para tornar um objeto de banco de dados acessível por meio do ORDS, você precisa executar apenas uma etapa - o comando ORDS.ENABLE_OBJECT. Depois disso, o objeto pode ser acessado por um URI do formulário:

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

Crie um padrão de teste


Por exemplo, criaremos a tabela "Pedidos".

Script de criação da tabela:

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;

Abrindo acesso à tabela através do ORDS


  1. Em SQL Developer invocar o menu de contexto para a mesa necessário, selecione o Habilitar o serviço REST ... .



  2. Na janela de configurações de acesso, marque a caixa de seleção Ativar objeto , desmarque a caixa de seleção Autorização necessária , clique em "Concluir" (ou "Avançar" para ver o código PL / SQL recebido):



  3. Depois de executar estas etapas, a tabela T_ORDERfica disponível através de HTTP, o URI base para acessar o recurso:

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

    Listagem de inclusão de tabela:

    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;
    /


Crie ou edite um registro


O acesso à tabela está aberto - verificamos como você pode criar e editar registros na tabela através do ORDS.

Para criar um registro, executamos a solicitação PUT.

Na documentação do ORDS, a seguinte descrição PUTé especificada na descrição do método :

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

Ou seja, o campo KeyValues(chave do registro) deve ser preenchido mesmo para um registro recém-criado. A consulta em si deve listar todos os campos da tabela (mas o campo chave pode ser omitido).

Inquérito
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"
}

Em resposta, obtemos todos os campos do registro recém-criado:

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/"
      }
   ]
}

Examinamos o conteúdo da tabela - nosso novo registro apareceu:



Para alterar o registro, chamamos o mesmo método PUT. Altere a nota em nossa ordem:

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.  "
}

Na resposta, obtemos o mesmo JSON com os parâmetros do registro modificado. Na tabela, vemos que a nota foi atualizada:



Recuperando Registros de uma Tabela


Existem três modos de consultar dados de uma tabela:

  1. Solicitação de página:

    GET http://<HOST>:<PORT>/ords/<SchemaAlias>/<ObjectAlias>/?offset=<Offset>&limit=<Limit>
  2. Pedido de condições:

     GET http://<HOST>:<PORT>/ords/<SchemaAlias>/<ObjectAlias>/?q=<FilterClause>
  3. Solicitação de chave primária:

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

Para obter todos os registros, você pode executar a consulta sem especificar nenhum parâmetro:

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

Responda
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/"
      }
   ]
}

Como fazer com que o Oracle adicione uma codificação ao cabeçalho Content-Type é uma questão em aberto.

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

Responda
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/"
      }
   ]
}

Apagar registro


Para excluir, use o método HTTP DELETE.

Inquérito:

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

O pedido em sua forma original:

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

Responda:

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

achados


O ORDS é um mecanismo bastante flexível e versátil para trabalhar com serviços da Web, que permite implementar o REST completo. Em termos de desempenho, é muito superior ao Native Oracle WS, com sua pesada análise interna de XML. Para implementar um sistema altamente carregado, essa abordagem não é adequada: nesse caso, é necessária uma pilha de tecnologia diferente - um servidor de aplicativos separado, solicitações de proxy, uso de bancos de dados em cluster e assim por diante. No entanto, para a implementação de sistemas com um número relativamente pequeno de solicitações HTTP (até 10 a 20 por segundo), o ORDS é a abordagem ideal em desempenho e flexibilidade. O ORDS é inferior ao Oracle WS nativo apenas em termos de geração de uma especificação de serviço da Web: o último fornece uma especificação totalmente concluída (WSDL) que pode ser fornecida "como está" para os consumidores do serviço. ORDS também tem a capacidadegerando uma descrição, mas para a abordagem considerada neste artigo com um serviço totalmente universal (quando há um procedimento de processamento comum para todos os serviços), a geração automática da especificação se torna impossível. O Oracle gerará apenas uma especificação de nível superior e as partes (modelos de dados) deverão ser descritas manualmente.

Abordagens alternativas


Servlet Java


Essa opção para criar serviços da Web no método de configuração é semelhante ao Oracle WS nativo: também requer o uso do servidor HTTP interno do Oracle, bem como configurações da ACL (como, de fato, todos os outros métodos). Mas, diferentemente do Native Oracle WS, essa opção funciona com HTTP puro. Manipuladores de solicitação, neste caso, são escritos em Java e olhar apenas para o tipo HTTP-request ( PUT, GET, POSTe assim por diante, embora possa ser feito e uma rotina de tratamento para todos os tipos), e lógica de processamento permanece completamente a critério do desenvolvedor. Você pode transferir o corpo da solicitação “como está” para a lógica do banco de dados, desmontá-lo e processá-lo lá, pode deixar parte da lógica ao lado do manipulador Java e chamar o procedimento desejado a partir do banco de dados, dependendo dos dados que vieram na solicitação.

Essa abordagem para a implementação de serviços da Web é bastante universal e também não requer a instalação de nenhum componente adicional. Não conseguimos aplicá-lo apenas devido aos requisitos estritos do serviço: precisávamos de um serviço da web que não exigisse autenticação. Ao implementar essa abordagem, a autenticação é necessária e esse requisito não pode ser contornado.

Consulte a documentação do Oracle para obter mais detalhes sobre esse método .

Descritor de acesso ao banco de dados (servlet PL / SQL)


Esta opção é completamente semelhante à anterior, apenas o procedimento armazenado PL / SQL atua como o manipulador de solicitações.

URL de exemplo - o nome do pacote, o nome do procedimento, os parâmetros (solicitação GET) são indicados:

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

No caso de uma solicitação POST, os nomes dos parâmetros devem ser inseridos diretamente no corpo da solicitação através do sinal “=”, o que é bastante inconveniente, pois o tipo de conteúdo da solicitação (ContentType) nesse caso pode ser apenas texto. Você pode transferir uma estrutura xml ou json apenas neste formulário:

p_proc_param_name=<xml_data>…</xml_data>

Esta versão do serviço da web é aplicável apenas nos casos em que estamos lidando com solicitações muito simples - o procedimento chama com tipos de dados simples. Transmitir qualquer estrutura multinível complexa nesta opção não funcionará.

Essa abordagem é descrita em detalhes no site da ORACLE-BASE.

Conclusão


Criar um serviço da Web no Oracle é uma tarefa bastante simples que não requer a escrita de nenhum tipo de código super complexo. Ao mesmo tempo, os desenvolvedores da Oracle entram em seu arsenal um mecanismo bastante poderoso que permite integrar sistemas heterogêneos ou partes de sistemas por meio de HTTP.

Neste artigo, examinamos quatro abordagens para a criação de serviços da web.

O Oracle WS nativo é uma tecnologia desatualizada que tem suas vantagens: WSDL gerado automaticamente, análise automática de XML, sem necessidade de instalar software adicional. A principal desvantagem é o baixo desempenho e a limitação dos tipos de dados suportados.

ORDS- na minha opinião, a maneira preferida de criar serviços da web. Flexível o suficiente e versátil. Das inconveniências desse método, podemos apenas distinguir que ele não está incluído no pacote padrão do Oracle, ou seja, requer uma instalação separada.

O Java Servlet é uma maneira completamente universal que não requer a instalação de software adicional. No entanto, tudo precisa ser feito completamente manualmente, pois não há possibilidade de geração automática de serviços.

O servlet PL / SQL é a abordagem menos bem-sucedida. Das vantagens, podemos distinguir que nesta opção temos a capacidade de chamar procedimentos armazenados via HTTP sem a necessidade de instalar software adicional ou sem escrever código adicional em outros idiomas: todo o código é escrito apenas em PL / SQL.

Obrigado a todos pela atenção! Espero que o material do artigo seja útil para aqueles que estão de alguma forma conectados aos produtos Oracle e esteja intrigado com os problemas de integração intra-sistema e intersistema.


All Articles