Explorar el Código

下载工具类

9060 hace 4 meses
padre
commit
b3ae1810fd

+ 13 - 1
properties/esign/esignConfig.properties

@@ -23,4 +23,16 @@ detail.sign_fields=/v3/sign-flow/{0}/detail
 #删除签署区
 del.sign_fields=/v3/sign-flow/{0}/signers/sign-fields
 #添加抄送方
-add.copiers=/v3/sign-flow/{0}/copiers
+add.copiers=/v3/sign-flow/{0}/copiers
+#删除抄送方
+del.copiers=/v3/sign-flow/{signFlowId}/copiers/delete
+#基于文件发起签署
+create_by_file=/v3/sign-flow/create-by-file
+#开启签署流程
+start_by_file=/v3/sign-flow/{0}/start
+#开启签署流程
+revoke_by_file=/v3/sign-flow/{0}/revoke
+#催签流程中签署人
+urge_by_file=/v3/sign-flow/{0}/urge
+#下载已签署文件及附属材料
+file_download_url=/v3/sign-flow/{0}/file-download-url

+ 6 - 0
src/com/kingdee/eas/custom/esign/tsign/hz/comm/EsignHttpResponse.java

@@ -1,4 +1,6 @@
 package com.kingdee.eas.custom.esign.tsign.hz.comm;
+
+
 /**
  * ÍøÂçÇëÇóµÄresponseÀà
  * @author  ³Îãü
@@ -9,6 +11,8 @@ public class EsignHttpResponse {
     private int status;
     private String body;
 
+
+
     public int getStatus() {
         return status;
     }
@@ -24,4 +28,6 @@ public class EsignHttpResponse {
     public void setBody(String body) {
         this.body = body;
     }
+
+
 }

+ 292 - 0
src/com/kingdee/eas/custom/esign/util/DownloaderUtil.java

@@ -0,0 +1,292 @@
+package com.kingdee.eas.custom.esign.util;
+
+import okhttp3.*;
+import org.apache.commons.io.IOUtils;
+
+import java.io.*;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 下载文件工具类
+ * description: Downloader <br>
+ * date: 18/11/2025 下午 4:25 <br>
+ * author: lhbj <br>
+ * version: 1.0 <br>
+ */
+public class DownloaderUtil {
+
+    /**
+     * 异步接口
+     */
+    public interface Listener {
+        void onSuccess(String data);
+        void onError(String error);
+    }
+    /**
+     * 异步接口
+     */
+    public interface CallbackBytes {
+        void onSuccess(byte[] bytes);
+        void onError(String error);
+    }
+    /**
+     * 异步
+     * 进度条监听类接口
+     */
+    public interface ProgressListener extends Listener{
+        void onProgress(int percentage, long downloaded, long total);
+    }
+    /**
+     * 异步下载
+     * 由于返回byte数组,使用时需要注意下载文件大小,不能过大,不能多线程调用,以规避内存风险。
+     * @param url
+     * @param callback 回调实现类
+     */
+    public static void downloadFileToByteArrayAsync(String url,
+                                                    final CallbackBytes callback) {
+        downloadFileToByteArrayAsync(url,null,callback);
+    }
+    /**
+     * 异步下载
+     * 由于返回byte数组,使用时需要注意下载文件大小,不能过大,不能多线程调用,以规避内存风险。
+     * @param url
+     * @param headers 请求头
+     * @param callback 回调实现类
+     */
+    public static void downloadFileToByteArrayAsync(String url,Map<String, String> headers,
+                                            final CallbackBytes callback) {
+        OkHttpClient client = new OkHttpClient();
+        Request request = new Request.Builder()
+                .url(url)
+                .build();
+
+        client.newCall(request).enqueue(new Callback() {
+            @Override
+            public void onFailure(Call call, IOException e) {
+                callback.onError(e.getMessage());
+            }
+
+            @Override
+            public void onResponse(Call call, Response response) throws IOException {
+                if (!response.isSuccessful()) {
+                    callback.onError("HTTP " + response.code());
+                    return;
+                }
+                InputStream inputStream = null;
+                try {
+
+                    ResponseBody body=response.body();
+                    long contentLength =body.contentLength();
+
+                    inputStream = body.byteStream();
+                    callback.onSuccess(IOUtils.toByteArray(inputStream));
+                } catch (Exception e) {
+                    callback.onError("文件保存失败: " + e.getMessage());
+                } finally {
+                    closeQuietly(inputStream);
+
+                    if (response != null) {
+                        response.close();
+                    }
+                }
+            }
+        });
+    }
+    /**
+     * 进度条下载
+     * @param url
+     * @param outputPath 保存下载文件地址
+     * @param listener 进度条监听类接口
+     */
+    public static void downloadWithProgress(String url, String outputPath,
+                                            final ProgressListener listener) {
+        downloadWithProgress(url,outputPath,null,listener);
+    }
+    public static void downloadWithProgress(String url, String outputPath,Map<String, String> headers,
+                                            final ProgressListener listener) {
+        OkHttpClient client = new OkHttpClient();
+        Request request = new Request.Builder()
+                .url(url)
+                .build();
+
+        client.newCall(request).enqueue(new Callback() {
+            @Override
+            public void onFailure(Call call, IOException e) {
+                listener.onError(e.getMessage());
+            }
+
+            @Override
+            public void onResponse(Call call, Response response) throws IOException {
+                if (!response.isSuccessful()) {
+                    listener.onError("HTTP " + response.code());
+                    return;
+                }
+
+                long contentLength = response.body().contentLength();
+                InputStream inputStream = null;
+                FileOutputStream outputStream = null;
+
+                try {
+                    inputStream = response.body().byteStream();
+                    File file = new File(outputPath);
+                    outputStream = new FileOutputStream(file);
+
+                    byte[] buffer = new byte[8192];
+                    int bytesRead;
+                    long totalBytesRead = 0;
+
+                    while ((bytesRead = inputStream.read(buffer)) != -1) {
+                        outputStream.write(buffer, 0, bytesRead);
+                        totalBytesRead += bytesRead;
+
+                        // 更新进度
+                        if (contentLength > 0) {
+                            int progress = (int) (totalBytesRead * 100 / contentLength);
+                            listener.onProgress(progress, totalBytesRead, contentLength);
+                        }
+                    }
+
+                    listener.onSuccess(file.getAbsolutePath());
+
+                } catch (Exception e) {
+                    listener.onError("文件保存失败: " + e.getMessage());
+                } finally {
+                    closeQuietly(inputStream);
+                    closeQuietly(outputStream);
+                    if (response != null) {
+                        response.close();
+                    }
+                }
+            }
+        });
+    }
+    /**
+     * 下载文件到byte数组
+     * 由于返回byte数组,使用时需要注意下载文件大小,不能过大,不能多线程调用,以规避内存风险。
+     * @param url
+     * @return
+     * @throws IOException
+     */
+    public static byte[] downloadFileToByteArray(String url) throws IOException {
+        return downloadFileToByteArray(url,null);
+    }
+    /**
+     * 携带header下载文件到byte数组
+     * 由于返回byte数组,使用时需要注意下载文件大小,不能过大,不能多线程调用,以规避内存风险。
+     * @param url
+     * @param headers 请求头
+     * @return
+     * @throws IOException
+     */
+    public static byte[] downloadFileToByteArray(String url, Map<String, String> headers) throws IOException {
+        OkHttpClient client = new OkHttpClient.Builder()
+                .connectTimeout(240, TimeUnit.SECONDS)
+                .readTimeout(240, TimeUnit.SECONDS)
+                .writeTimeout(240, TimeUnit.SECONDS)
+                .retryOnConnectionFailure(true)
+                .build();
+        Request.Builder requestBuilder = new Request.Builder().url(url);
+        // 添加自定义请求头
+        if (headers != null) {
+            for (Map.Entry<String, String> entry : headers.entrySet()) {
+                requestBuilder.addHeader(entry.getKey(), entry.getValue());
+            }
+        }
+        Request request = requestBuilder.build();
+        Response response = null;
+        InputStream inputStream = null;
+        try {
+            response = client.newCall(request).execute();
+            if (!response.isSuccessful()) {
+                throw new IOException("下载失败: " + response.code());
+            }
+            inputStream = response.body().byteStream();
+            return IOUtils.toByteArray(inputStream);
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw e;
+        } finally {
+            // 手动关闭资源
+            closeQuietly(inputStream);
+            if (response != null) {
+                response.close();
+            }
+        }
+    }
+
+    /**
+     * 文件下载方法
+     * @param url
+     * @param savePath 保存下载文件地址
+     * @param headers 请求头
+     * @return
+     */
+    public static boolean download(String url, String savePath,Map<String, String> headers) {
+        OkHttpClient client = new OkHttpClient.Builder()
+                .connectTimeout(240, TimeUnit.SECONDS)
+                .readTimeout(240, TimeUnit.SECONDS)
+                .writeTimeout(240, TimeUnit.SECONDS)
+                .retryOnConnectionFailure(true)
+                .build();
+        Request.Builder requestBuilder = new Request.Builder().url(url);
+        // 添加自定义请求头
+        if (headers != null) {
+            for (Map.Entry<String, String> entry : headers.entrySet()) {
+                requestBuilder.addHeader(entry.getKey(), entry.getValue());
+            }
+        }
+        Request request = requestBuilder.build();
+
+        Response response = null;
+        InputStream inputStream = null;
+        FileOutputStream outputStream = null;
+
+        try {
+            response = client.newCall(request).execute();
+            if (response.isSuccessful()) {
+                inputStream = response.body().byteStream();
+                outputStream = new FileOutputStream(new File(savePath));
+
+                byte[] buffer = new byte[4096];
+                int bytesRead;
+                while ((bytesRead = inputStream.read(buffer)) != -1) {
+                    outputStream.write(buffer, 0, bytesRead);
+                }
+                return true;
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            // 关闭资源
+            closeQuietly(inputStream);
+            closeQuietly(outputStream);
+            if (response != null) {
+                response.close();
+            }
+        }
+        return false;
+    }
+
+    private static void closeQuietly(InputStream is) {
+        if (is != null) {
+            try {
+                is.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+                // 静默关闭
+            }
+        }
+    }
+
+    private static void closeQuietly(OutputStream fos) {
+        if (fos != null) {
+            try {
+                fos.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+                // 静默关闭
+            }
+        }
+    }
+}

+ 127 - 0
src/com/kingdee/eas/custom/esign/util/EsignHttpUtil.java

@@ -1,5 +1,7 @@
 package com.kingdee.eas.custom.esign.util;
 
+import com.alibaba.fastjson.JSON;
+import com.google.common.collect.Maps;
 import com.kingdee.eas.custom.esign.tsign.hz.comm.EsignHttpHelper;
 import com.kingdee.eas.custom.esign.tsign.hz.comm.EsignHttpResponse;
 import com.kingdee.eas.custom.esign.tsign.hz.enums.EsignRequestType;
@@ -281,4 +283,129 @@ public class EsignHttpUtil {
         return POST(apiaddr, json);
     }
 
+    /**
+     * 删除抄送方信息
+     * 参考文档:https://open.esign.cn/doc/opendoc/pdf-sign3/bdn9yt
+     * 接口地址:https://{host}/v3/sign-flow/{signFlowId}/copiers/delete
+     *
+     * 请求方法:POST
+     * 注意事项:流程若已开启,将不支持再删除抄送方信息。
+     * @param signFlowId 签署流程ID
+     * @param json 删除抄送方信息
+     * @return
+     */
+    public static EsignHttpResponse delCopiers(String signFlowId,String json) throws EsignException {
+        String apiaddr = EsignConfig.getInstance().get("del.copiers");
+        apiaddr = MessageFormat.format(apiaddr, signFlowId);
+        return POST(apiaddr, json);
+    }
+    /**
+     * 基于文件发起签署
+     * 参考文档:https://open.esign.cn/doc/opendoc/pdf-sign3/su5g42
+     * 接口地址:https://{host}/v3/sign-flow/create-by-file
+     * 请求方法:POST
+     * 注意事项:
+     * 1. 单个签署流程中对签署文件(docs)要求如下:
+     *  单个签署流程中所添加的文件个数不可超过50个。
+     *  单个文件大小不可超过50MB。
+     *  单个文件内单页大小不可超过20MB(文件内含图片时,需特别关注单页大小)。
+     *  单个签署流程中所添加的文件大小总和不可超过500MB。
+     * 2. 单个签署流程中一次性添加的签署方(signers)不要超过10个,如果超过10个后续可以用《追加签署区》接口追加,整个流程不能超过50个签署方。
+     * 3. 单个签署流程中所添加的签署区(signFields)总和不要超过300个。
+     * 4. 单个签署流程中对附属材料(attachments)要求如下:
+     *  单个签署流程中所添加的附件个数不可超过50个。
+     *  单个附件大小不可超过10MB。
+     * 5. autoStart自动开启签署流程,默认值 true
+     *  true - 自动开启(发起签署流程,将直接进入“签署中”状态)
+     *  false - 非自动开启(发起“草稿”状态的签署流程,需调用【开启签署流程】接口后流程进入“签署中”状态)
+     *  补充说明: 自动开启的流程不允许再追加待签署文件,点击这里了解更多流程状态说明。
+     * @param json 签署信息
+     * @return
+     */
+    public static EsignHttpResponse create_by_file(String json) throws EsignException {
+        String apiaddr = EsignConfig.getInstance().get("create_by_file");
+        return POST(apiaddr, json);
+    }
+
+    /**
+     * 开启签署流程
+     * 参考文档:https://open.esign.cn/doc/opendoc/pdf-sign3/bdn9yt
+     * 接口地址:https://{host}/v3/sign-flow/{signFlowId}/start
+     *
+     * 请求方法:POST
+     * 注意事项:流程若已开启,将不支持再删除抄送方信息。
+     * @param signFlowId 签署流程ID
+     * @return
+     */
+    public static EsignHttpResponse start_by_file(String signFlowId) throws EsignException {
+        String apiaddr = EsignConfig.getInstance().get("start_by_file");
+        apiaddr = MessageFormat.format(apiaddr, signFlowId);
+        return POST(apiaddr, null);
+    }
+    /**
+     * 撤销签署流程
+     * 参考文档:https://open.esign.cn/doc/opendoc/pdf-sign3/klbicu
+     * 接口地址:https://{host}/v3/sign-flow/{signFlowId}/revoke
+     *
+     * 请求方法:POST
+     * 注意事项:撤销签署中的流程,撤销后签署流程将终止,变为已撤销状态。
+     * @param signFlowId 签署流程ID
+     * @param revokeReason 撤销原因 撤销原因最多50字
+     * @return
+     */
+    public static EsignHttpResponse revoke_by_file(String signFlowId,String revokeReason) throws EsignException {
+        String apiaddr = EsignConfig.getInstance().get("revoke_by_file");
+        apiaddr = MessageFormat.format(apiaddr, signFlowId);
+        Map<String,String> jsonMap = Maps.newHashMap();
+        jsonMap.put("revokeReason",(StringUtils.isNotBlank(revokeReason)?revokeReason:""));
+        String json = JSON.toJSONString(jsonMap);
+        return POST(apiaddr, json);
+    }
+
+    /**
+     * 催签流程中签署人
+     * 参考文档:https://open.esign.cn/doc/opendoc/pdf-sign3/klbicu
+     * 接口地址:https://{host}/v3/sign-flow/{signFlowId}/urge
+     * 请求方法:POST
+     * 【注意事项】
+     * 发起签署之后的前半小时不可进行催签;
+     * 与上一次催签,请至少间隔十分钟再发起下一次催签提醒。
+     * @param signFlowId 签署流程ID
+     * @param json 催签的签署人信息
+     * @return
+     */
+    public static EsignHttpResponse urge_by_file(String signFlowId,String json) throws EsignException {
+        String apiaddr = EsignConfig.getInstance().get("urge_by_file");
+        apiaddr = MessageFormat.format(apiaddr, signFlowId);
+        return POST(apiaddr, json);
+    }
+
+    /**
+     * 下载已签署文件及附属材料
+     * 参考文档:https://open.esign.cn/doc/opendoc/pdf-sign3/kczf8g
+     * 接口地址:https://{host}/v3/sign-flow/{signFlowId}/file-download-url
+     * 请求方法:GET
+     * 【注意事项】
+     * 未签署完成的流程,无法下载相关文件,否则会报错:"流程非签署完成状态,不允许下载文档"。
+     * @param signFlowId 签署流程ID
+     * @param urlAvailableDate 下载链接有效期,单位:秒。默认:3600秒(60分钟)
+     * 可传入:1-3600
+     * 补充说明:
+     * 为链接设置有效期是一项安全措施,旨在降低因无关人员访问而导致的信息泄露风险。
+     * @return
+     */
+    public static EsignHttpResponse getFile_download_url(String signFlowId,Integer urlAvailableDate) throws EsignException, URISyntaxException {
+        String apiaddr = EsignConfig.getInstance().get("file_download_url");
+        apiaddr = MessageFormat.format(apiaddr, signFlowId);
+        if (null!=urlAvailableDate&&urlAvailableDate>0&&urlAvailableDate<=3600) {
+            URIBuilder uriBuilder = new URIBuilder(apiaddr);
+            uriBuilder.addParameter("urlAvailableDate", String.valueOf(urlAvailableDate));
+            URI uri = uriBuilder.build(); // 自动编码
+            apiaddr = uri.toString();
+        }
+        return GET(apiaddr, null);
+    }
+
+
+
 }