【问题标题】:Encoding a PDF to Base64 in Java, decoding in PL/SQL: doesn't work在 Java 中将 PDF 编码为 Base64,在 PL/SQL 中解码:不起作用
【发布时间】:2014-04-18 14:05:38
【问题描述】:

所以,我正在开发一个 Web 服务项目。

基本上可以归结为:

  1. PL/SQL 端上传一个 PDF 文件,然后对该文件进行 Base64 编码,然后将其发送到我的 REST Web 服务。
  2. Java web 服务接收文件。我在做任何其他事情之前保存了这个文件(只是为了测试):正如预期的那样,文件已损坏(它是一个 Base64 字符串,这是正常的)。
  3. Java Web 服务 Base64 解码文件,然后继续执行它需要对文件执行的任何操作。解码后我再次保存文件,它再次按预期工作,我能够打开和阅读 PDF。
  4. PL/SQL 现在请求重新下载文件。我重新编码文件并将其发送回请求者。我在编码后保存了文件,正如预期的那样(它再次被 Base64 编码):它不起作用(损坏)。
  5. PL/SQL 接收到文件,Base64 解码文件并尝试打开它...糟糕,损坏,无法读取文件。

通信之间可能有问题:它在 Java 中是 Base64 编码的,在 PL/SQL 中是 Base64 解码的。您会怀疑它使用标准没有区别(我猜 Base64 是标准的,对吧?)。

我们尝试了两种选择:在我用 Java 重新编码 PDF 之后,我尝试再次重新解码并保存它;这个文件是正确的,我可以阅读 PDF。所以我们假设Java中的编码是正确的。我们还在 PL/SQL 中进行了尝试——上传一个 BLOB,编码为 Base64,解码回来,下载并打开。这也有效。所以我们假设 PL/SQL 中的编码和解码部分也可以工作。

奇怪的是,我可以在 PL/SQL 中对文件进行 Base64 编码,然后在 Java 中对其进行解码,然后保存并读取它。只有当我在 Java 中重新编码文件并尝试在 PL/SQL 中对其进行解码时,它才会出错。所以在我看来,PL/SQL - Java 中使用的标准之间真的没有问题,因为那样第一步也会失败。

我们正在使用 Java 中的公共库 (org.apache.commons.codec.binary.Base64)。在 PL/SQL 中,我们尝试使用 UTL 包以及自定义方法以及 Java 存储过程以及 Apex_webservice(apex_web_service.blob2clobbase64(p_blob)apex_web_service.clobbase642blob(p_clob))。它们都给出相同的结果。

我们的想法正在慢慢枯竭。有没有人有另一个更好的主意?

谢谢!

--- 编辑 ---

这是文件在 PL/SQL 中的解码方式:

FUNCTION encode_base64 (p_blob_in IN BLOB) 
    RETURN CLOB IS
        v_clob             CLOB;
        v_result           CLOB;
        v_offset           INTEGER;
        v_chunk_size       BINARY_INTEGER := (48 / 4) * 3;
        v_buffer_varchar   VARCHAR2 (48);
        v_buffer_raw       RAW (48);
    BEGIN
        IF p_blob_in IS NULL THEN
            RETURN NULL;
        END IF;
        DBMS_LOB.createtemporary (v_clob, TRUE);
        v_offset := 1;
        FOR i IN 1 .. CEIL (DBMS_LOB.getlength (p_blob_in) / v_chunk_size) LOOP
            DBMS_LOB.read (p_blob_in, v_chunk_size, v_offset, v_buffer_raw);
            v_buffer_raw := UTL_ENCODE.base64_encode (v_buffer_raw);
            v_buffer_varchar := UTL_RAW.cast_to_varchar2 (v_buffer_raw);
            DBMS_LOB.writeappend (v_clob, LENGTH (v_buffer_varchar), v_buffer_varchar);
            v_offset := v_offset + v_chunk_size;
        END LOOP;
        v_result := v_clob;
        DBMS_LOB.freetemporary (v_clob);
        RETURN v_result;
END encode_base64;

这是文件在 Java 中的编码方式:

byte[] content = /*Here is my content in bytes. Before encoding, when I save, this is correct*/
Base64.encodeBase64String(content);

--- 编辑 2 ---

我不小心在上面的 PL/SQL 中添加了解码部分。这是 PL/SQL 中的编码部分。

function decode_base64(p_clob_in in clob) return blob is
    v_blob blob;
    v_result blob;
    v_offset integer;
    v_buffer_size binary_integer := 48;
    v_buffer_varchar varchar2(48);
    v_buffer_raw raw(48);
    begin
        if p_clob_in is null then
            return null;
        end if;
        dbms_lob.createtemporary(v_blob, true);
        v_offset := 1;
        for i in 1 .. ceil(dbms_lob.getlength(p_clob_in) / v_buffer_size) loop
            dbms_lob.read(p_clob_in, v_buffer_size, v_offset, v_buffer_varchar);
            v_buffer_raw := utl_raw.cast_to_raw(v_buffer_varchar);
            v_buffer_raw := utl_encode.base64_decode(v_buffer_raw);
            dbms_lob.writeappend(v_blob, utl_raw.length(v_buffer_raw), v_buffer_raw);
            v_offset := v_offset + v_buffer_size;
        end loop;
        v_result := v_blob;
        dbms_lob.freetemporary(v_blob);
        return v_result;
end decode_base64;

【问题讨论】:

  • 您确定在两端使用“相同”的 Base64 表示(特别是填充)吗?
  • 问题似乎来自PL/SQL中的解码部分。你能分享那些吗? (还有什么特殊原因导致您不使用二进制数据传输和 BLOB?)
  • @fge - 我们已经尝试过检查;我知道 Java 中的 commons 使用 76 作为块大小,而在 PL/SQL 中我们使用 48。据我所知,这应该没什么区别,对吧?
  • @VincentMalgrat,我添加了我在 Java 和 PL/SQL 中使用的代码。至于二进制数据传输 - 有一种公司规则,我们应该对其进行编码以保持“安全”。当在传输过程中不进行编码解码并且只发送纯字节时,它可以工作,但是“这还不够好”。
  • 这类问题大多来自小事……那到底发生了什么?我将 Base64-String 发送回 XML 中。在 PL/SQL 中,我们将该字符串提取到一个 clob 中,然后再将其解码回一个 blob。我们打印并检查了那个字符串……它是正确的。当我们试图检查我们从 PL/SQL 发送的 clob 与我们在 PL/SQL 中返回的 clob 之间的差异时,我们发现了一些 char(10) 和 char(13) - 基本上是换行符。肉眼看不到,但会使 clob(和解码的 blob)损坏。翻译功能可以解决这些问题,现在它可以作为一种魅力。

标签: java sql plsql base64 oracle-apex


【解决方案1】:

这类问题大多来自小事……

那么发生了什么?我将 Base64-String 发送回 XML 中。在 PL/SQL 中,我们将该字符串提取到一个 clob 中,然后再将其解码回一个 blob。

我们打印并检查了那个字符串……它是正确的。

当我们尝试检查我们从 PL/SQL 发送的 clob 与我们在 PL/SQL 中返回的 clob 之间的差异时,我们发现了一些 char(10) 和 char(13) - 本质上是换行符。肉眼看不到,但会使 clob(和解码的 blob)损坏。翻译功能可以解决这些问题,现在它可以作为一种魅力。

感谢大家的帮助!

【讨论】:

  • 因此您在 XML 中获取 base64 字符串,然后将其提取到 CLOB。可以直接提取到 BLOB 中吗?我怀疑 CLOB 可能“有用”地将它认为是行尾字符从 Unix 转换为 DOS 样式,反之亦然。只是一个想法。分享和享受。
  • 问题是我们需要在从 XML 中提取 CLOB 后立即对其进行 Base64 解码(返回 BLOB)。解码函数假定 IN 参数为 CLOB,OUT 参数为 BLOB。所以在我看来这将是一种变通方法(我承认,现在的翻译也是一种变通方法)
  • 举个例子?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-13
  • 2012-10-18
  • 2018-03-19
相关资源
最近更新 更多