diff --git a/pom.xml b/pom.xml
index 1290a62..77f2c05 100644
--- a/pom.xml
+++ b/pom.xml
@@ -53,6 +53,29 @@
spring-boot-starter-test
test
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.14
+
+
+
+ cn.hutool
+ hutool-all
+ 5.8.32
+
+
+ com.alibaba.fastjson2
+ fastjson2
+ 2.0.53
+
+
+
+ org.apache.httpcomponents
+ httpmime
+ 4.5.13
+
diff --git a/src/main/java/vin/vio/collaboraonline/controller/WopiController.java b/src/main/java/vin/vio/collaboraonline/controller/WopiController.java
index 835316e..96bfde1 100644
--- a/src/main/java/vin/vio/collaboraonline/controller/WopiController.java
+++ b/src/main/java/vin/vio/collaboraonline/controller/WopiController.java
@@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.*;
import vin.vio.collaboraonline.model.WopiFile;
import vin.vio.collaboraonline.service.FileService;
+import java.io.File;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -48,9 +49,9 @@ public class WopiController {
// 获取文件内容
@GetMapping("/files/{fileId}/contents")
- public ResponseEntity getFile(@PathVariable String fileId) {
+ public ResponseEntity getFile(@PathVariable String fileId) {
- org.springframework.core.io.Resource fileResource = fileService.loadFileAsResource(fileId);
+ File fileResource = fileService.loadFileAsResource(fileId);
if (fileResource == null) {
return ResponseEntity.notFound().build();
}
diff --git a/src/main/java/vin/vio/collaboraonline/exception/AllKingdeeException.java b/src/main/java/vin/vio/collaboraonline/exception/AllKingdeeException.java
new file mode 100644
index 0000000..2c8b882
--- /dev/null
+++ b/src/main/java/vin/vio/collaboraonline/exception/AllKingdeeException.java
@@ -0,0 +1,16 @@
+package vin.vio.collaboraonline.exception;
+
+/**
+ * @Description: TODO
+ * @Date: 2025/2/21 16:24
+ * @Created: by ZZSLL
+ */
+
+public class AllKingdeeException extends Exception
+{
+
+ public AllKingdeeException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/src/main/java/vin/vio/collaboraonline/kingdee/AuthService.java b/src/main/java/vin/vio/collaboraonline/kingdee/AuthService.java
new file mode 100644
index 0000000..cd390d4
--- /dev/null
+++ b/src/main/java/vin/vio/collaboraonline/kingdee/AuthService.java
@@ -0,0 +1,187 @@
+package vin.vio.collaboraonline.kingdee;
+
+
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.entity.mime.HttpMultipartMode;
+import org.apache.http.entity.mime.MultipartEntity;
+import org.apache.http.entity.mime.content.InputStreamBody;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import vin.vio.collaboraonline.exception.AllKingdeeException;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @Description: TODO
+ * @Date: 2025/2/21 16:25
+ * @Created: by ZZSLL
+ */
+
+@Service
+public class AuthService {
+
+
+ @Value("${ensign.kingdee.is-public}")
+ private Boolean isPublic;
+
+ @Value("${ensign.kingdee.test-public-end-point}")
+ private String testPublicEndPoint;
+
+ @Value("${ensign.kingdee.test-inner-end-point}")
+ private String testInnerEndPoint;
+
+ @Value("${ensign.kingdee.prod-public-end-point}")
+ private String prodPublicEndPoint;
+
+ @Value("${ensign.kingdee.prod-inner-end-point}")
+ private String prodInnerEndPoint;
+
+ @Value("${ensign.kingdee.env}")
+ private String env;
+
+ @Value("${ensign.kingdee.appToken.appId}")
+ private String appId;
+
+ @Value("${ensign.kingdee.appToken.appSecuret}")
+ private String appSecuret;
+
+ @Value("${ensign.kingdee.appToken.tenantid}")
+ private String tenantid;
+
+ @Value("${ensign.kingdee.appToken.accountId}")
+ private String accountId;
+
+ @Value("${ensign.kingdee.appToken.language}")
+ private String language;
+
+ @Value("${ensign.kingdee.accessToken.user}")
+ private String user;
+
+ @Value("${ensign.kingdee.accessToken.usertype}")
+ private String usertype;
+
+ public String initBasePath() {
+ if ("test".equals(env)) {
+ if (isPublic) {
+ return testPublicEndPoint;
+ } else {
+ return testInnerEndPoint;
+ }
+ }
+
+ if ("prod".equals(env)) {
+ if (isPublic) {
+ return prodPublicEndPoint;
+ } else {
+ return prodInnerEndPoint;
+ }
+ }
+
+ return "";
+ }
+
+
+
+ public String initAccessToken() throws IOException, AllKingdeeException {
+
+ final String END_POINT = initBasePath() + "/ierp/api/getAppToken.do";
+ HttpClient client = new DefaultHttpClient();
+
+ HttpPost post = new HttpPost(END_POINT);
+
+ Map body = new HashMap<>();
+
+ body.put("appId", appId);
+ body.put("appSecuret", appSecuret);
+ body.put("tenantid", tenantid);
+ body.put("accountId", accountId);
+ body.put("language", language);
+
+ HttpEntity reqEntity = new StringEntity(JSONUtil.toJsonStr(body), "utf-8");
+
+ post.setEntity(reqEntity);
+ post.setConfig(initRequestConfig());
+ HttpResponse response = client.execute(post);
+ if (response.getStatusLine().getStatusCode() == 200) {
+
+ HttpEntity resEntity = response.getEntity();
+ String responseData = EntityUtils.toString(resEntity, "utf-8");
+ JSONObject jsonObject = JSON.parseObject(responseData);
+ Boolean status = (Boolean) jsonObject.get("status");
+ String state = (String) jsonObject.get("state");
+ if (status && "success".equals(state)) {
+ JSONObject data = (JSONObject) jsonObject.get("data");
+ String appToken = (String) data.get("app_token");
+ if (appToken != null && !appToken.isEmpty()) {
+ return doGetAccessToken(appToken);
+ }
+ }
+ }
+ throw new AllKingdeeException("获取AppToken失败");
+ }
+
+ private String doGetAccessToken(String appToken) throws IOException, AllKingdeeException {
+
+ HttpClient client = new DefaultHttpClient();
+
+ HttpPost post = new HttpPost(initBasePath() + "/ierp/api/login.do");
+
+ Map body = new HashMap<>();
+
+ body.put("user", user);
+ body.put("apptoken", appToken);
+ body.put("tenantid", tenantid);
+ body.put("accountId", accountId);
+ body.put("language", language);
+ body.put("usertype", usertype);
+
+ HttpEntity reqEntity = new StringEntity(JSONUtil.toJsonStr(body), "utf-8");
+
+ post.setEntity(reqEntity);
+ post.setConfig(initRequestConfig());
+ HttpResponse response = client.execute(post);
+
+ if (response.getStatusLine().getStatusCode() == 200) {
+
+ HttpEntity resEntity = response.getEntity();
+ String responseData = EntityUtils.toString(resEntity, "utf-8");
+ JSONObject jsonObject = JSON.parseObject(responseData);
+ Boolean status = (Boolean) jsonObject.get("status");
+ String state = (String) jsonObject.get("state");
+
+ if (status && "success".equals(state)) {
+ JSONObject data = (JSONObject) jsonObject.get("data");
+ String accessToken = (String) data.get("access_token");
+ if (accessToken != null && !accessToken.isEmpty()) {
+ return accessToken;
+ }
+ }
+ }
+ throw new AllKingdeeException("获取AccessToken失败");
+ }
+
+ private RequestConfig initRequestConfig() {
+ return RequestConfig.custom()
+ .setConnectTimeout(5000)//一、连接超时:connectionTimeout-->指的是连接一个url的连接等待时间
+ .setSocketTimeout(5000)// 二、读取数据超时:SocketTimeout-->指的是连接上一个url,获取response的返回等待时间
+ .setConnectionRequestTimeout(5000)
+ .build();
+ }
+
+}
diff --git a/src/main/java/vin/vio/collaboraonline/service/FileService.java b/src/main/java/vin/vio/collaboraonline/service/FileService.java
index bb5145d..6a8148c 100644
--- a/src/main/java/vin/vio/collaboraonline/service/FileService.java
+++ b/src/main/java/vin/vio/collaboraonline/service/FileService.java
@@ -26,12 +26,15 @@ import java.nio.file.*;
@Service
public class FileService {
-
@Value("${collabora.file-storage-path}")
private String BASE_DIR;
+ @Autowired
+ private KingdeeService kingdeeService;
+
public WopiFile getFileInfo(String fileId) {
- Path filePath = Paths.get(BASE_DIR, fileId);
+
+ Path filePath = Paths.get(kingdeeService.requestFile(fileId));
File targetFile = filePath.toFile();
@@ -60,23 +63,18 @@ public class FileService {
return file;
}
- public Resource loadFileAsResource(String fileId) {
- try {
- Path resolvedPath = validateFilePath(fileId);
+ public File loadFileAsResource(String fileId) {
+ String requestFile = kingdeeService.requestFile(fileId);
+ Path resolvedPath = new File(requestFile).toPath();
- FileSystemResource resource = new FileSystemResource(resolvedPath);
-
- if (resource.exists() && resource.isReadable() && Files.isRegularFile(resolvedPath)) {
- return resource;
- }
- return null;
- } catch (InvalidPathException | SecurityException e) {
- throw new RuntimeException("非法文件访问: " + fileId, e);
- }
+ return resolvedPath.toFile();
}
public boolean saveFile(String fileId, InputStream content) {
- Path targetPath = validateFilePath(fileId);
+
+ String requestFile = kingdeeService.requestFile(fileId);
+
+ Path targetPath = new File(requestFile).toPath();
try {
Path tempFile = Files.createTempFile(targetPath.getParent(), "wopi_", ".tmp");
@@ -90,43 +88,9 @@ public class FileService {
}
Files.move(tempFile, targetPath, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
-
- setFilePermissions(targetPath);
-
return true;
} catch (IOException e) {
throw new RuntimeException("文件保存失败: " + targetPath, e);
}
}
-
- private Path validateFilePath(String fileId) {
- if (fileId.contains("..") || fileId.contains(":") || fileId.contains("\\\\")) {
- throw new SecurityException("非法文件名: " + fileId);
- }
-
- Path basePath = Paths.get(BASE_DIR).normalize().toAbsolutePath();
- Path resolvedPath = basePath.resolve(fileId).normalize();
-
- if (!resolvedPath.startsWith(basePath)) {
- throw new SecurityException("路径越界访问: " + fileId);
- }
-
- return resolvedPath;
- }
-
- private void setFilePermissions(Path path) throws IOException {
- if (!System.getProperty("os.name").toLowerCase().contains("win")) return;
-
- String aclCommand = String.format(
- "icacls \"%s\" /grant:r \"%s\":(F) /inheritance:r",
- path.toString(),
- System.getProperty("user.name")
- );
-
- try {
- Runtime.getRuntime().exec(aclCommand).waitFor();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
}
diff --git a/src/main/java/vin/vio/collaboraonline/service/KingdeeService.java b/src/main/java/vin/vio/collaboraonline/service/KingdeeService.java
new file mode 100644
index 0000000..ed761f4
--- /dev/null
+++ b/src/main/java/vin/vio/collaboraonline/service/KingdeeService.java
@@ -0,0 +1,87 @@
+package vin.vio.collaboraonline.service;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.client.ClientHttpRequest;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.http.client.SimpleClientHttpRequestFactory;
+import org.springframework.stereotype.Service;
+import vin.vio.collaboraonline.exception.AllKingdeeException;
+import vin.vio.collaboraonline.kingdee.AuthService;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import static cn.hutool.http.HttpUtil.downloadFile;
+
+/**
+ * @Description: TODO
+ * @Date: 2025/2/21 16:40
+ * @Created: by ZZSLL
+ */
+
+@Service
+public class KingdeeService {
+
+ @Value("${collabora.file-storage-path}")
+ private String BASE_DIR;
+
+ @Autowired
+ private AuthService authService;
+
+ public String requestFile(String attPkId) {
+ try {
+ String accessToken = authService.initAccessToken();
+ URI newUri = new URI(authService.initBasePath() + "/ierp/kapi/v2/yem/yem_receipt/AttachmentsQueryAPI/Query");
+
+ ClientHttpRequest delegate = new SimpleClientHttpRequestFactory().createRequest(newUri, HttpMethod.POST);
+ delegate.getHeaders().add("access_token", accessToken);
+ delegate.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
+ Map requestBody = new HashMap<>();
+ requestBody.put("formId", "yem_testbill");
+ requestBody.put("pkId", attPkId);
+ requestBody.put("attachKey", "attachmentpanel");
+ String jsonBody = JSON.toJSONString(requestBody);
+ // 设置请求体
+ try (OutputStream os = delegate.getBody()) {
+ os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
+ }
+ ClientHttpResponse response = delegate.execute();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(response.getBody()));
+ StringBuilder responseBody = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ responseBody.append(line);
+ }
+ String savePath = "";
+ JSONObject result = JSON.parseObject(responseBody.toString());
+ if (result.containsKey("status") && result.getBooleanValue("status", false)) {
+ JSONArray data = result.getJSONArray("data");
+ if (data != null && !data.isEmpty()) {
+ JSONObject data0 = data.getJSONObject(0);
+ String url = data0.getString("url");
+ String name = data0.getString("name");
+ savePath = BASE_DIR + "/" + name;
+ downloadFile(url, savePath);
+ }
+ } else {
+ throw new AllKingdeeException(line);
+ }
+ return savePath;
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
index 94cbb2c..e35dce3 100644
--- a/src/main/resources/application.yaml
+++ b/src/main/resources/application.yaml
@@ -8,4 +8,24 @@ spring:
# http://47.99.175.155:59980/browser/dist/cool.html?WOPISrc=http://47.99.175.155:59981/wopi/files/test.docx&lang=zh-cn
-# http://:<端口>/browser/dist/cool.html?WOPISrc=http://<本机IP>:<服务端口>/wopi/files/<文件名>&lang=zh-cn
\ No newline at end of file
+# http://:<端口>/browser/dist/cool.html?WOPISrc=http://<本机IP>:<服务端口>/wopi/files/<文件名>&lang=zh-cn
+
+
+# http://192.168.3.211:9980/browser/dist/cool.html?WOPISrc=http://192.168.3.104:8080/wopi/files/2087131858671270912&lang=zh-cn
+ensign:
+ kingdee:
+ env: test
+ test-public-end-point: 'http://122.4.221.133:8022'
+ test-inner-end-point: 'http://10.64.112.152:8022'
+ prod-public-end-point: 'http://122.4.221.130:8022'
+ prod-inner-end-point: 'http://10.64.111.134:8022'
+ is-public: true
+ appToken:
+ appId: 'CRM'
+ appSecuret: 'yx.CRM.tksecurit@240924'
+ tenantid: 'yxzg-topview-dev'
+ accountId: '1878420900609526784'
+ language: 'zh_CN'
+ accessToken:
+ user: 'COSMIC'
+ usertype: 'UserName'
\ No newline at end of file