feat: use nacos

This commit is contained in:
zzs 2025-02-26 11:30:08 +08:00
parent 9926490203
commit c9ab19d68b
13 changed files with 303 additions and 172 deletions

View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.2</version>
<version>3.3.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>vin.vio</groupId>
@ -76,6 +76,12 @@
<artifactId>httpmime</artifactId>
<version>4.5.13</version> <!-- 请根据需要使用最新版本 -->
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2023.0.1.2</version>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,33 @@
package vin.vio.collaboraonline.config.filter;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
/**
* @Description: 设置需要使用的配置文件
* @Date: 2025/2/26 9:50
* @Created: by ZZSLL
*/
@Configuration
public class ProfileSplitFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String path = request.getRequestURI();
String[] parts = path.split("/");
if (parts.length > 1) {
String tenant = parts[1];
if (!"wopi".equals(tenant)) {
request.setAttribute("tenant", tenant);
} else {
request.setAttribute("tenant", "cmoc");
}
}
chain.doFilter(request, response);
}
}

View File

@ -0,0 +1,89 @@
package vin.vio.collaboraonline.config.tenant;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
/**
* @Description: 获取配置文件中内容保存为map供后续调用支持动态刷新配置文件
* @Date: 2025/2/26 9:57
* @Created: by ZZSLL
*/
@Component
public class TenantConfigManager {
private static final Log log = LogFactory.get();
// 存储各租户配置key租户名称
private final ConcurrentHashMap<String, Map<String, Object>> tenantConfigs = new ConcurrentHashMap<>();
@Autowired
private TenantProperties tenantProperties;
@Value("${spring.cloud.nacos.server-addr}")
private String nacosServerAddr;
@Value("${spring.cloud.nacos.config.group}")
private String group;
@Value("${spring.cloud.nacos.config.namespace}")
private String namespace;
@PostConstruct
public void init() throws Exception {
Properties properties = new Properties();
properties.put("serverAddr", nacosServerAddr);
properties.put("namespace", namespace);
ConfigService configService = NacosFactory.createConfigService(properties);
for (String tenant : tenantProperties.getList()) {
String dataId = "application-" + tenant + ".yml";
String content = configService.getConfig(dataId, group, 5000);
Map<String, Object> configMap = parseYaml(content);
tenantConfigs.put(tenant, configMap);
configService.addListener(dataId, group, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
Map<String, Object> updatedConfig = parseYaml(configInfo);
tenantConfigs.put(tenant, updatedConfig);
log.info("租户 " + tenant + " 配置已更新!");
}
});
}
}
private Map<String, Object> parseYaml(String yamlContent) {
if (yamlContent == null || yamlContent.trim().isEmpty()) {
return null;
}
Yaml yaml = new Yaml();
// YAML 转换为 Map结果结构和 YAML 文件结构一致
return yaml.load(yamlContent);
}
/**
* 根据租户名称获取对应的配置 Map
*/
public Map<String, Object> getConfigByTenant(String tenant) {
return tenantConfigs.get(tenant);
}
}

View File

@ -0,0 +1,26 @@
package vin.vio.collaboraonline.config.tenant;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @Description: 配置文件列表
* @Date: 2025/2/26 10:15
* @Created: by ZZSLL
*/
@Component
@ConfigurationProperties(prefix = "tenant")
public class TenantProperties {
private List<String> list;
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
}

View File

@ -5,11 +5,13 @@ import cn.hutool.log.LogFactory;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import vin.vio.collaboraonline.config.tenant.TenantConfigManager;
import vin.vio.collaboraonline.model.WopiFile;
import vin.vio.collaboraonline.service.FileService;
@ -24,22 +26,23 @@ import java.util.Map;
*/
@RestController
@RequestMapping("/wopi")
@RequestMapping("/{tenant}/wopi")
public class WopiController {
@Autowired
private FileService fileService;
@Value("${collabora.host-server-addr}")
private String host;
@Autowired
private TenantConfigManager manager;
private static final Log log = LogFactory.get();
// 检查文件信息
@GetMapping("/files/{fileId}")
public ResponseEntity<?> checkFileInfo(@PathVariable String fileId, @RequestParam(required = false) String access_token, HttpServletRequest request) {
public ResponseEntity<?> checkFileInfo(
@PathVariable String fileId,
@RequestParam(required = false) String access_token,
HttpServletRequest request) {
log.info("=========checkFileInfo===========start");
log.info("{} {}", request.getPathInfo(), request.getMethod());
log.info("{}", fileId);
@ -50,12 +53,14 @@ public class WopiController {
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(createCheckFileInfoResponse(file, fileId));
.body(createCheckFileInfoResponse(file, fileId, request));
}
// 获取文件内容
@GetMapping("/files/{fileId}/contents")
public ResponseEntity<Resource> getFile(@PathVariable String fileId, HttpServletRequest request) {
public ResponseEntity<Resource> getFile(
@PathVariable String fileId,
HttpServletRequest request) {
log.info("=========getFile===========start");
log.info("{} {}", request.getPathInfo(), request.getMethod());
log.info("{}", fileId);
@ -71,8 +76,9 @@ public class WopiController {
// 保存文件
@RequestMapping(value = "/files/{fileId}/contents", method = {RequestMethod.POST, RequestMethod.PUT})
public ResponseEntity<Void> putFile(
@PathVariable String fileId, InputStream contentStream, HttpServletRequest request) {
public ResponseEntity<Void> putFile(@PathVariable String fileId,
InputStream contentStream,
HttpServletRequest request) {
log.info("=========putFile===========start");
log.info("{} {}", request.getPathInfo(), request.getMethod());
log.info("{}", fileId);
@ -82,7 +88,17 @@ public class WopiController {
ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
private Map<String, Object> createCheckFileInfoResponse(WopiFile file, String fileId) {
private Map<String, Object> createCheckFileInfoResponse(WopiFile file, String fileId, HttpServletRequest request) {
String tenant = (String) request.getAttribute("tenant");
Map<String, Object> config = manager.getConfigByTenant(tenant);
String host = null;
if (config.containsKey("collabora") && config.get("collabora") instanceof Map<?, ?>) {
Map<String, Object> collabora = (Map<String, Object>) config.get("collabora");
host = (String) collabora.get("host");
}
log.info("=========createCheckFileInfoResponse===========start");
Map<String, Object> response = new LinkedHashMap<>();

View File

@ -4,6 +4,7 @@ package vin.vio.collaboraonline.kingdee;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
@ -18,8 +19,10 @@ 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.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import vin.vio.collaboraonline.config.tenant.TenantConfigManager;
import vin.vio.collaboraonline.exception.AllKingdeeException;
import java.io.IOException;
@ -35,48 +38,35 @@ import java.util.concurrent.TimeUnit;
@Service
public class AuthService {
@Autowired
private TenantConfigManager manager;
@Value("${kingdee.is-public}")
private Boolean isPublic;
@Value("${kingdee.test-public-end-point}")
private String testPublicEndPoint;
@Value("${kingdee.test-inner-end-point}")
private String testInnerEndPoint;
@Value("${kingdee.prod-public-end-point}")
private String prodPublicEndPoint;
@Value("${kingdee.prod-inner-end-point}")
private String prodInnerEndPoint;
@Value("${kingdee.env}")
private String env;
@Value("${kingdee.appToken.appId}")
private String appId;
@Value("${kingdee.appToken.appSecuret}")
private String appSecuret;
@Value("${kingdee.appToken.tenantid}")
private String tenantid;
@Value("${kingdee.appToken.accountId}")
private String accountId;
@Value("${kingdee.appToken.language}")
private String language;
@Value("${kingdee.accessToken.user}")
private String user;
@Value("${kingdee.accessToken.usertype}")
private String usertype;
@Autowired
private HttpServletRequest request;
public String initBasePath() {
Boolean isPublic = null;
String testPublicEndPoint = null;
String testInnerEndPoint = null;
String prodPublicEndPoint = null;
String prodInnerEndPoint = null;
String env = null;
String tenant = (String) request.getAttribute("tenant");
Map<String, Object> config = manager.getConfigByTenant(tenant);
if (config.containsKey("kingdee") && config.get("kingdee") instanceof Map<?,?>) {
Map<String, Object> kingdee = (Map<String, Object>) config.get("kingdee");
env = (String) kingdee.get("env");
testPublicEndPoint = (String) kingdee.get("test-public-end-point");
testInnerEndPoint = (String) kingdee.get("test-inner-end-point");
prodPublicEndPoint = (String) kingdee.get("prod-public-end-point");
prodInnerEndPoint = (String) kingdee.get("prod-inner-end-point");
isPublic = (Boolean) kingdee.get("is-public");
}
if ("test".equals(env)) {
if (isPublic) {
return testPublicEndPoint;
@ -97,9 +87,30 @@ public class AuthService {
}
public String initAccessToken() throws IOException, AllKingdeeException {
String tenant = (String) request.getAttribute("tenant");
Map<String, Object> config = manager.getConfigByTenant(tenant);
String appId = null;
String appSecuret = null;
String tenantid = null;
String accountId = null;
String language = null;
if (config.containsKey("kingdee") && config.get("kingdee") instanceof Map<?,?>) {
Map<String, Object> kingdee = (Map<String, Object>) config.get("kingdee");
if (kingdee.containsKey("appToken") && kingdee.get("appToken") instanceof Map<?,?>) {
Map<String, Object> appToken = (Map<String, Object>) kingdee.get("appToken");
appId = (String) appToken.get("appId");
appSecuret = (String) appToken.get("appSecuret");
tenantid = (String) appToken.get("tenantid");
accountId = (String) appToken.get("accountId");
language = (String) appToken.get("language");
}
}
final String END_POINT = initBasePath() + "/ierp/api/getAppToken.do";
HttpClient client = new DefaultHttpClient();
@ -144,6 +155,32 @@ public class AuthService {
Map<String, String> body = new HashMap<>();
String user = null;
String usertype = null;
String tenantid = null;
String accountId = null;
String language = null;
String tenant = (String) request.getAttribute("tenant");
Map<String, Object> config = manager.getConfigByTenant(tenant);
if (config.containsKey("kingdee") && config.get("kingdee") instanceof Map<?,?>) {
Map<String, Object> kingdee = (Map<String, Object>) config.get("kingdee");
if (kingdee.containsKey("accessToken") && kingdee.get("accessToken") instanceof Map<?,?>) {
Map<String, Object> accessToken = (Map<String, Object>) kingdee.get("accessToken");
user = (String) accessToken.get("user");
usertype = (String) accessToken.get("usertype");
}
if (kingdee.containsKey("appToken") && kingdee.get("appToken") instanceof Map<?,?>) {
Map<String, Object> appTokenParams = (Map<String, Object>) kingdee.get("appToken");
tenantid = (String) appTokenParams.get("tenantid");
accountId = (String) appTokenParams.get("accountId");
language = (String) appTokenParams.get("language");
}
}
body.put("user", user);
body.put("apptoken", appToken);
body.put("tenantid", tenantid);

View File

@ -1,11 +1,8 @@
package vin.vio.collaboraonline.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import vin.vio.collaboraonline.model.WopiFile;
@ -13,7 +10,6 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.nio.file.*;
/**

View File

@ -1,8 +1,10 @@
package vin.vio.collaboraonline.service;
import cn.hutool.log.Log;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
@ -10,6 +12,7 @@ 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.config.tenant.TenantConfigManager;
import vin.vio.collaboraonline.exception.AllKingdeeException;
import vin.vio.collaboraonline.kingdee.AuthService;
@ -31,22 +34,42 @@ import static cn.hutool.http.HttpUtil.downloadFile;
@Service
public class KingdeeService {
@Value("${collabora.file-storage-path}")
private String BASE_DIR;
@Value("${kingdee.attachment-query-uri}")
private String attachmentQueryURI;
@Value("${kingdee.bill.formId}")
private String fromId;
@Value("${kingdee.bill.attachKey}")
private String attachKey;
@Autowired
private TenantConfigManager manager;
@Autowired
private AuthService authService;
@Autowired
private HttpServletRequest request;
private final static Log log = Log.get();
public String requestFile(String attPkId) {
String BASE_DIR = null;
String attachmentQueryURI = null;
String fromId = null;
String attachKey = null;
String tenant = (String) request.getAttribute("tenant");
Map<String, Object> config = manager.getConfigByTenant(tenant);
if (config.containsKey("collabora") && config.get("collabora") instanceof Map<?,?>) {
Map<String, Object> collabora = (Map<String, Object>) config.get("collabora");
BASE_DIR = (String) collabora.get("file-storage-path");
}
if (config.containsKey("kingdee") && config.get("kingdee") instanceof Map<?,?>) {
Map<String, Object> kingdee = (Map<String, Object>) config.get("kingdee");
attachmentQueryURI = (String) kingdee.get("attachment-query-uri");
if (kingdee.containsKey("bill") && kingdee.get("bill") instanceof Map<?,?>) {
Map<String, Object> bill = (Map<String, Object>) kingdee.get("bill");
fromId = (String) bill.get("formId");
attachKey = (String) bill.get("attachKey");
}
}
try {
String accessToken = authService.initAccessToken();
URI newUri = new URI(authService.initBasePath() + attachmentQueryURI);
@ -72,6 +95,7 @@ public class KingdeeService {
}
String savePath = "";
JSONObject result = JSON.parseObject(responseBody.toString());
log.info(JSON.toJSONString(result));
if (result.containsKey("status") && result.getBooleanValue("status", false)) {
JSONArray data = result.getJSONArray("data");
if (data != null && !data.isEmpty()) {

View File

@ -1,26 +0,0 @@
kingdee:
env: test
test-public-end-point: 'https://srm-dev.cmoc.cloud:8022'
test-inner-end-point: ''
prod-public-end-point: ''
prod-inner-end-point: ''
is-public: true
appToken:
appId: 'OA'
appSecuret: 'Cmoc@OA2024!#@..'
tenantid: 'cmocdev'
accountId: '2117884374501299200'
language: 'zh_CN'
accessToken:
user: '18791337254'
usertype: 'Mobile'
attachment-query-uri: /ierp/kapi/v2/yem/yem_base/AttachmentsQueryAPI/Query
bill:
formId: 'yem_webofficemodel2'
attachKey: 'yem_attachmentpanelap'
collabora:
host-server-addr: https://web-api.wmyun.com/cmoc
file-storage-path: /work/projects/collabora-api/cmoc/file

View File

@ -1,26 +0,0 @@
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'
attachment-query-uri: /ierp/kapi/v2/yem/yem_receipt/AttachmentsQueryAPI/Query
bill:
formId: 'yem_testbill'
attachKey: 'attachmentpanel'
collabora:
host-server-addr: https://web-api.wmyun.com/ensign
file-storage-path: /work/projects/collabora-api/ensign/file

View File

@ -1,26 +0,0 @@
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'
attachment-query-uri: /ierp/kapi/v2/yem/yem_receipt/AttachmentsQueryAPI/Query
bill:
formId: 'yem_testbill'
attachKey: 'attachmentpanel'
collabora:
host-server-addr: http://192.168.3.104:8080
file-storage-path: E:\Code\CollaboraOnline\files

View File

@ -1,26 +0,0 @@
kingdee:
env: test
test-public-end-point: 'http://39.98.69.61:22284'
test-inner-end-point: ''
prod-public-end-point: ''
prod-inner-end-point: ''
is-public: true
appToken:
appId: 'yem_test'
appSecuret: 'Yem.test.20250224'
tenantid: 'ierp'
accountId: '2155968549812699136'
language: 'zh_CN'
accessToken:
user: '18791337254'
usertype: 'Mobile'
attachment-query-uri: '/ierp/kapi/v2/yem/yem_ges/AttachmentsQueryAPI/Query'
bill:
formId: 'yem_sex_contract'
attachKey: 'attachmentpanel'
collabora:
host-server-addr: https://web-api.wmyun.com/yem
file-storage-path: /work/projects/collabora-api/yem/file

View File

@ -2,7 +2,15 @@ spring:
application:
name: CollaboraOnline
profiles:
active: ensign
active: local
cloud:
nacos:
config:
namespace: office
group: ATTACHMENT_VIA_GROUP
server-addr: 192.168.3.100:8848
config:
import: nacos:application-tenant.yml
# http://192.168.3.211:9980/browser/dist/cool.html?WOPISrc=http://192.168.3.104:8080/wopi/files/2087131858671270912&lang=zh-cn