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.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:- Serviços da Web Oracle DB DB nativos
- Serviço de Dados REST Oracle
- Servlet Java
- 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):- - : , 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:- Configure o servidor HTTP interno no Oracle.
- Configure o acesso dentro do banco de dados Oracle (abra a porta HTTP).
- Crie um servlet.
- 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
- 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. - Configuração de porta.
BEGIN
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
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 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:
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;
/
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:- 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. - 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 '/ ';
- 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 pacoteObserve 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 1
vemos 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:- Defina as configurações antes da instalação.
- Conclua a instalação do ODRS.
- Inicie o ORDS.
- 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çãoParâmetros para o modo autônomo: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 params
localizado 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:- 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 conf
no qual os arquivos com a configuração ORDS serão criados). - 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. - 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
. - 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”.
- Após a instrução Digite 1 se estiver usando HTTP ou 2 se estiver usando HTTPS [1], responderemos 1.
Diálogo de instalaçãoD:\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á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
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:- No SQL Developer, crie uma conexão para
WS_TEST
. - Na lista de conexões, chame o menu de contexto para a nova conexão. Escolha Serviços REST → Ativar Serviços REST ... :

- 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_test
outro texto seja exibido no URI em vez do nome do esquema ):

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

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

- 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 modeloBEGIN
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:- Chamamos o menu de contexto para o modelo, selecione Adicionar manipulador e, em seguida, selecione o 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;
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
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_MODULE
novamente, 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_uri
e 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â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 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_uri
e :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 / 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 também: Cabeçalhos HTTP (OWA_UTIL) e variáveis de ligação específicas do ORDSExemplo 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
- Em SQL Developer invocar o menu de contexto para a mesa necessário, selecione o Habilitar o serviço REST ... .

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

- Depois de executar estas etapas, a tabela
T_ORDER
fica 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éritoPUT 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:- Solicitação de página:
GET http://<HOST>:<PORT>/ords/<SchemaAlias>/<ObjectAlias>/?offset=<Offset>&limit=<Limit>
- Pedido de condições:
GET http://<HOST>:<PORT>/ords/<SchemaAlias>/<ObjectAlias>/?q=<FilterClause>
- 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/
RespondaHTTP/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
RespondaHTTP/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
, POST
e 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.