【问题标题】:Access Web service from Oracle stored procedure从 Oracle 存储过程访问 Web 服务
【发布时间】:2010-09-22 21:01:58
【问题描述】:

是否有人从 Oracle 存储过程中成功访问了 Web 服务?如果是这样,它是 Java 存储过程吗? PL/SQL 存储过程?

我有什么理由不应该尝试从存储过程中访问 WS?

这是我目前找到的几个参考文献

..澄清一下,这是针对 SOAP 调用的

【问题讨论】:

    标签: java oracle web-services stored-procedures plsql


    【解决方案1】:

    将 UTL_HTTP 包装在一个便利函数中相当简单:

    FUNCTION post
    (
        p_url     IN VARCHAR2,
        p_data    IN CLOB,
        p_timeout IN BINARY_INTEGER DEFAULT 60
    ) 
        RETURN CLOB
    IS
        --
        v_request  utl_http.req;
        v_response utl_http.resp;
        v_buffer   CLOB;
        v_chunk    VARCHAR2(4000);
        v_length   NUMBER;
        v_index    NUMBER;
    BEGIN
    
        v_index := 1;
        v_length := nvl(length(p_data), 0);
    
        -- configure HTTP
        utl_http.set_response_error_check(enable => FALSE);
        utl_http.set_detailed_excp_support(enable => FALSE);
        utl_http.set_transfer_timeout(p_timeout);
    
        -- send request
        v_request := utl_http.begin_request(p_url, 'POST','HTTP/1.0');
        utl_http.set_header(v_request, 'Content-Type', 'text/xml');
        utl_http.set_header(v_request, 'Content-Length', v_length);
        WHILE v_index <= v_length LOOP
            utl_http.write_text(v_request, substr(p_data, v_index, 4000));
            v_index := v_index + 4000;
        END LOOP;
    
        -- check HTTP status code for error
        IF v_response.status_code <> utl_http.http_ok THEN   
            raise_application_error(
                cn_http_error,
                v_response.status_code || ' - ' || v_response.reason_phrase
            );
        END IF;
    
        -- get response
        dbms_lob.createtemporary(v_buffer, FALSE);
        v_response := utl_http.get_response(v_request);
        BEGIN
            LOOP
                utl_http.read_text(v_response, v_chunk, 4000);
                dbms_lob.writeappend(v_buffer, length(v_chunk), v_chunk);
            END LOOP;
        EXCEPTION
            WHEN utl_http.end_of_body THEN NULL;
        END;
        utl_http.end_response(v_response);
    
        RETURN v_buffer;
    
    END;
    

    那么你只需要一些东西来 POST 一个 SOAP 信封:

    FUNCTION invoke
    (
        p_url IN VARCHAR2,
        p_method IN XMLTYPE,
        p_timeout IN NUMBER := 60
    )
        RETURN XMLTYPE
    IS
        -- calls the given SOAP service
        cn_procedure_name CONSTANT VARCHAR2(30) := 'invoke';
        --
        v_envelope XMLTYPE;
        v_response CLOB;
        v_fault XMLTYPE;
        v_sqlerrm VARCHAR2(2000);
    BEGIN
    
        -- wrap method in SOAP envelope
        SELECT
            XMLElement(
                "soap:Envelope",
                XMLAttributes(
                    'http://schemas.xmlsoap.org/soap/envelope/' AS "xmlns:soap"
                ),
                XMLElement(
                    "soap:Body",
                    p_method
                )
            )
        INTO
            v_envelope
        FROM
            dual;
    
        -- POST request
        v_response := post(
            p_url,
            '<?xml version="1.0" encoding="ISO-8859-1"?>' || chr(10) || v_envelope.getClobVal(),
            p_timeout
        );
        IF v_response IS NULL THEN
            RAISE null_response;
        END IF;
    
        -- parse response
        BEGIN
            v_envelope := XMLType(v_response);
        EXCEPTION
            WHEN OTHERS THEN
                v_sqlerrm := SQLERRM;
                RAISE xml_parse_error;
        END;
    
        -- check for a fault
        v_fault := v_envelope.extract(  
            '/soap:Envelope/soap:Body/soap:Fault', 
            'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"'
        );
        IF v_fault IS NOT NULL THEN
            v_sqlerrm := v_fault.extract('.//faultstring/text()').getStringVal();
            RAISE soap_fault;
        END IF;
    
        -- the actual response is the child of the <soap:Body /> element
        RETURN v_envelope.extract(
            '/soap:Envelope/soap:Body/*[position() = 1]', 
            'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"'
        );
    
    END;
    

    请注意,我删除了我们的异常处理块,因为它与示例无关。

    这样,您可以让任何其他过程生成调用服务所需的 XML,通过调用传递它,并解析返回值。

    我们在 9i 数据库上开发了这个解决方案,所以我们还没有研究 UTL_DBWS。不过效果很好。

    【讨论】:

      【解决方案2】:

      首先,您调用的是哪种网络服务?我假设是 SOAP 或 REST。

      对于 REST Web 服务,UTL_HTTP 通常是绰绰有余,在一个简单的 PL/SQL 存储过程中结合一点 XPath。

      对于 SOAP Web 服务,这取决于您需要(或希望)变得多复杂。您当然可以使用 XQuery 创建一个符合 Web 服务规范的 XML 文档,使用 UTL_HTTP 发布文档并获取响应,然后使用一些 XPath 来解析所有 PL/SQL 中的响应。这是一个相对手动且相对蛮力的解决方案,但如果您谈论的是少数 Web 服务,它涉及最少的基础架构,并且调用可以很快地组合在一起。

      如果您希望调用会随着时间的推移而发展,或者您希望有许多过程调用许多 Web 服务,那么在诸如 UTL_DBWS 之类的东西上投入时间可能是有意义的(不过,这不是您通常会在几个小时内开始工作)。

      【讨论】:

      • 尽管我一点都不懂,我还是要投赞成票。
      • 不从存储过程调用服务的一个重要原因是可能会使短事务运行很长时间。谨慎使用!
      猜你喜欢
      • 1970-01-01
      • 2010-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-30
      • 2011-12-30
      相关资源
      最近更新 更多