Explorar el Código

航福oa流程发票附件上传钉盘

hxx hace 2 meses
padre
commit
c9464d8172

+ 105 - 0
mjava-hangfu/pom.xml

@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.malk</groupId>
+    <artifactId>mjava-hangfu</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>mjava-hangfu</name>
+    <description>mjava-hangfu</description>
+    <properties>
+        <java.version>1.8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <spring-boot.version>2.6.13</spring-boot.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>base</artifactId>
+            <version>1.3</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.example</groupId>
+            <artifactId>k3cloud</artifactId>
+            <version>8.0.6</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>easyexcel</artifactId>
+            <version>3.3.2</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.example</groupId>
+            <artifactId>gson</artifactId>
+            <version>2.8.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.example</groupId>
+            <artifactId>k3cloud</artifactId>
+            <version>8.0.6</version>
+            <scope>compile</scope>
+        </dependency>
+    </dependencies>
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.1</version>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                    <encoding>UTF-8</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot.version}</version>
+                <configuration>
+                    <mainClass>com.malk.hangfu.MjavaHangfuApplication</mainClass>
+                    <skip>true</skip>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>repackage</id>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 15 - 0
mjava-hangfu/src/main/java/com/malk/hangfu/MjavaHangfuApplication.java

@@ -0,0 +1,15 @@
+package com.malk.hangfu;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@EnableScheduling
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+public class MjavaHangfuApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(MjavaHangfuApplication.class, args);
+    }
+
+}

+ 27 - 0
mjava-hangfu/src/main/java/com/malk/hangfu/config/KDWebApiConfig.java

@@ -0,0 +1,27 @@
+package com.malk.hangfu.config;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 功能:
+ * 作者:hanxue
+ * 日期:2025/12/1 15:09
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "kingdee")
+@Slf4j
+public class KDWebApiConfig {
+    private String XKDApiAcctID;
+
+    private String XKDApiUserName;
+
+    private String XKDApiAppID;
+
+    private String XKDApiAppSec;
+
+    private String XKDApiServerUrl;
+}

+ 48 - 0
mjava-hangfu/src/main/java/com/malk/hangfu/controller/FiletoDingController.java

@@ -0,0 +1,48 @@
+package com.malk.hangfu.controller;
+
+import com.malk.hangfu.service.HangfuService;
+import com.malk.server.common.McR;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * 功能:
+ * 作者:hanxue
+ * 日期:2025/11/6 15:24
+ */
+@RequestMapping
+@RestController
+public class FiletoDingController {
+    @Autowired
+    private HangfuService hangfuService;
+
+
+//    同步审批流程的附件到钉盘
+    @PostMapping("/syncFileToDing")
+    public McR syncFileToDing(@RequestBody Map<String, Object> param) throws IOException {
+        if (Objects.nonNull(param.get("formInstId"))){
+            return hangfuService.syncFileToDing(param);
+        }
+        return McR.errorParam("实例id不能为空!");
+
+    }
+
+
+//    同步金蝶附件到钉盘
+@PostMapping("/syncKindeeToDing")
+public McR syncKindeeToDing(@RequestBody Map<String, Object> param) throws Exception {
+    if (Objects.nonNull(param.get("formInstId"))){
+        return hangfuService.syncKindeeToDing(param);
+    }
+    return McR.errorParam("实例id不能为空!");
+
+}
+
+
+
+}

+ 36 - 0
mjava-hangfu/src/main/java/com/malk/hangfu/entity/Voucher.java

@@ -0,0 +1,36 @@
+package com.malk.hangfu.entity;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * 功能:
+ * 作者:hanxue
+ * 日期:2025/12/2 14:59
+ */
+@Data
+@EqualsAndHashCode
+public class Voucher {
+    @ExcelProperty("账簿")
+    private String accountBook;
+    @ExcelProperty("日期")
+    private Date date;
+    @ExcelProperty("凭证字")
+    private String voucherWord;
+    @ExcelProperty("会计年度")
+    private String year;
+    @ExcelProperty("凭证号")
+    private String voucherNo;
+    @ExcelProperty("摘要")
+    private String explanation;
+    @ExcelProperty("科目编码")
+    private String accountId;
+    @ExcelProperty("借方金额")
+    private Double debit;
+    @ExcelProperty("贷方金额")
+    private Double credit;
+
+}

+ 14 - 0
mjava-hangfu/src/main/java/com/malk/hangfu/service/HangfuService.java

@@ -0,0 +1,14 @@
+package com.malk.hangfu.service;
+
+import com.malk.server.common.McR;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.Map;
+
+@Service
+public interface HangfuService {
+    McR syncFileToDing(Map param) throws IOException;
+
+    McR syncKindeeToDing(Map<String, Object> param) throws Exception;
+}

+ 426 - 0
mjava-hangfu/src/main/java/com/malk/hangfu/service/impl/HangfuServiceImpl.java

@@ -0,0 +1,426 @@
+package com.malk.hangfu.service.impl;
+
+import cn.hutool.core.date.DateUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.util.ListUtils;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.gson.Gson;
+import com.kingdee.bos.webapi.entity.IdentifyInfo;
+import com.kingdee.bos.webapi.sdk.K3CloudApi;
+import com.malk.hangfu.entity.Voucher;
+import com.malk.hangfu.service.HangfuService;
+import com.malk.server.common.McR;
+import com.malk.server.dingtalk.DDConf;
+import com.malk.server.dingtalk.DDR_New;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Workflow;
+import com.malk.utils.UtilHttp;
+import com.malk.utils.UtilMap;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
+import com.malk.hangfu.config.KDWebApiConfig;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.time.LocalDate;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 功能:
+ * 作者:hanxue
+ * 日期:2025/11/17 10:38
+ */
+@Service
+@Slf4j
+@Component
+public class HangfuServiceImpl implements HangfuService {
+    @Autowired
+    private DDConf ddConf;
+    @Autowired
+    private DDClient ddClient;
+    @Autowired
+    private DDClient_Workflow ddworkflow;
+    @Autowired
+    private KDWebApiConfig kdWebApiConf;
+
+    @Value(value = "${dingtalk.unionId}")
+    private String unionId;
+    @Value(value = "${dingtalk.spaceId}")
+    private String spaceId;
+    @Value(value = "${dingtalk.saveFilePath}")
+    private String saveFilePath;
+    @Value(value ="${dingtalk.demoFilePath}")
+    private String demoFilePath;
+    @Override
+    public McR syncFileToDing(Map param) throws IOException {
+        String formInstId = param.get("formInstId").toString();
+        String formSerNo = param.get("formSerNo").toString();
+        LocalDate now = LocalDate.now();
+        String yearMonth = now.getYear()+""+now.getMonthValue();
+        Map topFolder = getDentryList(spaceId, "0", unionId, "").stream()
+                .filter(map -> map.get("name").toString().equals(yearMonth) && map.get("type").toString().equals("FOLDER"))
+                .findFirst()
+                .orElse(null);
+        String parentId ="";
+//        1、获取到yyyyMM文件夹id信息
+        if (Objects.nonNull(topFolder)){
+            parentId = topFolder.get("id").toString();
+        }else {
+            //创建该数据标题文件夹
+            Map yearMonthDentry = createFolder(spaceId,"0",yearMonth,unionId);
+            parentId = yearMonthDentry.get("id").toString();
+        }
+//        2、创建yyyy-MM-formSerNo目录
+        Map formInstIdentry = createFolder(spaceId,parentId,now.getYear()+"-"+now.getMonthValue()+"-"+formSerNo,unionId);
+//        3、审批附件同步到钉盘
+        return OAfileUptoDing(formInstId,formInstIdentry.get("uuid").toString());
+    }
+
+    @Override
+    public McR syncKindeeToDing(Map<String, Object> param) throws Exception {
+        String formSerNo = param.get("formSerNo").toString();
+        LocalDate now = LocalDate.now();
+        String yearMonth = now.getYear()+""+now.getMonthValue();
+        String secondName =yearMonth+"-"+formSerNo;
+//        Map topFolder = getDentryList(spaceId, "0", unionId, "").stream()
+//                .filter(map -> map.get("name").toString().equals(yearMonth) && map.get("type").toString().equals("FOLDER"))
+//                .findFirst()
+//                .orElse(null);
+//        String parentId =topFolder.get("id").toString();
+//        Map formInstIdentry = getDentryList(spaceId, parentId, unionId, "").stream()
+//                .filter(map -> map.get("name").toString().equals(secondName) && map.get("type").toString().equals("FOLDER"))
+//                .findFirst()
+//                .orElse(null);
+
+
+        return kibdeeFileUptoDing(null,null,"FAccountBookID.FNumber='001'  and FYear='2025'");
+    }
+
+
+    //===========================================辅助函数================================================================
+    //创建钉盘文件夹
+    private Map createFolder(String spaceId, String parentId, String folderName, String unionId){
+        String url = "https://api.dingtalk.com/v1.0/storage/spaces/"+spaceId+"/dentries/"+parentId+"/folders";
+        Map query = new HashMap();
+        query.put("unionId",unionId);
+        Map body = new HashMap();
+        body.put("name",folderName);
+        DDR_New ddrNew = (DDR_New) UtilHttp.doPost(url, ddClient.initTokenHeader(), query, body, DDR_New.class);
+        Map dentry = ddrNew.getDentry();
+        return dentry;
+    }
+
+    //    获取文件夹
+    private List<Map> getDentryList(String spaceId, String parentId, String unionId, String nextToken) {
+        List<Map> dentryList = new ArrayList<>();
+        Map query = new HashMap();
+        query.put("parentId",parentId);
+        query.put("unionId",unionId);
+        query.put("maxResults",50);
+        if (Strings.isNotBlank(nextToken)){
+            query.put("nextToken",nextToken);
+        }
+//        获取文件或文件夹列表
+        DDR_New ddrNew = (DDR_New) UtilHttp.doGet("https://api.dingtalk.com/v1.0/storage/spaces/"+spaceId+"/dentries", ddClient.initTokenHeader(), query, DDR_New.class);
+        dentryList.addAll(ddrNew.getDentries());
+        if (Objects.nonNull(ddrNew.getNextToken())){
+            dentryList.addAll(getDentryList(spaceId, parentId, unionId, ddrNew.getNextToken()));
+        }
+        return dentryList;
+    }
+
+    //  上传审批附件到钉盘
+    private McR OAfileUptoDing(String formInstId,String dentryUuid ) throws IOException {
+        Map<String, Object> result = new HashMap<>();
+        List<FileTask> processedFiles = new ArrayList<>();
+        try {
+            // 1. 获取表单详情
+            Map<String, Object> tableDetails = ddworkflow.getProcessInstanceId(ddClient.getAccessToken(), formInstId);
+            if (tableDetails == null || tableDetails.isEmpty()) {
+                return McR.errorParam("获取表单详情失败");
+            }
+            List<Map<String, Object>> formComponentValues = (List<Map<String, Object>>) tableDetails.get("formComponentValues");
+            if (formComponentValues == null || formComponentValues.isEmpty()) {
+                return McR.errorParam("获取表单详情失败");
+            }
+            Set<String> targetNames = new HashSet<>(Arrays.asList("其他附件", "银行回单", "报销明细", "发票", "上传附件", "附件"));
+            for (Map<String, Object> formComponentValue : formComponentValues) {
+                String name = UtilMap.getString(formComponentValue, "name");
+                if (name == null || !targetNames.contains(name)) {
+                    continue;
+                }
+                try {
+                    if ("银行回单".equals(name) || "其他附件".equals(name) || "附件".equals(name)) {
+                        processFileAttachments(formComponentValue, formInstId, processedFiles);
+                    } else if ("发票".equals(name)) {
+                        processInvoiceAttachments(formComponentValue, processedFiles);
+                    } else if ("报销明细".equals(name)) {
+                        List<Map> paymentDeatils = (List<Map>) JSONArray.parse(formComponentValue.get("value").toString());
+                        for (Map paymentDeatil : paymentDeatils) {
+                            List<Map> rowValues = (List<Map>) JSONArray.parse(paymentDeatil.get("rowValue").toString());
+                            for (Map rowValue : rowValues) {
+                                String label = (String) rowValue.get("label");
+                                switch (label) {
+                                    case "发票":
+                                        processInvoiceAttachments(rowValue, processedFiles);
+                                        continue;
+                                    case "附件":
+                                        processFileAttachments(rowValue, formInstId, processedFiles);
+                                        continue;
+                                }
+                            }
+                        }
+                    }
+
+                } catch (Exception e) {
+                    System.err.println("处理字段 [" + name + "] 时出错: " + e.getMessage());
+                    e.printStackTrace();
+                }
+
+            }
+            if (processedFiles.size() > 0) {
+                for (FileTask processedFile : processedFiles) {
+                    downloadFile(processedFile.downloadUrl, saveFilePath + processedFile.fileName);
+                    uploadToDingTalk(saveFilePath + processedFile.fileName, dentryUuid, "OVERWRITE");
+
+                }
+            }
+            return McR.success();
+        } catch (Exception e) {
+            return McR.errorParam("上传附件失败");
+        }
+    }
+
+    //    上传金蝶附件到钉盘
+    private McR kibdeeFileUptoDing(String formInstId,String dentryUuid,String filterString ) throws Exception {
+        Map<String, Object> billInfo = new HashMap<>();
+        billInfo.put("FormId","GL_VOUCHER");
+        billInfo.put("FieldKeys","FAccountBookID.FNumber,FDate,FVOUCHERGROUPID.Fname,FYEAR,FVOUCHERGROUPNO,FEXPLANATION,FACCOUNTID.Fname,FDC,FDebit,FCredit,FDEBITTOTAL,FCREDITTOTAL");
+        billInfo.put("FilterString",filterString);
+        String billInfoJson = new Gson().toJson(billInfo);
+        K3CloudApi client = new K3CloudApi(initIden());
+        List<List<Object>> billList = client.executeBillQuery(billInfoJson);
+        System.out.println(billList);
+        if (billList == null || billList.isEmpty()) {
+            return McR.errorParam("获取表单详情失败");
+        }else{
+            Map<Object, List<List<Object>>> grouped = billList.stream()
+                    .filter(row -> row != null && row.size() > 4)
+                    .collect(Collectors.groupingBy(row -> row.get(4)));
+            System.out.println(grouped);
+            for (Map.Entry<Object, List<List<Object>>> entry : grouped.entrySet()) {
+                List<Voucher> voucherList = ListUtils.newArrayList();
+                List<List<Object>> group = entry.getValue();
+                for (List<Object> row : group) {
+                    Voucher voucherentity = new Voucher();
+                    voucherentity.setAccountBook(row.get(0).toString());
+                    voucherentity.setDate((Date) row.get(1));
+                    voucherentity.setVoucherWord(row.get(2).toString());
+                    voucherentity.setYear(row.get(3).toString());
+                    voucherentity.setVoucherNo(row.get(4).toString());
+                    voucherentity.setExplanation(row.get(5).toString());
+                    voucherentity.setAccountId(row.get(6).toString());
+                    voucherentity.setDebit(Double.parseDouble(row.get(7).toString()));
+                    voucherentity.setCredit(Double.parseDouble(row.get(8).toString()));
+                    voucherList.add(voucherentity);
+                }
+                writeExcel(voucherList);
+
+                // 转为 Object[][] 或直接传 List
+//                callExternalFunction(entry.getKey(), group);
+            }
+        }
+
+
+        return McR.success();
+
+    }
+
+    private void writeExcel(List<Voucher> voucherList)  {
+        String templateFileName = demoFilePath + "demo" + File.separator + "凭证模板.xls";
+        String fileName = demoFilePath + "templateWrite" + System.currentTimeMillis() + ".xlsx";
+        EasyExcel.write(fileName, Voucher.class).withTemplate(templateFileName).sheet().doWrite(voucherList);
+    }
+    private List<Voucher> getVoucherData() {
+        List<Voucher> voucherListlist = ListUtils.newArrayList();
+        for (int i = 0; i < 10; i++) {
+            Voucher data = new Voucher();
+
+            voucherListlist.add(data);
+        }
+        return voucherListlist;
+    }
+
+    private IdentifyInfo initIden(){
+        //注意 1:此处不再使用参数形式传入用户名及密码等敏感信息,改为在登录配置文件中设置。
+        //注意 2:必须先配置第三方系统登录授权信息后,再进行业务操作,详情参考各语言版本SDK介绍中的登录配置文件说明。
+        //读取配置,初始化SDK
+        IdentifyInfo iden = new IdentifyInfo();
+        iden.setUserName(kdWebApiConf.getXKDApiUserName());
+        iden.setAppId(kdWebApiConf.getXKDApiAppID());
+        iden.setdCID(kdWebApiConf.getXKDApiAcctID());
+        iden.setAppSecret(kdWebApiConf.getXKDApiAppSec());
+        iden.setServerUrl(kdWebApiConf.getXKDApiServerUrl());
+
+        return iden;
+    }
+    static class FileTask {
+        String fileName;        // 文件名
+        String downloadUrl;     // 下载链接(后续填充)
+
+        public FileTask(String fileName, String downloadUrl) {
+            this.fileName = fileName;
+            this.downloadUrl = downloadUrl;
+        }
+    }
+    //处理附件组件
+    private void processFileAttachments(Map<String, Object> formComponentValue, String formInstId, List<FileTask> processedFiles) throws IOException{
+        Object valueObj = formComponentValue.get("value");
+        if (valueObj == null) return;
+        try {
+            List<Map<String, Object>> files = (List<Map<String, Object>>) JSONArray.parse(UtilMap.getString(formComponentValue,"value"));
+            if (files == null) return;
+            for (Map<String, Object> file : files) {
+                String fileId = UtilMap.getString(file, "fileId");
+                String fileName = UtilMap.getString(file, "fileName");
+                if (fileId == null || fileName == null) continue;
+                Map body = new HashMap();
+                body.put("processInstanceId",formInstId);
+                body.put("fileId",fileId);
+                DDR_New ddr = (DDR_New) UtilHttp.doPost("https://api.dingtalk.com//v1.0/workflow/processInstances/spaces/files/urls/download", ddConf.initTokenHeader(ddClient.getAccessToken()), null, body, DDR_New.class);
+                Map downloadUri = (Map) ddr.getResult();
+                String downloadUrl = UtilMap.getString(downloadUri, "downloadUri");
+                if (downloadUrl == null) continue;
+                processedFiles.add(new FileTask(fileName, downloadUrl));
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("解析附件列表失败", e);
+        }
+    }
+
+    //    处理发票组件
+    private void processInvoiceAttachments(Map<String, Object> formComponentValue, List<FileTask> processedFiles) throws IOException {
+        Map extendValue =new HashMap();
+        if(formComponentValue.containsKey("extValue")){
+//            主表发票信息
+            extendValue =(Map)  JSONObject.parse(formComponentValue.get("extValue").toString());
+        }else if (formComponentValue.containsKey("extendValue")){
+//            明细表发票信息extendValue
+            extendValue =(Map)  JSONObject.parse(formComponentValue.get("extendValue").toString());
+        }
+        if(extendValue.containsKey("invoiceList")){
+            List< Map> invoiceList = (List<Map>) extendValue.get("invoiceList");
+            for(Map invoice : invoiceList){
+                String downloadUrl = UtilMap.getString(invoice,"electronicUrl");
+                String fileName = UtilMap.getString(invoice,"fileName");
+                processedFiles.add(new FileTask(fileName, downloadUrl));
+            }
+        }
+    }
+
+
+    //上传文件至钉盘
+    private Map uploadToDingTalk(String filePath,String dentryUuid,String conflictStrategy) {
+        //获取当前时间戳
+        long beginTimestamp = System.currentTimeMillis();
+        System.out.println("开始上传附件:" + DateUtil.format(new Date(beginTimestamp), "yyyy-MM-dd HH:mm:ss"));
+
+        //文件
+        File file = new File(filePath);
+
+        //获取文件上传信息
+        Map param = new HashMap();
+        param.put("unionId",unionId);
+        Map body = new HashMap();
+        body.put("protocol","HEADER_SIGNATURE");
+        body.put("multipart",false);
+
+        DDR_New ddr = (DDR_New) UtilHttp.doPost("https://api.dingtalk.com/v1.0/storage/spaces/" + spaceId + "/files/uploadInfos/query", ddConf.initTokenHeader(ddClient.getAccessToken()), param, body, DDR_New.class);
+        String uploadKey = ddr.getUploadKey();
+        Map headerSignatureInfo = ddr.getHeaderSignatureInfo();
+        Map<String,String> headers = (Map<String,String>) headerSignatureInfo.get("headers");
+        List<String> resourceUrls = (List<String>) headerSignatureInfo.get("resourceUrls");
+        String resourceUrl = resourceUrls.get(0);
+
+        Map dentry = new HashMap();
+        //使用OSS的header加签方式上传文件
+        try {
+            URL url = new URL(resourceUrl);
+            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
+            if (headers != null) {
+                for (Map.Entry<String, String> entry : headers.entrySet()) {
+                    connection.setRequestProperty(entry.getKey(), entry.getValue());
+                }
+            }
+            connection.setDoOutput(true);
+            connection.setRequestMethod("PUT");
+            connection.setUseCaches(false);
+            connection.setReadTimeout(10000);
+            connection.setConnectTimeout(10000);
+            connection.connect();
+            OutputStream out = connection.getOutputStream();
+            InputStream is = new FileInputStream(file);
+            byte[] b =new byte[1024];
+            int temp;
+            while ((temp=is.read(b))!=-1){
+                out.write(b,0,temp);
+            }
+            out.flush();
+            out.close();
+            int responseCode = connection.getResponseCode();
+            connection.disconnect();
+            if (responseCode == 200) {
+                System.out.println("上传成功");
+            } else {
+                System.out.println("上传失败");
+            }
+            //提交文件
+            Map body2 = new HashMap();
+            Map option = new HashMap();
+            option.put("conflictStrategy",conflictStrategy);
+            body2.put("uploadKey",uploadKey);
+            body2.put("name",file.getName());
+            body2.put("option",option);
+            DDR_New ddrNew = (DDR_New) UtilHttp.doPost("https://api.dingtalk.com/v2.0/storage/spaces/files/"+dentryUuid+"/commit", ddClient.initTokenHeader(), param, body2, DDR_New.class);
+            dentry = ddrNew.getDentry();
+
+        }catch (IOException e){
+            log.info("上传文件异常:{}",e);
+        }
+
+        long endTimestamp = System.currentTimeMillis();
+        System.out.println("上传文件结束:" + DateUtil.format(new Date(endTimestamp), "yyyy-MM-dd HH:mm:ss"));
+        System.out.println("上传文件耗时:" + (endTimestamp - beginTimestamp)/1000.0 + "s");
+        return dentry;
+    }
+    // 文件下载本地
+    private void downloadFile(String fileURL, String savePath) throws IOException {
+        URL url = new URL(fileURL);
+        HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
+        int responseCode = httpConn.getResponseCode();
+
+        // 检查HTTP响应代码是否为200
+        if (responseCode == HttpURLConnection.HTTP_OK) {
+            InputStream inputStream = httpConn.getInputStream();
+            FileOutputStream outputStream = new FileOutputStream(savePath);
+
+            byte[] buffer = new byte[4096];
+            int bytesRead = -1;
+
+            while ((bytesRead = inputStream.read(buffer)) != -1) {
+                outputStream.write(buffer, 0, bytesRead);
+            }
+            outputStream.close();
+            inputStream.close();
+        } else {
+            System.out.println("无法下载文件。HTTP响应代码: " + responseCode);
+        }
+        httpConn.disconnect();
+    }
+}

+ 42 - 0
mjava-hangfu/src/main/resources/application-dev.yml

@@ -0,0 +1,42 @@
+server:
+  port: 9050
+  servlet:
+    context-path: /hangfu
+
+enable:
+  scheduling: true
+logging:
+  config: classpath:logback-spring.xml
+  path: /home/server/hangfu/log/
+  level:
+    com.malk.*: debug
+
+# dingtalk
+dingtalk:
+  agentId:
+  appKey: dingzzfjcyru6dsvukdi
+  appSecret: rkfWqEmeAMNycW09DxL9yeduOAIibOClszovu1vLbb5sLIInkkVa9SuGfIFW1rDU
+  corpId:
+  aesKey:
+  token:
+  operator: 54414418031244193
+  unionId: DF0glWxzrarF8VGN0uvcDgiEiE
+  spaceId: 27710317834
+  saveFilePath: d://
+  demoFilePath: d://
+
+aliwork:
+  appType: APP_D7TTZKL8C03JKEWCNW74
+  systemToken: TCC66771RQETFGT5DYPUGAXP4GRC29A6HCV7MV19
+
+kingdee:
+  # 第三方系统登录授权的账套ID
+  X-KDApi-AcctID: 6928f69a15e1d6
+  # 第三方系统登录授权的用户
+  X-KDApi-UserName: 王丽丽
+  # 第三方系统登录授权的应用ID
+  X-KDApi-AppID: 330032_5/8oQbvOTmAZXV/s30Rt489G0j7+SNoO
+  # 第三方系统登录授权的应用密钥
+  X-KDApi-AppSec: 35ff354a51624e76a035687acd61157b
+  # 服务Url地址(公有云统一走网关sdk底层已处理,无需传X-KDApi-ServerUrl,下面这行需要注释)
+  X-KDApi-ServerUrl: http://223.78.107.18:9000/k3cloud

+ 42 - 0
mjava-hangfu/src/main/resources/application-prod.yml

@@ -0,0 +1,42 @@
+server:
+  port: 9050
+  servlet:
+    context-path: /hangfu
+
+enable:
+  scheduling: true
+logging:
+  config: classpath:logback-spring.xml
+  path: /home/server/hangfu/log/
+  level:
+    com.malk.*: debug
+
+# dingtalk
+dingtalk:
+  agentId:
+  appKey: dingzzfjcyru6dsvukdi
+  appSecret: rkfWqEmeAMNycW09DxL9yeduOAIibOClszovu1vLbb5sLIInkkVa9SuGfIFW1rDU
+  corpId:
+  aesKey:
+  token:
+  operator: 104742182429066347
+  unionId: yzd0zzAziSqx3ZvFqGJWKxQiEiE
+  spaceId: 27710317834
+  saveFilePath: d://
+  demoFilePath: d://
+
+aliwork:
+  appType: APP_D7TTZKL8C03JKEWCNW74
+  systemToken: TCC66771RQETFGT5DYPUGAXP4GRC29A6HCV7MV19
+
+kingdee:
+  # 第三方系统登录授权的账套ID
+  X-KDApi-AcctID: 6928f69a15e1d6
+  # 第三方系统登录授权的用户
+  X-KDApi-UserName: 王丽丽
+  # 第三方系统登录授权的应用ID
+  X-KDApi-AppID: 330032_5/8oQbvOTmAZXV/s30Rt489G0j7+SNoO
+  # 第三方系统登录授权的应用密钥
+  X-KDApi-AppSec: 35ff354a51624e76a035687acd61157b
+  # 服务Url地址(公有云统一走网关sdk底层已处理,无需传X-KDApi-ServerUrl,下面这行需要注释)
+  X-KDApi-ServerUrl: http://223.78.107.18:9000/k3cloud

+ 15 - 0
mjava-hangfu/src/main/resources/application.yml

@@ -0,0 +1,15 @@
+spring:
+  profiles:
+    active: dev
+  servlet:
+    multipart:
+      max-file-size: 100MB
+      max-request-size: 100MB
+  http:
+    enabled: false
+
+#  configuration:
+#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+  global-config:
+    db-config:
+      id-type: auto

+ 61 - 0
mjava-hangfu/src/main/resources/logback-spring.xml

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration debug="false" scan="false" scanPeriod="60 seconds">
+    <springProperty scope="context" name="LOG_HOME" source="logging.path" defaultValue="/home/server/log/"/>
+    <property name="FileNamePattern" value="${LOG_HOME}%d{yyyyMM}/%d{dd}"/>
+
+    <!-- 定义控制台输出 -->
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} - [%thread] - %-5level - %logger{50} - %msg%n</pattern>
+        </layout>
+    </appender>
+
+    <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 指定日志文件的名称 -->
+        <!--<file>${FileNamePattern}/info.log</file>-->
+
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${FileNamePattern}/info-%i.log</fileNamePattern>
+            <MaxHistory>30</MaxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <MaxFileSize>30MB</MaxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
+        </layout>
+    </appender>
+
+    <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
+        <discriminator>
+            <Key>processid</Key>
+            <DefaultValue>sys</DefaultValue>
+        </discriminator>
+        <sift>
+            <appender name="FILE-${processid}"
+                      class="ch.qos.logback.core.rolling.RollingFileAppender">
+                <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+                    <FileNamePattern>
+                        ${FileNamePattern}/${processid}.log
+                    </FileNamePattern>
+                </rollingPolicy>
+                <layout class="ch.qos.logback.classic.PatternLayout">
+                    <Pattern>
+                        %d{yyyyMMdd:HH:mm:ss.SSS} [%thread] %-5level %msg%n
+                    </Pattern>
+                </layout>
+            </appender>
+        </sift>
+    </appender>
+
+
+    <!-- 日志输出级别 -->
+    <logger name="org.springframework" level="debug"  additivity="false"/>
+    <logger name="com.malk.connecter" level="debug"/>
+    <root level="INFO">
+        <appender-ref ref="stdout"/>
+        <appender-ref ref="appLogAppender"/>
+        <appender-ref ref="SIFT"/>
+    </root>
+</configuration>

+ 14 - 0
mjava-hangfu/src/test/java/com/malk/hangfu/MjavaHangfuApplicationTests.java

@@ -0,0 +1,14 @@
+package com.malk.hangfu;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@SpringBootTest
+class MjavaHangfuApplicationTests {
+
+    @Test
+    void contextLoads() {
+    }
+
+}