forked from Gitlink/microservices
Compare commits
286 Commits
master
...
dev_monito
| Author | SHA1 | Date |
|---|---|---|
|
|
4c62b8c1f5 | |
|
|
e74cbd5d8a | |
|
|
c52e178f4d | |
|
|
69d627f8e5 | |
|
|
4ccda26fd5 | |
|
|
7f07d226da | |
|
|
7a28e98b5d | |
|
|
7dd24d43bc | |
|
|
10fe8855d5 | |
|
|
65a5089ddc | |
|
|
ebab84d04b | |
|
|
ee7f36bb8f | |
|
|
0450126d84 | |
|
|
419548cb52 | |
|
|
c433080296 | |
|
|
850a477d17 | |
|
|
95b35d1847 | |
|
|
9394e9f9a0 | |
|
|
14bdda20a1 | |
|
|
cb5cc6e3b4 | |
|
|
93aca87a0b | |
|
|
9300a8f092 | |
|
|
4ff20b445b | |
|
|
9d110b608d | |
|
|
561363ea1b | |
|
|
2116f7cadd | |
|
|
afc7c9f20a | |
|
|
3fdfee7bd5 | |
|
|
4513ae20d6 | |
|
|
4ada9fc829 | |
|
|
2eb21023e4 | |
|
|
f46b3c40b3 | |
|
|
e8bdc8fc92 | |
|
|
3a0f0d84c5 | |
|
|
569eaa14ff | |
|
|
3fad2b311f | |
|
|
10323b94f1 | |
|
|
33e77ed05b | |
|
|
7c785d4743 | |
|
|
c890870e09 | |
|
|
07a70f12ce | |
|
|
5daaa3d54a | |
|
|
e87484b1e1 | |
|
|
c22addc4e5 | |
|
|
43d2ce4231 | |
|
|
fca7e4e502 | |
|
|
e92c412c4e | |
|
|
f94a885908 | |
|
|
5776ddd748 | |
|
|
661709efaf | |
|
|
7760f5afb3 | |
|
|
575170a801 | |
|
|
be80d64dd5 | |
|
|
6f1068f082 | |
|
|
3589a9b51a | |
|
|
e9e3852364 | |
|
|
1aabdcf752 | |
|
|
44f0bfb4c8 | |
|
|
ab58222217 | |
|
|
a3ccf62c10 | |
|
|
a4e92ca636 | |
|
|
8bfd8c6e1a | |
|
|
3e4c801cbd | |
|
|
c76b6efa20 | |
|
|
0d833872b6 | |
|
|
4782b8c0c0 | |
|
|
e792599fc3 | |
|
|
2e9c3d0f9d | |
|
|
b7e68454ac | |
|
|
e3921d833b | |
|
|
723825064c | |
|
|
02791388bd | |
|
|
5d14d5e56a | |
|
|
e3ddab5ceb | |
|
|
587a2707a7 | |
|
|
992c17b4c8 | |
|
|
0aa96e853a | |
|
|
34ab56eb8a | |
|
|
bdbd2da88d | |
|
|
30f8ce8184 | |
|
|
7fbfbdaf8d | |
|
|
93ed7838e6 | |
|
|
68988926b9 | |
|
|
5485d39894 | |
|
|
2516ba038e | |
|
|
e80d7f8a6f | |
|
|
bb9b4f05da | |
|
|
4bbf3c91e2 | |
|
|
00bde1ad9a | |
|
|
092d566de4 | |
|
|
27c5e64e1a | |
|
|
71f4e4bc8f | |
|
|
8c8e13a5e1 | |
|
|
82c74b9184 | |
|
|
290fc64c88 | |
|
|
b0aede3f93 | |
|
|
902f961469 | |
|
|
e904d854f6 | |
|
|
3dbdef7ab8 | |
|
|
072e85de82 | |
|
|
8f48c1030a | |
|
|
9380081443 | |
|
|
0646a3b773 | |
|
|
43e75440d5 | |
|
|
0ca345d200 | |
|
|
83c1457c50 | |
|
|
3f208de48a | |
|
|
bce79534bd | |
|
|
f402ec1748 | |
|
|
7de259d088 | |
|
|
1c9bc630d8 | |
|
|
c13748d494 | |
|
|
69e789d856 | |
|
|
02f215c2e4 | |
|
|
d1076e48d5 | |
|
|
b25411e35c | |
|
|
1f3d65fd39 | |
|
|
3f155f2270 | |
|
|
ee77bdb8a1 | |
|
|
631f6752a6 | |
|
|
39a8dde543 | |
|
|
0f0a639bf4 | |
|
|
cf2c5cffa3 | |
|
|
b89c235df3 | |
|
|
2d5d43b37e | |
|
|
32b58df5d1 | |
|
|
555ef0fc80 | |
|
|
46cbaccf64 | |
|
|
ebf1dc53cf | |
|
|
e6dadf2ccd | |
|
|
71cf4fb6fc | |
|
|
eed4b9d9eb | |
|
|
cad9ea1247 | |
|
|
02e369849d | |
|
|
f7e9d9350e | |
|
|
356b85fd35 | |
|
|
19a32e2f7c | |
|
|
b2f9921664 | |
|
|
2567386baa | |
|
|
8e10fee65f | |
|
|
310b423ec9 | |
|
|
705823ec3f | |
|
|
172e0ee92e | |
|
|
726ece8af9 | |
|
|
82f180d31c | |
|
|
e91ee14d63 | |
|
|
10a1b3f5cf | |
|
|
7f22a2c6ec | |
|
|
9c76980bdc | |
|
|
a861d69061 | |
|
|
53274c3b0e | |
|
|
32ded69b77 | |
|
|
36e9d84dd8 | |
|
|
4e0d281bf7 | |
|
|
fbcbe63ad4 | |
|
|
48e0510bb3 | |
|
|
3726e4b294 | |
|
|
335d05d2c3 | |
|
|
fa4ee4526b | |
|
|
405b2e07c1 | |
|
|
c6fd9a1c9d | |
|
|
bfbaa3491d | |
|
|
c97b64f3bc | |
|
|
83c8d5fe3e | |
|
|
7cff154598 | |
|
|
d0fcf1fbce | |
|
|
3cf7ced976 | |
|
|
ddb1a06acc | |
|
|
0c94e636e1 | |
|
|
0f2d37babe | |
|
|
6e72d6f762 | |
|
|
d330e7a56d | |
|
|
29dbc84989 | |
|
|
f055d0f28e | |
|
|
20ce451a9a | |
|
|
629822dcb9 | |
|
|
e7ca96f280 | |
|
|
f9956c305e | |
|
|
d13b38e980 | |
|
|
45c84d17b6 | |
|
|
71ec75c3e5 | |
|
|
0d0b0072c3 | |
|
|
8f84d425c8 | |
|
|
1cb6c3e758 | |
|
|
17a911c54e | |
|
|
adc86b04c9 | |
|
|
cd19bd94cc | |
|
|
dc814cffff | |
|
|
92bfd2c7f2 | |
|
|
6a71629784 | |
|
|
1e016300c7 | |
|
|
fdf61667f7 | |
|
|
22f350510c | |
|
|
2566f119d3 | |
|
|
19718b6123 | |
|
|
3fa2daac28 | |
|
|
2d304cfae0 | |
|
|
1f2f48c120 | |
|
|
19e298b67a | |
|
|
f70681d783 | |
|
|
8abb5a38bd | |
|
|
9eb10143f7 | |
|
|
9865c8bad9 | |
|
|
bc92fb8419 | |
|
|
a25048faad | |
|
|
8c068c4b79 | |
|
|
735d7fd9e9 | |
|
|
705a9241b6 | |
|
|
03b7c170e4 | |
|
|
0c0f27810e | |
|
|
4fd5c1cc4d | |
|
|
65a5b5d081 | |
|
|
e97b972f31 | |
|
|
828901d322 | |
|
|
33185a1d0c | |
|
|
29b6b2bbae | |
|
|
2883029641 | |
|
|
5eed69522c | |
|
|
c5d99153b8 | |
|
|
6f4a10f1cb | |
|
|
c6f58972a6 | |
|
|
53795b1b88 | |
|
|
1f653894cd | |
|
|
5af3df62ee | |
|
|
fde9893840 | |
|
|
e44f63a4c6 | |
|
|
6d47364cca | |
|
|
128a107f8f | |
|
|
65aaa7df5b | |
|
|
b1da0ba006 | |
|
|
ad3625a823 | |
|
|
115a3cbe12 | |
|
|
c9d08ef3d5 | |
|
|
3f795fadb5 | |
|
|
672476ba53 | |
|
|
1f55a7835e | |
|
|
0b16dbf195 | |
|
|
8111f6db61 | |
|
|
ae073b68bc | |
|
|
14072b1dff | |
|
|
12eecde9c4 | |
|
|
66e1b9aca6 | |
|
|
93e56ed555 | |
|
|
13d5e7aa46 | |
|
|
dc9a537feb | |
|
|
3d5d6bfc6e | |
|
|
bac9eeda5f | |
|
|
18f89d1b8e | |
|
|
c3b5dcafba | |
|
|
a0aec9bf88 | |
|
|
a511f39a13 | |
|
|
75f828b76c | |
|
|
4b1042c25d | |
|
|
e9c41768e1 | |
|
|
15aa7016b9 | |
|
|
f96cee3f4a | |
|
|
055b26ee29 | |
|
|
368a45e8b2 | |
|
|
2c5f0518ca | |
|
|
06fbbf7208 | |
|
|
6613950ff8 | |
|
|
8184eb2401 | |
|
|
213aee5587 | |
|
|
274af358dd | |
|
|
58bf8326c5 | |
|
|
5e19e53b94 | |
|
|
2be36ca12e | |
|
|
ad405c912e | |
|
|
6ef1fafac8 | |
|
|
39d43e3d68 | |
|
|
1eefa65c32 | |
|
|
c6b4a1bd80 | |
|
|
21ba1ce6bd | |
|
|
dd870b3cd3 | |
|
|
417d440549 | |
|
|
67b2e9ce7c | |
|
|
32b83749e2 | |
|
|
010d5e5354 | |
|
|
94e0be0e71 | |
|
|
2845d19aae | |
|
|
97b1c9437c | |
|
|
b0f9e06e18 | |
|
|
f58af4b0b5 | |
|
|
78cbd4b0ee | |
|
|
fca8490bdd | |
|
|
616bf1229f |
|
|
@ -14,6 +14,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件服务
|
* 文件服务
|
||||||
|
|
@ -34,6 +35,17 @@ public interface RemoteFileService {
|
||||||
@RequestParam("hierarchy") String hierarchy,
|
@RequestParam("hierarchy") String hierarchy,
|
||||||
@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base64 图片上传(HashMap 版本)
|
||||||
|
*/
|
||||||
|
@PostMapping(value = "/upload/base64")
|
||||||
|
R<SysFileInfo> uploadBase64(
|
||||||
|
@RequestBody Map<String, Object> params,
|
||||||
|
@RequestParam("type") String type,
|
||||||
|
@RequestParam("hierarchy") String hierarchy,
|
||||||
|
@RequestHeader(SecurityConstants.FROM_SOURCE) String source
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据文件Id列表获取文件列表
|
* 根据文件Id列表获取文件列表
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@ package com.microservices.system.api;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.microservices.common.core.constant.ServiceNameConstants;
|
import com.microservices.common.core.constant.ServiceNameConstants;
|
||||||
|
import com.microservices.common.core.constant.TokenConstants;
|
||||||
import com.microservices.system.api.factory.RemoteGatewayFallbackFactory;
|
import com.microservices.system.api.factory.RemoteGatewayFallbackFactory;
|
||||||
|
import com.microservices.system.api.model.GraphqlQueryVo;
|
||||||
import feign.Response;
|
import feign.Response;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
@ -28,6 +28,14 @@ public interface RemoteGatewayService {
|
||||||
@PostMapping("/sentinel/auth/login")
|
@PostMapping("/sentinel/auth/login")
|
||||||
Response loginSentinel(@RequestParam("username") String username, @RequestParam("password") String password);
|
Response loginSentinel(@RequestParam("username") String username, @RequestParam("password") String password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录Rancher
|
||||||
|
*
|
||||||
|
* @return 响应
|
||||||
|
*/
|
||||||
|
@PostMapping("/rancher/v3-public/localProviders/local?action=login")
|
||||||
|
Response loginRancher(@RequestBody JSONObject loginBody);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录Nacos
|
* 登录Nacos
|
||||||
*
|
*
|
||||||
|
|
@ -43,4 +51,45 @@ public interface RemoteGatewayService {
|
||||||
*/
|
*/
|
||||||
@PostMapping("/portainer/api/auth")
|
@PostMapping("/portainer/api/auth")
|
||||||
Response loginPortainer(@RequestBody JSONObject loginBody);
|
Response loginPortainer(@RequestBody JSONObject loginBody);
|
||||||
|
|
||||||
|
@GetMapping("/prometheus/api/v1/query")
|
||||||
|
JSONObject getPrometheusQueryRes(@RequestParam("query") String query,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/prometheus/api/v1/query_range")
|
||||||
|
JSONObject getPrometheusQueryRangeRes(@RequestParam("query") String query,
|
||||||
|
@RequestParam("step") Long step,
|
||||||
|
@RequestParam("start") Long start,
|
||||||
|
@RequestParam("end") Long end,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@PostMapping("/skywalking/graphql")
|
||||||
|
JSONObject executeSkywalkingGql(@RequestBody GraphqlQueryVo gqlBody);
|
||||||
|
|
||||||
|
@GetMapping("/sentinel/app/briefinfos.json")
|
||||||
|
JSONObject getSentinelAppList(@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/nacos/v1/ns/catalog/services?pageNo=1&pageSize=999")
|
||||||
|
JSONObject getNacosServiceList(@RequestParam("serviceNameParam") String serviceNameParam, @RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/nacos/v1/cs/configs?types=yaml&search=blur&group=&pageNo=1&pageSize=10")
|
||||||
|
JSONObject getGatewayNacosConfigList(@RequestParam("dataId") String dataId, @RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/nacos/v1/cs/listener")
|
||||||
|
JSONObject getNacosConfigList(@RequestParam("ip") String ip, @RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/nacos/v1/cs/configs")
|
||||||
|
String getNacosConfigDetail(@RequestParam("dataId") String dataId, @RequestParam("group") String group, @RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@PostMapping(value = "/nacos/v1/cs/configs", consumes = {"application/x-www-form-urlencoded"})
|
||||||
|
Response updateNacosConfig(Map<String, ?> formParams, @RequestHeader(TokenConstants.AUTHENTICATION) String userKey);
|
||||||
|
|
||||||
|
@PostMapping("/es/{esIndex}/_search")
|
||||||
|
JSONObject executeElasticsearchQuery(@PathVariable("esIndex") String esIndex, @RequestBody JSONObject esBody);
|
||||||
|
|
||||||
|
@PostMapping("/es/{esIndex}/_doc/{docId}/_update")
|
||||||
|
JSONObject executeElasticsearchUpdate(@PathVariable("esIndex") String esIndex,@PathVariable("docId") String docId, @RequestBody JSONObject esBody);
|
||||||
|
|
||||||
|
@PostMapping("/gns/notification/gitlink")
|
||||||
|
JSONObject sendNotification(@RequestBody JSONObject body);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
package com.microservices.system.api;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.constant.Constants;
|
||||||
|
import com.microservices.common.core.constant.SecurityConstants;
|
||||||
|
import com.microservices.common.core.constant.ServiceNameConstants;
|
||||||
|
import com.microservices.common.core.constant.TokenConstants;
|
||||||
|
import com.microservices.system.api.factory.RemoteGatewayFallbackFactory;
|
||||||
|
import com.microservices.system.api.factory.RemoteRancherFallbackFactory;
|
||||||
|
import feign.Response;
|
||||||
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网关
|
||||||
|
*
|
||||||
|
* @author microservices
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@FeignClient(contextId = "RemoteRancherService", value = ServiceNameConstants.GATEWAY_SERVICE, fallbackFactory = RemoteRancherFallbackFactory.class)
|
||||||
|
public interface RemoteRancherService {
|
||||||
|
@GetMapping("/rancher/v3/clusters/{cluster_id}/namespaces")
|
||||||
|
Response getK8sNamespaceList(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/apps.daemonsets?exclude=metadata.managedFields")
|
||||||
|
Response getK8sDaemonsetsList(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/apps.deployments?exclude=metadata.managedFields")
|
||||||
|
Response getK8sDeployList(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/apps.statefulsets?exclude=metadata.managedFields")
|
||||||
|
Response getK8sStatefulList(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/nodes?exclude=metadata.managedFields")
|
||||||
|
Response getK8sClusterNodeList(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/{fullKind}/{namespace}/{applicationName}")
|
||||||
|
Response getK8sApplicationDetail(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@PathVariable("fullKind") String fullKind,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/pods/{namespace}")
|
||||||
|
Response getK8sPodListByNamespace(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/pods")
|
||||||
|
Response getK8sPodList(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/services/{nginxApplicationId}")
|
||||||
|
Response getK8sServiceByApplicationId(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@PathVariable("nginxApplicationId") String nginxApplicationId,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@DeleteMapping("/rancher/v1/pods/{namespace}/{podName}")
|
||||||
|
Response deletePod(@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("podName") String podName,
|
||||||
|
@RequestBody JSONObject deletePodBody,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@PutMapping("/rancher/v1/{fullKind}/{namespace}/{applicationName}")
|
||||||
|
Response updateK8sApplication(@PathVariable("fullKind") String fullKind,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName,
|
||||||
|
@RequestBody JSONObject applicationDetail,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String userKey);
|
||||||
|
|
||||||
|
@PostMapping(value = "/rancher/v1/{fullKind}", consumes = {Constants.YAML_CONTENT_TYPE})
|
||||||
|
Response createK8sApplication(@PathVariable("fullKind") String fullName,
|
||||||
|
@RequestBody String yamlContent,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String userKey);
|
||||||
|
|
||||||
|
@PostMapping(value = "/rancher/v1/management.cattle.io.clusters/{cluster_id}?action=apply")
|
||||||
|
Response applyK8sYaml(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@RequestBody JSONObject yamlContent,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String userKey);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/apis/apps/v1/namespaces/{namespace}/{kindName}/{applicationName}")
|
||||||
|
Response getApplicationYamlFile(@PathVariable("kindName") String kindName,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@PutMapping(value = "/rancher/v1/{fullKind}/{namespace}/{applicationName}", consumes = {Constants.YAML_CONTENT_TYPE})
|
||||||
|
Response editK8sApplication(@PathVariable("fullKind") String fullKind,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName,
|
||||||
|
@RequestBody String yamlContent,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@DeleteMapping("/rancher/v1/{fullKind}/{namespace}/{applicationName}")
|
||||||
|
Response deleteApplication(@PathVariable("fullKind") String fullKind,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/v1/configmaps/{namespace}")
|
||||||
|
Response getK8sConfigmapByNamespace(@PathVariable("namespace") String namespace,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/v1/secrets/{namespace}")
|
||||||
|
Response getK8sSecretByNamespace(@PathVariable("namespace") String namespace,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/services/{namespace}")
|
||||||
|
Response getK8sServiceByNamespace(@PathVariable("cluster_id") String cluster_id,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
|
||||||
|
|
||||||
|
@DeleteMapping("/rancher/v1/services/{serviceId}")
|
||||||
|
Response deleteK8sService(@PathVariable("serviceId") String serviceId,@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件服务降级处理
|
* 文件服务降级处理
|
||||||
|
|
@ -36,6 +37,11 @@ public class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileServ
|
||||||
return R.fail("上传文件失败:" + throwable.getMessage());
|
return R.fail("上传文件失败:" + throwable.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public R<SysFileInfo> uploadBase64(Map<String, Object> params, String type, String hierarchy, String source) {
|
||||||
|
return R.fail("上传base64文件失败:" + throwable.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public R<List<SysFileInfo>> getFileList(String fileIds) {
|
public R<List<SysFileInfo>> getFileList(String fileIds) {
|
||||||
return R.fail("获取文件列表失败:" + throwable.getMessage());
|
return R.fail("获取文件列表失败:" + throwable.getMessage());
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package com.microservices.system.api.factory;
|
package com.microservices.system.api.factory;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.exception.ServiceException;
|
||||||
import com.microservices.system.api.RemoteGatewayService;
|
import com.microservices.system.api.RemoteGatewayService;
|
||||||
|
import com.microservices.system.api.model.GraphqlQueryVo;
|
||||||
import feign.Response;
|
import feign.Response;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
@ -25,7 +27,12 @@ public class RemoteGatewayFallbackFactory implements FallbackFactory<RemoteGatew
|
||||||
return new RemoteGatewayService() {
|
return new RemoteGatewayService() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response loginSentinel(String password, String username) {
|
public Response loginSentinel(String username, String password) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response loginRancher(JSONObject loginBody) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,7 +43,66 @@ public class RemoteGatewayFallbackFactory implements FallbackFactory<RemoteGatew
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response loginPortainer(JSONObject loginBody) {
|
public Response loginPortainer(JSONObject loginBody) {
|
||||||
System.out.println(throwable.getMessage());
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getPrometheusQueryRes(String query, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getPrometheusQueryRangeRes(String query, Long step, Long start, Long end, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject executeSkywalkingGql(GraphqlQueryVo gqlBody) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getSentinelAppList(String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getNacosServiceList(String serviceNameParam, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getGatewayNacosConfigList(String dataId, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getNacosConfigList(String ip, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNacosConfigDetail(String dataId, String group, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response updateNacosConfig(Map<String, ?> formParams, String userKey) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject executeElasticsearchQuery(String esIndex, JSONObject esBody) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject executeElasticsearchUpdate(String esIndex, String docId, JSONObject esBody) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject sendNotification(JSONObject body) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
package com.microservices.system.api.factory;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.exception.ServiceException;
|
||||||
|
import com.microservices.system.api.RemoteGatewayService;
|
||||||
|
import com.microservices.system.api.RemoteRancherService;
|
||||||
|
import com.microservices.system.api.utils.FeignUtils;
|
||||||
|
import feign.FeignException;
|
||||||
|
import feign.Response;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户服务降级处理
|
||||||
|
*
|
||||||
|
* @author microservices
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class RemoteRancherFallbackFactory implements FallbackFactory<RemoteRancherService> {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(RemoteRancherFallbackFactory.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RemoteRancherService create(Throwable throwable) {
|
||||||
|
log.error("Rancher服务调用失败:{}", throwable.getMessage());
|
||||||
|
|
||||||
|
return new RemoteRancherService() {
|
||||||
|
@Override
|
||||||
|
public Response getK8sNamespaceList(String cluster_id, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getK8sDaemonsetsList(String cluster_id, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getK8sDeployList(String cluster_id, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getK8sStatefulList(String cluster_id, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getK8sClusterNodeList(String cluster_id, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getK8sApplicationDetail(String cluster_id, String fullKind, String namespace, String applicationName, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getK8sPodListByNamespace(String cluster_id, String namespace, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getK8sPodList(String cluster_id, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getK8sServiceByApplicationId(String cluster_id, String nginxApplicationId, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response deletePod(String namespace, String podName, JSONObject deletePodBody, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response updateK8sApplication(String fullKind, String namespace, String applicationName, JSONObject applicationDetail, String userKey) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response createK8sApplication(String fullName, String yamlContent, String userKey) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response applyK8sYaml(String cluster_id, JSONObject yamlContent, String userKey) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getApplicationYamlFile(String kindName, String namespace, String applicationName, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response editK8sApplication(String fullKind, String namespace, String applicationName, String yamlContent, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response deleteApplication(String fullKind, String namespace, String applicationName, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getK8sConfigmapByNamespace(String namespace, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getK8sSecretByNamespace(String namespace, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getK8sServiceByNamespace(String cluster_id, String namespace, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response deleteK8sService(String serviceId, String token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.microservices.system.api.model;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class GraphqlQueryVo {
|
||||||
|
String operationName;
|
||||||
|
String query;
|
||||||
|
JSONObject variables;
|
||||||
|
}
|
||||||
|
|
@ -3,20 +3,24 @@ package com.microservices.system.api.utils;
|
||||||
import com.microservices.common.core.domain.R;
|
import com.microservices.common.core.domain.R;
|
||||||
import com.microservices.common.core.exception.ServiceException;
|
import com.microservices.common.core.exception.ServiceException;
|
||||||
import com.microservices.common.core.utils.StringUtils;
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
|
import feign.Response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author otto
|
* @author otto
|
||||||
*/
|
*/
|
||||||
public class FeignUtils {
|
public class FeignUtils {
|
||||||
public static <T> T getReturnData(R<T> result){
|
public static <T> T getReturnData(R<T> result) {
|
||||||
if (StringUtils.isNull(result)) {
|
if (StringUtils.isNull(result)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R.FAIL == result.getCode())
|
if (R.FAIL == result.getCode()) {
|
||||||
{
|
|
||||||
throw new ServiceException(result.getMsg());
|
throw new ServiceException(result.getMsg());
|
||||||
}
|
}
|
||||||
return result.getData();
|
return result.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Boolean isSuccess(Response response) {
|
||||||
|
return response != null && response.status() >= 200 && response.status() < 300;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
package com.microservices.system.api.utils;
|
||||||
|
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
public class StandardMultipartFile implements MultipartFile {
|
||||||
|
|
||||||
|
private final byte[] content;
|
||||||
|
private final String name;
|
||||||
|
private final String originalFilename;
|
||||||
|
private final String contentType;
|
||||||
|
|
||||||
|
public StandardMultipartFile(byte[] content, String name, String originalFilename, String contentType) {
|
||||||
|
this.content = content != null ? content : new byte[0];
|
||||||
|
this.name = name;
|
||||||
|
this.originalFilename = originalFilename;
|
||||||
|
this.contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOriginalFilename() {
|
||||||
|
return originalFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return content.length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getSize() {
|
||||||
|
return content.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBytes() throws IOException {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
return new ByteArrayInputStream(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void transferTo(File dest) throws IOException, IllegalStateException {
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(dest)) {
|
||||||
|
fos.write(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,3 +6,4 @@ com.microservices.system.api.factory.RemoteCmsFallbackFactory
|
||||||
com.microservices.system.api.factory.RemoteZoneFallbackFactory
|
com.microservices.system.api.factory.RemoteZoneFallbackFactory
|
||||||
com.microservices.system.api.factory.RemotePmsFallbackFactory
|
com.microservices.system.api.factory.RemotePmsFallbackFactory
|
||||||
com.microservices.system.api.factory.RemoteGatewayFallbackFactory
|
com.microservices.system.api.factory.RemoteGatewayFallbackFactory
|
||||||
|
com.microservices.system.api.factory.RemoteRancherFallbackFactory
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Tomcat
|
# Tomcat
|
||||||
server:
|
server:
|
||||||
port: 9110
|
port: 8080
|
||||||
|
|
||||||
# Spring
|
# Spring
|
||||||
spring:
|
spring:
|
||||||
|
|
|
||||||
|
|
@ -213,6 +213,11 @@ public class CacheConstants {
|
||||||
*/
|
*/
|
||||||
public final static String SENTINEL_TOKEN = "sentinel_token";
|
public final static String SENTINEL_TOKEN = "sentinel_token";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rancher Token缓存Key
|
||||||
|
*/
|
||||||
|
public final static String RANCHER_TOKEN = "rancher_token";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nacos Token缓存Key
|
* Nacos Token缓存Key
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@ package com.microservices.common.core.constant;
|
||||||
*
|
*
|
||||||
* @author microservices
|
* @author microservices
|
||||||
*/
|
*/
|
||||||
public class Constants
|
public class Constants {
|
||||||
{
|
|
||||||
/**
|
/**
|
||||||
* UTF-8 字符集
|
* UTF-8 字符集
|
||||||
*/
|
*/
|
||||||
|
|
@ -125,6 +124,10 @@ public class Constants
|
||||||
* JSON类型
|
* JSON类型
|
||||||
*/
|
*/
|
||||||
public static final String JSON_CONTENT_TYPE = "application/json";
|
public static final String JSON_CONTENT_TYPE = "application/json";
|
||||||
|
/**
|
||||||
|
* Yaml类型
|
||||||
|
*/
|
||||||
|
public static final String YAML_CONTENT_TYPE = "application/yaml";
|
||||||
/**
|
/**
|
||||||
* 文本类型
|
* 文本类型
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,11 @@ public class SecurityConstants
|
||||||
*/
|
*/
|
||||||
public static final String USER_KEY = "user_key";
|
public static final String USER_KEY = "user_key";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户Token
|
||||||
|
*/
|
||||||
|
public static final String TOKEN = "token";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组织ID
|
* 组织ID
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,16 @@ public class TokenConstants {
|
||||||
* Sentinel令牌标识
|
* Sentinel令牌标识
|
||||||
*/
|
*/
|
||||||
public static final String Sentinel_Token_Key = "sentinel_dashboard_cookie";
|
public static final String Sentinel_Token_Key = "sentinel_dashboard_cookie";
|
||||||
|
/**
|
||||||
|
* Rancher令牌标识
|
||||||
|
*/
|
||||||
|
public static final String Rancher_Cookie_Token_Key = "R_SESS";
|
||||||
|
/**
|
||||||
|
* Portainer令牌标识
|
||||||
|
*/
|
||||||
public static final String Portainer_Token_Key = "portainer_api_key";
|
public static final String Portainer_Token_Key = "portainer_api_key";
|
||||||
/**
|
/**
|
||||||
* Sentinel令牌标识
|
* Nacos令牌标识
|
||||||
*/
|
*/
|
||||||
public static final String Nacos_Token_Key = "Accesstoken";
|
public static final String Nacos_Token_Key = "Accesstoken";
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.microservices.common.core.threadPool;
|
package com.microservices.common.core.threadPool;
|
||||||
|
|
||||||
|
import com.microservices.common.core.constant.TokenConstants;
|
||||||
import com.microservices.common.core.context.SecurityContextHolder;
|
import com.microservices.common.core.context.SecurityContextHolder;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
@ -37,6 +38,9 @@ public class ThreadPoolExecutorWrap extends ThreadPoolExecutor {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
if(contextValue != null&&contextValue.containsKey("user_key")){
|
||||||
|
contextValue.put(TokenConstants.AUTHENTICATION, contextValue.get("user_key"));
|
||||||
|
}
|
||||||
SecurityContextHolder.setLocalMap(contextValue);
|
SecurityContextHolder.setLocalMap(contextValue);
|
||||||
// 用户任务逻辑
|
// 用户任务逻辑
|
||||||
task.run();
|
task.run();
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,19 @@ import com.microservices.common.core.utils.reflect.ReflectUtils;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.apache.commons.lang3.RegExUtils;
|
import org.apache.commons.lang3.RegExUtils;
|
||||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||||
|
import org.apache.poi.hssf.usermodel.*;
|
||||||
import org.apache.poi.ss.usermodel.*;
|
import org.apache.poi.ss.usermodel.*;
|
||||||
import org.apache.poi.ss.util.CellRangeAddress;
|
import org.apache.poi.ss.util.CellRangeAddress;
|
||||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||||
import org.apache.poi.util.IOUtils;
|
import org.apache.poi.util.IOUtils;
|
||||||
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
|
import org.apache.poi.xssf.usermodel.*;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
@ -1458,4 +1460,288 @@ public class ExcelUtil<T>
|
||||||
}
|
}
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 存储Excel中的图片(key: 行号_列号,value: MultipartFile)
|
||||||
|
private final Map<String, MultipartFile> excelImageMap = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取解析后的Excel图片映射表(行号_列号 -> MultipartFile)
|
||||||
|
* <p>对外返回不可修改的Map,避免外部篡改,同时让静态检查识别到该集合被查询</p>
|
||||||
|
* @return 图片映射表
|
||||||
|
*/
|
||||||
|
public Map<String, MultipartFile> getExcelImageMap() {
|
||||||
|
// 返回不可修改的Map,提升代码安全性,同时让静态检查识别到集合被读取
|
||||||
|
return Collections.unmodifiableMap(excelImageMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析Excel中的图片并转换为MultipartFile,存入{@link #excelImageMap}
|
||||||
|
* @param sheet Excel工作表
|
||||||
|
* @throws IOException 解析图片失败时抛出
|
||||||
|
*/
|
||||||
|
private void parseExcelImages(Sheet sheet) throws IOException {
|
||||||
|
if (wb instanceof XSSFWorkbook) {
|
||||||
|
parseXSSFImages((XSSFSheet) sheet);
|
||||||
|
} else if (wb instanceof HSSFWorkbook) {
|
||||||
|
parseHSSFImages((HSSFWorkbook) wb, sheet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析XSSF格式(xlsx)图片
|
||||||
|
*/
|
||||||
|
private void parseXSSFImages(XSSFSheet sheet) {
|
||||||
|
XSSFDrawing drawing = sheet.createDrawingPatriarch();
|
||||||
|
List<XSSFShape> shapes = drawing.getShapes();
|
||||||
|
|
||||||
|
for (XSSFShape shape : shapes) {
|
||||||
|
if (shape instanceof XSSFPicture) {
|
||||||
|
XSSFPicture picture = (XSSFPicture) shape;
|
||||||
|
XSSFPictureData pictureData = picture.getPictureData();
|
||||||
|
XSSFClientAnchor anchor = picture.getPreferredSize();
|
||||||
|
|
||||||
|
// 获取图片所在单元格位置
|
||||||
|
int row = anchor.getRow1();
|
||||||
|
int col = anchor.getCol1();
|
||||||
|
String cellKey = row + "_" + col;
|
||||||
|
|
||||||
|
// 转换为MultipartFile并存储
|
||||||
|
MultipartFile multipartFile = bytesToMultipartFile(pictureData.getData(), "xlsx_image.png");
|
||||||
|
excelImageMap.put(cellKey, multipartFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析HSSF格式(xls)图片
|
||||||
|
*/
|
||||||
|
private void parseHSSFImages(HSSFWorkbook workbook, Sheet sheet) {
|
||||||
|
List<HSSFPictureData> pictureDataList = workbook.getAllPictures();
|
||||||
|
|
||||||
|
for (int i = 0; i < pictureDataList.size(); i++) {
|
||||||
|
HSSFPictureData pictureData = pictureDataList.get(i);
|
||||||
|
HSSFPatriarch patriarch = (HSSFPatriarch) sheet.createDrawingPatriarch();
|
||||||
|
List<HSSFShape> shapes = patriarch.getChildren();
|
||||||
|
|
||||||
|
for (HSSFShape shape : shapes) {
|
||||||
|
if (shape instanceof HSSFPicture) {
|
||||||
|
HSSFPicture picture = (HSSFPicture) shape;
|
||||||
|
if (picture.getPictureIndex() == i) {
|
||||||
|
HSSFClientAnchor anchor = picture.getClientAnchor();
|
||||||
|
int row = anchor.getRow1();
|
||||||
|
int col = anchor.getCol1();
|
||||||
|
String cellKey = row + "_" + col;
|
||||||
|
|
||||||
|
// 转换为MultipartFile并存储
|
||||||
|
MultipartFile multipartFile = bytesToMultipartFile(pictureData.getData(), "xls_image.png");
|
||||||
|
excelImageMap.put(cellKey, multipartFile);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义MultipartFile实现(通用版,无外部依赖)
|
||||||
|
*/
|
||||||
|
public static class CustomMultipartFile implements MultipartFile {
|
||||||
|
private final byte[] content;
|
||||||
|
private final String filename;
|
||||||
|
private final String contentType;
|
||||||
|
|
||||||
|
public CustomMultipartFile(byte[] content, String filename, String contentType) {
|
||||||
|
this.content = content;
|
||||||
|
this.filename = filename;
|
||||||
|
this.contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "file";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOriginalFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return content == null || content.length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getSize() {
|
||||||
|
return content.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBytes() throws IOException {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
return new ByteArrayInputStream(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void transferTo(java.io.File dest) throws IOException, IllegalStateException {
|
||||||
|
try (java.io.OutputStream os = new java.io.FileOutputStream(dest)) {
|
||||||
|
os.write(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字节数组转换为MultipartFile(核心工具方法)
|
||||||
|
*/
|
||||||
|
public MultipartFile bytesToMultipartFile(byte[] bytes, String fileName) {
|
||||||
|
try {
|
||||||
|
String suffix = "png";
|
||||||
|
if (fileName != null && fileName.contains(".")) {
|
||||||
|
suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||||
|
}
|
||||||
|
String finalFileName = UUID.randomUUID().toString() + "." + suffix;
|
||||||
|
String contentType = "image/" + suffix;
|
||||||
|
|
||||||
|
return new CustomMultipartFile(bytes, finalFileName, contentType);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("转换图片为MultipartFile失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导入包含图片的excel
|
||||||
|
public List<T> importExcelWithImages(String sheetName, InputStream is, int titleNum) throws Exception {
|
||||||
|
this.type = Type.IMPORT;
|
||||||
|
this.wb = WorkbookFactory.create(is);
|
||||||
|
List<T> list = new ArrayList<T>();
|
||||||
|
|
||||||
|
Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0);
|
||||||
|
if (sheet == null) {
|
||||||
|
throw new IOException("文件sheet不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 解析Excel中的图片,生成imageMap(行号_列号 -> MultipartFile)
|
||||||
|
parseExcelImages(sheet);
|
||||||
|
|
||||||
|
int rows = sheet.getLastRowNum();
|
||||||
|
if (rows > 0) {
|
||||||
|
// ========== 参考原有逻辑:构建表头列名和下标映射 ==========
|
||||||
|
Map<String, Integer> cellMap = new HashMap<>();
|
||||||
|
Row heard = sheet.getRow(titleNum);
|
||||||
|
for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) {
|
||||||
|
Cell cell = heard.getCell(i);
|
||||||
|
if (StringUtils.isNotNull(cell)) {
|
||||||
|
String columnName = this.getCellValue(heard, i).toString().trim();
|
||||||
|
cellMap.put(columnName, i);
|
||||||
|
} else {
|
||||||
|
cellMap.put(null, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 参考原有逻辑:构建字段映射(通过Excel注解匹配列名) ==========
|
||||||
|
List<Object[]> fields = this.getFields();
|
||||||
|
Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>();
|
||||||
|
for (Object[] objects : fields) {
|
||||||
|
Excel attr = (Excel) objects[1];
|
||||||
|
Integer column = cellMap.get(attr.name());
|
||||||
|
if (column != null) {
|
||||||
|
fieldsMap.put(column, objects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到「图片」列的下标(关键:和Excel模板的列名对应)
|
||||||
|
Integer imageColumnIndex = cellMap.get("图片");
|
||||||
|
|
||||||
|
// ========== 遍历数据行(参考原有逻辑) ==========
|
||||||
|
for (int i = titleNum + 1; i <= rows; i++) {
|
||||||
|
Row row = sheet.getRow(i);
|
||||||
|
if (isRowEmpty(row)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
T entity = null;
|
||||||
|
// 生成当前行的图片key:行号_图片列下标(i是数据行号,对应Excel的行)
|
||||||
|
String imageCellKey = i + "_" + imageColumnIndex;
|
||||||
|
|
||||||
|
// ========== 参考原有逻辑:遍历字段映射赋值 ==========
|
||||||
|
for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet()) {
|
||||||
|
Integer columnIndex = entry.getKey();
|
||||||
|
Object val = this.getCellValue(row, columnIndex);
|
||||||
|
|
||||||
|
// 如果不存在实例则新建
|
||||||
|
entity = (entity == null ? clazz.newInstance() : entity);
|
||||||
|
|
||||||
|
// 从map中得到对应列的field和Excel注解
|
||||||
|
Field field = (Field) entry.getValue()[0];
|
||||||
|
Excel attr = (Excel) entry.getValue()[1];
|
||||||
|
|
||||||
|
// ========== 关键修改:如果是「图片」列,替换值为图片key ==========
|
||||||
|
if (imageColumnIndex != null && columnIndex.equals(imageColumnIndex)) {
|
||||||
|
val = imageCellKey; // 将单元格原始值替换为图片key(如1_12)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 原有类型转换逻辑(完全复用) ==========
|
||||||
|
Class<?> fieldType = field.getType();
|
||||||
|
if (String.class == fieldType) {
|
||||||
|
String s = Convert.toStr(val);
|
||||||
|
if (StringUtils.endsWith(s, ".0")) {
|
||||||
|
val = StringUtils.substringBefore(s, ".0");
|
||||||
|
} else {
|
||||||
|
String dateFormat = field.getAnnotation(Excel.class).dateFormat();
|
||||||
|
if (StringUtils.isNotEmpty(dateFormat)) {
|
||||||
|
val = parseDateToStr(dateFormat, val);
|
||||||
|
} else {
|
||||||
|
val = Convert.toStr(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) {
|
||||||
|
val = Convert.toInt(val);
|
||||||
|
} else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) {
|
||||||
|
val = Convert.toLong(val);
|
||||||
|
} else if (Double.TYPE == fieldType || Double.class == fieldType) {
|
||||||
|
val = Convert.toDouble(val);
|
||||||
|
} else if (Float.TYPE == fieldType || Float.class == fieldType) {
|
||||||
|
val = Convert.toFloat(val);
|
||||||
|
} else if (BigDecimal.class == fieldType) {
|
||||||
|
val = Convert.toBigDecimal(val);
|
||||||
|
} else if (Date.class == fieldType) {
|
||||||
|
if (val instanceof String) {
|
||||||
|
val = DateUtils.parseDate(val);
|
||||||
|
} else if (val instanceof Double) {
|
||||||
|
val = DateUtil.getJavaDate((Double) val);
|
||||||
|
}
|
||||||
|
} else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) {
|
||||||
|
val = Convert.toBool(val, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 原有反射赋值逻辑(完全复用) ==========
|
||||||
|
if (StringUtils.isNotNull(fieldType)) {
|
||||||
|
String propertyName = field.getName();
|
||||||
|
if (StringUtils.isNotEmpty(attr.targetAttr())) {
|
||||||
|
propertyName = field.getName() + "." + attr.targetAttr();
|
||||||
|
} else if (StringUtils.isNotEmpty(attr.readConverterExp())) {
|
||||||
|
val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
|
||||||
|
} else if (!attr.handler().equals(ExcelHandlerAdapter.class)) {
|
||||||
|
val = dataFormatHandlerAdapter(val, attr);
|
||||||
|
}
|
||||||
|
// 使用原有工具类反射赋值(核心:替换自定义setEntityFieldValue)
|
||||||
|
ReflectUtils.invokeSetter(entity, propertyName, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity != null) {
|
||||||
|
list.add(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ public class GenericsTableDataInfo<T> implements Serializable {
|
||||||
/**
|
/**
|
||||||
* 面包屑数据
|
* 面包屑数据
|
||||||
*/
|
*/
|
||||||
@ApiModelProperty("面包屑数据")
|
@ApiModelProperty(value = "面包屑数据",hidden = true)
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) //为空时隐藏
|
@JsonInclude(JsonInclude.Include.NON_NULL) //为空时隐藏
|
||||||
private List<Breadcrumb> breadcrumb;
|
private List<Breadcrumb> breadcrumb;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
package com.microservices.common.httpClient.config;
|
package com.microservices.common.httpClient.config;
|
||||||
|
|
||||||
import org.apache.http.client.config.RequestConfig;
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
import org.apache.http.config.Registry;
|
||||||
|
import org.apache.http.config.RegistryBuilder;
|
||||||
|
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
||||||
|
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
||||||
|
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.http.impl.client.HttpClients;
|
||||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
@ -11,7 +16,13 @@ import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* HttpClient 配置类
|
||||||
|
* 支持 HTTPS 和连接池管理,包含自动连接清理机制
|
||||||
|
*
|
||||||
* @author admin
|
* @author admin
|
||||||
* @date 2017/2/6
|
* @date 2017/2/6
|
||||||
*/
|
*/
|
||||||
|
|
@ -20,74 +31,131 @@ public class HttpClientConfiguration {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(HttpClientConfiguration.class);
|
private static final Logger logger = LoggerFactory.getLogger(HttpClientConfiguration.class);
|
||||||
|
|
||||||
@Value("${http.maxTotal}")
|
@Value("${http.maxTotal:100}")
|
||||||
private Integer maxTotal;
|
private Integer maxTotal;
|
||||||
|
|
||||||
@Value("${http.defaultMaxPerRoute}")
|
@Value("${http.defaultMaxPerRoute:20}")
|
||||||
private Integer defaultMaxPerRoute;
|
private Integer defaultMaxPerRoute;
|
||||||
|
|
||||||
@Value("${http.connectTimeout}")
|
@Value("${http.connectTimeout:10000}")
|
||||||
private Integer connectTimeout;
|
private Integer connectTimeout;
|
||||||
|
|
||||||
@Value("${http.connectionRequestTimeout}")
|
@Value("${http.connectionRequestTimeout:5000}")
|
||||||
private Integer connectionRequestTimeout;
|
private Integer connectionRequestTimeout;
|
||||||
|
|
||||||
@Value("${http.socketTimeout}")
|
@Value("${http.socketTimeout:30000}")
|
||||||
private Integer socketTimeout;
|
private Integer socketTimeout;
|
||||||
|
|
||||||
@Value("${http.staleConnectionCheckEnabled}")
|
@Value("${http.staleConnectionCheckEnabled:true}")
|
||||||
private boolean staleConnectionCheckEnabled;
|
private boolean staleConnectionCheckEnabled;
|
||||||
|
|
||||||
|
private PoolingHttpClientConnectionManager connectionManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 首先实例化一个连接池管理器,设置最大连接数、并发连接数
|
* 创建支持 HTTPS 的连接池管理器
|
||||||
|
* 使用自定义的 SSL 配置来避免 "peer not authenticated" 错误
|
||||||
*
|
*
|
||||||
* @return
|
* @return PoolingHttpClientConnectionManager
|
||||||
*/
|
*/
|
||||||
@Bean(name = "httpClientConnectionManager")
|
@Bean(name = "httpClientConnectionManager")
|
||||||
public PoolingHttpClientConnectionManager getHttpClientConnectionManager() {
|
public PoolingHttpClientConnectionManager getHttpClientConnectionManager() {
|
||||||
PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager();
|
try {
|
||||||
//最大连接数
|
// 创建 SSLConnectionSocketFactory
|
||||||
httpClientConnectionManager.setMaxTotal(maxTotal);
|
SSLConnectionSocketFactory sslSocketFactory = SSLContextFactory.createSSLConnectionSocketFactory();
|
||||||
//并发数
|
|
||||||
httpClientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
|
// 注册 HTTP 和 HTTPS 的 SocketFactory
|
||||||
return httpClientConnectionManager;
|
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
|
||||||
|
.register("http", PlainConnectionSocketFactory.getSocketFactory())
|
||||||
|
.register("https", sslSocketFactory)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 使用自定义 Registry 创建连接池管理器
|
||||||
|
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(registry);
|
||||||
|
|
||||||
|
// 设置连接池参数
|
||||||
|
manager.setMaxTotal(maxTotal);
|
||||||
|
manager.setDefaultMaxPerRoute(defaultMaxPerRoute);
|
||||||
|
|
||||||
|
// 设置连接验证间隔(非常重要!防止使用已关闭的连接)
|
||||||
|
manager.setValidateAfterInactivity(2000);
|
||||||
|
|
||||||
|
this.connectionManager = manager;
|
||||||
|
|
||||||
|
logger.info("HttpClient连接池初始化成功 - 最大连接数: {}, 每个路由最大连接数: {}, SSL验证: 启用",
|
||||||
|
maxTotal, defaultMaxPerRoute);
|
||||||
|
|
||||||
|
return manager;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("HttpClient连接池初始化失败", e);
|
||||||
|
throw new RuntimeException("HttpClient连接池初始化失败", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实例化连接池,设置连接池管理器。
|
* 创建 HttpClientBuilder
|
||||||
* 这里需要以参数形式注入上面实例化的连接池管理器
|
* 配置重试机制和连接管理策略
|
||||||
*
|
*
|
||||||
* @param httpClientConnectionManager
|
* @param httpClientConnectionManager 连接池管理器
|
||||||
* @return
|
* @return HttpClientBuilder
|
||||||
*/
|
*/
|
||||||
@Bean(name = "httpClientBuilder")
|
@Bean(name = "httpClientBuilder")
|
||||||
public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager") PoolingHttpClientConnectionManager httpClientConnectionManager) {
|
public org.apache.http.impl.client.HttpClientBuilder getHttpClientBuilder(
|
||||||
|
@Qualifier("httpClientConnectionManager") PoolingHttpClientConnectionManager httpClientConnectionManager) {
|
||||||
|
|
||||||
//HttpClientBuilder中的构造方法被protected修饰,所以这里不能直接使用new来实例化一个HttpClientBuilder,可以使用HttpClientBuilder提供的静态方法create()来获取HttpClientBuilder对象
|
org.apache.http.impl.client.HttpClientBuilder builder = HttpClients.custom()
|
||||||
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
|
.setConnectionManager(httpClientConnectionManager)
|
||||||
httpClientBuilder.setConnectionManager(httpClientConnectionManager);
|
// 设置连接存活时间 - 防止连接被长期占用
|
||||||
|
.setConnectionTimeToLive(60, TimeUnit.SECONDS)
|
||||||
|
// 添加重试机制 - 针对 IO/SSL 异常
|
||||||
|
.setRetryHandler((exception, executionCount, context) -> {
|
||||||
|
if (executionCount > 2) {
|
||||||
|
logger.warn("HTTP请求重试次数超过限制(2次),停止重试");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 可重试的异常类型
|
||||||
|
if (exception instanceof org.apache.http.NoHttpResponseException
|
||||||
|
|| exception instanceof javax.net.ssl.SSLHandshakeException
|
||||||
|
|| exception instanceof java.net.SocketException
|
||||||
|
|| exception instanceof org.apache.http.conn.HttpHostConnectException) {
|
||||||
|
logger.warn("HTTP请求失败,正在进行第{}次重试。异常类型: {}, 消息: {}",
|
||||||
|
executionCount, exception.getClass().getSimpleName(), exception.getMessage());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
logger.debug("HTTP请求失败,异常类型不支持重试: {}", exception.getClass().getName());
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
// 禁用过期连接
|
||||||
|
.evictIdleConnections(30, TimeUnit.SECONDS)
|
||||||
|
// 空闲连接验证
|
||||||
|
.setConnectionManagerShared(false);
|
||||||
|
|
||||||
return httpClientBuilder;
|
logger.info("HttpClientBuilder 配置完成 - 重试机制: 启用(最多2次), 连接存活时间: 60秒");
|
||||||
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注入连接池,用于获取httpClient
|
* 创建 CloseableHttpClient 实例
|
||||||
*
|
*
|
||||||
* @param httpClientBuilder
|
* @param httpClientBuilder HttpClientBuilder
|
||||||
* @return
|
* @return CloseableHttpClient
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder) {
|
public CloseableHttpClient getCloseableHttpClient(
|
||||||
return httpClientBuilder.build();
|
@Qualifier("httpClientBuilder") org.apache.http.impl.client.HttpClientBuilder httpClientBuilder) {
|
||||||
|
|
||||||
|
CloseableHttpClient httpClient = httpClientBuilder.build();
|
||||||
|
|
||||||
|
// 启动连接池清理后台线程
|
||||||
|
startConnectionMonitorThread();
|
||||||
|
|
||||||
|
logger.info("CloseableHttpClient 创建成功");
|
||||||
|
return httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder是RequestConfig的一个内部类
|
* 创建 RequestConfig.Builder
|
||||||
* 通过RequestConfig的custom方法来获取到一个Builder对象
|
|
||||||
* 设置builder的连接信息
|
|
||||||
* 这里还可以设置proxy,cookieSpec等属性。有需要的话可以在此设置
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return RequestConfig.Builder
|
||||||
*/
|
*/
|
||||||
@Bean(name = "builder")
|
@Bean(name = "builder")
|
||||||
public RequestConfig.Builder getBuilder() {
|
public RequestConfig.Builder getBuilder() {
|
||||||
|
|
@ -99,14 +167,78 @@ public class HttpClientConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用builder构建一个RequestConfig对象
|
* 创建 RequestConfig
|
||||||
*
|
*
|
||||||
* @param builder
|
* @param builder RequestConfig.Builder
|
||||||
* @return
|
* @return RequestConfig
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder) {
|
public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder) {
|
||||||
return builder.build();
|
RequestConfig config = builder.build();
|
||||||
|
logger.info("RequestConfig 配置完成 - 连接超时: {}ms, 请求超时: {}ms, Socket超时: {}ms, 陈旧连接检查: {}",
|
||||||
|
connectTimeout, connectionRequestTimeout, socketTimeout, staleConnectionCheckEnabled);
|
||||||
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动连接池监控和清理线程
|
||||||
|
* 定期清理过期和空闲连接,防止使用已关闭的连接
|
||||||
|
*/
|
||||||
|
private void startConnectionMonitorThread() {
|
||||||
|
Thread monitorThread = new Thread(() -> {
|
||||||
|
logger.info("HttpClient连接池监控线程启动");
|
||||||
|
try {
|
||||||
|
while (connectionManager != null) {
|
||||||
|
try {
|
||||||
|
// 每 10 秒清理一次
|
||||||
|
Thread.sleep(10000);
|
||||||
|
|
||||||
|
if (connectionManager != null) {
|
||||||
|
// 关闭过期连接
|
||||||
|
connectionManager.closeExpiredConnections();
|
||||||
|
// 关闭空闲超过 30 秒的连接
|
||||||
|
connectionManager.closeIdleConnections(30, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("HttpClient连接池状态 - 总连接数: {}, 路由数: {}, 最大连接数: {}, 每路由最大连接数: {}",
|
||||||
|
connectionManager.getTotalStats().getLeased() +
|
||||||
|
connectionManager.getTotalStats().getAvailable(),
|
||||||
|
connectionManager.getTotalStats().getLeased(),
|
||||||
|
connectionManager.getMaxTotal(),
|
||||||
|
connectionManager.getDefaultMaxPerRoute());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.warn("HttpClient连接池监控线程被中断");
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
break;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("HttpClient连接池清理过程中出现异常", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
logger.info("HttpClient连接池监控线程停止");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
monitorThread.setDaemon(true);
|
||||||
|
monitorThread.setName("http-connection-monitor");
|
||||||
|
monitorThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用关闭时清理资源
|
||||||
|
*/
|
||||||
|
@PreDestroy
|
||||||
|
public void destroy() {
|
||||||
|
logger.info("开始清理 HttpClient 资源");
|
||||||
|
if (connectionManager != null) {
|
||||||
|
try {
|
||||||
|
connectionManager.close();
|
||||||
|
logger.info("HttpClient 连接池已关闭");
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("关闭 HttpClient 连接池时出现异常", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
package com.microservices.common.httpClient.config;
|
||||||
|
|
||||||
|
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||||
|
import org.apache.http.ssl.SSLContexts;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.net.ssl.*;
|
||||||
|
import java.security.KeyManagementException;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSL/TLS 配置工厂类
|
||||||
|
* 用于创建支持 HTTPS 的 SSLContext 和 SocketFactory
|
||||||
|
*
|
||||||
|
* @author otto
|
||||||
|
*/
|
||||||
|
public class SSLContextFactory {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(SSLContextFactory.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建支持所有 TLS 版本的 SSLContext
|
||||||
|
* 信任所有证书(仅用于内部系统调用)
|
||||||
|
*
|
||||||
|
* @return SSLContext 实例
|
||||||
|
*/
|
||||||
|
public static SSLContext createSSLContext() {
|
||||||
|
try {
|
||||||
|
// 使用 TLSv1.2 或更高版本
|
||||||
|
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
|
||||||
|
|
||||||
|
// 创建信任所有证书的 TrustManager
|
||||||
|
TrustManager[] trustAllCerts = new TrustManager[]{
|
||||||
|
new X509TrustManager() {
|
||||||
|
@Override
|
||||||
|
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public X509Certificate[] getAcceptedIssuers() {
|
||||||
|
return new X509Certificate[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
|
||||||
|
logger.debug("SSLContext 创建成功,使用 TLSv1.2 协议");
|
||||||
|
return sslContext;
|
||||||
|
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||||
|
logger.error("创建 SSLContext 失败", e);
|
||||||
|
throw new RuntimeException("创建 SSLContext 失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建 SSLConnectionSocketFactory
|
||||||
|
* 跳过主机名验证(仅用于内部系统调用)
|
||||||
|
*
|
||||||
|
* @return SSLConnectionSocketFactory 实例
|
||||||
|
*/
|
||||||
|
public static SSLConnectionSocketFactory createSSLConnectionSocketFactory() {
|
||||||
|
try {
|
||||||
|
SSLContext sslContext = createSSLContext();
|
||||||
|
|
||||||
|
// 创建跳过主机名验证的 HostnameVerifier
|
||||||
|
HostnameVerifier allowAllHosts = new HostnameVerifier() {
|
||||||
|
@Override
|
||||||
|
public boolean verify(String hostname, SSLSession session) {
|
||||||
|
// 记录连接的主机信息,便于调试
|
||||||
|
logger.debug("SSL 连接主机: {}, 证书主体: {}", hostname, getCertificateSubject(session));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getCertificateSubject(SSLSession session) {
|
||||||
|
try {
|
||||||
|
return session.getPeerPrincipal().toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 支持的协议:TLSv1.2, TLSv1.3
|
||||||
|
String[] supportedProtocols = new String[]{"TLSv1.2", "TLSv1.3"};
|
||||||
|
|
||||||
|
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
|
||||||
|
sslContext,
|
||||||
|
supportedProtocols,
|
||||||
|
null, // 使用默认的密码套件
|
||||||
|
allowAllHosts
|
||||||
|
);
|
||||||
|
|
||||||
|
logger.debug("SSLConnectionSocketFactory 创建成功,支持的协议: TLSv1.2, TLSv1.3");
|
||||||
|
return sslSocketFactory;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("创建 SSLConnectionSocketFactory 失败", e);
|
||||||
|
throw new RuntimeException("创建 SSLConnectionSocketFactory 失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建用于信任所有证书的 TrustManager(用于日志记录)
|
||||||
|
*
|
||||||
|
* @return TrustManager 数组
|
||||||
|
*/
|
||||||
|
public static TrustManager[] createTrustAllManagers() {
|
||||||
|
return new TrustManager[]{
|
||||||
|
new X509TrustManager() {
|
||||||
|
@Override
|
||||||
|
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||||
|
logger.debug("客户端证书验证通过");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||||
|
if (chain != null && chain.length > 0) {
|
||||||
|
X509Certificate cert = chain[0];
|
||||||
|
logger.debug("服务器证书验证通过 - 主体: {}, 颁发者: {}, 有效期: {} - {}",
|
||||||
|
cert.getSubjectDN(),
|
||||||
|
cert.getIssuerDN(),
|
||||||
|
cert.getNotBefore(),
|
||||||
|
cert.getNotAfter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public X509Certificate[] getAcceptedIssuers() {
|
||||||
|
return new X509Certificate[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -27,6 +27,7 @@ import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static com.microservices.common.httpClient.domain.GitLinkRequestUrl.GET_FILE_SUB_ENTRIES;
|
import static com.microservices.common.httpClient.domain.GitLinkRequestUrl.GET_FILE_SUB_ENTRIES;
|
||||||
import static com.microservices.common.httpClient.util.GitLinkRequestHelper.RequestType.GET;
|
import static com.microservices.common.httpClient.util.GitLinkRequestHelper.RequestType.GET;
|
||||||
|
|
@ -79,44 +80,75 @@ public class GitLinkRequestHelper {
|
||||||
HashMap<String, String> headers = prepareAuthenticationHeaders(gitLinkRequestUrl);
|
HashMap<String, String> headers = prepareAuthenticationHeaders(gitLinkRequestUrl);
|
||||||
String requestId = UUID.randomUUID().toString();
|
String requestId = UUID.randomUUID().toString();
|
||||||
String path = gitLinkRequestUrl.getPath();
|
String path = gitLinkRequestUrl.getPath();
|
||||||
logger.info("[{}]通过HttpClient向平台发起请求,请求方法为:{},请求网站为:{},请求路由为:{},请求载体为:{},请求头为:{}"
|
logger.debug("[{}]通过HttpClient向平台发起请求,请求方法为:{},请求网站为:{},请求路由为:{},请求载体为:{},请求头为:{}"
|
||||||
, requestId
|
, requestId
|
||||||
, requestType
|
, requestType
|
||||||
, gitLinkUrl
|
, gitLinkUrl
|
||||||
, path
|
, path
|
||||||
, object
|
, object
|
||||||
, headers);
|
, headers);
|
||||||
JSONObject result;
|
JSONObject result = null;
|
||||||
try {
|
Exception lastException = null;
|
||||||
String requestURL = EscapeUtil.removeExtraSlashOfUrl(gitLinkUrl + path.replace(" ", "%20"));
|
|
||||||
switch (requestType) {
|
// 业务层重试机制:针对 SSL 握手失败等偶发性错误
|
||||||
case POST:
|
int maxRetries = 2;
|
||||||
result = httpAPIService.doPost(requestURL, (JSONObject) object, headers);
|
for (int attempt = 1; attempt <= maxRetries; attempt++) {
|
||||||
break;
|
try {
|
||||||
case POST_FILE:
|
String requestURL = EscapeUtil.removeExtraSlashOfUrl(gitLinkUrl + path.replace(" ", "%20"));
|
||||||
result = httpAPIService.doPostFile(requestURL, (MultipartFile) object, headers);
|
switch (requestType) {
|
||||||
break;
|
case POST:
|
||||||
case DELETE:
|
result = httpAPIService.doPost(requestURL, (JSONObject) object, headers);
|
||||||
result = httpAPIService.doDelete(requestURL, (JSONObject) object, headers);
|
break;
|
||||||
break;
|
case POST_FILE:
|
||||||
case GET:
|
result = httpAPIService.doPostFile(requestURL, (MultipartFile) object, headers);
|
||||||
result = httpAPIService.doGet(requestURL, headers);
|
break;
|
||||||
break;
|
case DELETE:
|
||||||
case PUT:
|
result = httpAPIService.doDelete(requestURL, (JSONObject) object, headers);
|
||||||
result = httpAPIService.doPut(requestURL, (JSONObject) object, headers);
|
break;
|
||||||
break;
|
case GET:
|
||||||
case PATCH:
|
result = httpAPIService.doGet(requestURL, headers);
|
||||||
result = httpAPIService.doPatch(requestURL, (JSONObject) object, headers);
|
break;
|
||||||
break;
|
case PUT:
|
||||||
default:
|
result = httpAPIService.doPut(requestURL, (JSONObject) object, headers);
|
||||||
throw new ServiceException("不支持该请求方式:" + requestType.name());
|
break;
|
||||||
|
case PATCH:
|
||||||
|
result = httpAPIService.doPatch(requestURL, (JSONObject) object, headers);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ServiceException("不支持该请求方式:" + requestType.name());
|
||||||
|
}
|
||||||
|
logger.debug("[{}]请求响应为:{}"
|
||||||
|
, requestId
|
||||||
|
, result);
|
||||||
|
// 请求成功,跳出重试循环
|
||||||
|
break;
|
||||||
|
} catch (Exception e) {
|
||||||
|
lastException = e;
|
||||||
|
String errorMsg = e.getMessage();
|
||||||
|
// 判断是否为可重试的异常类型
|
||||||
|
boolean isRetryable = errorMsg != null && (
|
||||||
|
errorMsg.contains("peer not authenticated") ||
|
||||||
|
errorMsg.contains("SSLHandshakeException") ||
|
||||||
|
errorMsg.contains("Connection reset") ||
|
||||||
|
errorMsg.contains("NoHttpResponseException") ||
|
||||||
|
errorMsg.contains("SocketException")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isRetryable && attempt < maxRetries) {
|
||||||
|
logger.warn("[{}]请求平台时发生可重试异常(第{}次尝试),将在100ms后重试。异常信息: {}",
|
||||||
|
requestId, attempt, errorMsg);
|
||||||
|
try {
|
||||||
|
TimeUnit.MILLISECONDS.sleep(100);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new ServiceException("请求被中断");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw new ServiceException("请求平台出现错误:" + errorMsg);
|
||||||
}
|
}
|
||||||
logger.info("[{}]请求响应为:{}"
|
|
||||||
, requestId
|
|
||||||
, result);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ServiceException("请求平台出现错误:" + e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
throw new ServiceException("请求平台时,未返回内容");
|
throw new ServiceException("请求平台时,未返回内容");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,12 @@
|
||||||
<artifactId>microservices-common-redis</artifactId>
|
<artifactId>microservices-common-redis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- SpringCloud Alibaba Sentinel -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.microservices.common.security.feign;
|
||||||
import feign.RequestInterceptor;
|
import feign.RequestInterceptor;
|
||||||
import feign.codec.Encoder;
|
import feign.codec.Encoder;
|
||||||
import feign.form.FormEncoder;
|
import feign.form.FormEncoder;
|
||||||
|
import feign.form.spring.SpringFormEncoder;
|
||||||
import org.springframework.beans.factory.ObjectFactory;
|
import org.springframework.beans.factory.ObjectFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||||
|
|
@ -33,6 +34,6 @@ public class FeignAutoConfiguration
|
||||||
// 重要的是返回类型要是 Encoder 并且实现类必须是 FormEncoder 或者其子类
|
// 重要的是返回类型要是 Encoder 并且实现类必须是 FormEncoder 或者其子类
|
||||||
@Bean
|
@Bean
|
||||||
public Encoder feignFormEncoder() {
|
public Encoder feignFormEncoder() {
|
||||||
return new FormEncoder(new SpringEncoder(messageConverters));
|
return new SpringFormEncoder(new SpringEncoder(messageConverters));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
package com.microservices.common.security.handler;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
|
||||||
|
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.domain.R;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class SentinelBlockExceptionHandler implements BlockExceptionHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
BlockException ex) throws Exception {
|
||||||
|
|
||||||
|
R<?> body;
|
||||||
|
if (ex instanceof FlowException) { // 限流
|
||||||
|
body = R.fail(429, "请求过于频繁,请稍后重试");
|
||||||
|
} else if (ex instanceof DegradeException) { // 熔断
|
||||||
|
body = R.fail(500, "服务暂时不可用,请稍后重试");
|
||||||
|
} else if (ex instanceof ParamFlowException) { // 热点参数限流
|
||||||
|
body = R.fail(400, "热点参数限流");
|
||||||
|
} else if (ex instanceof AuthorityException) { // 授权规则
|
||||||
|
body = R.fail(403, "无权限访问该资源");
|
||||||
|
} else if (ex instanceof SystemBlockException) { // 系统规则
|
||||||
|
body = R.fail(500, "系统规则限制,无法访问");
|
||||||
|
} else { // 兜底
|
||||||
|
body = R.fail(500, "服务繁忙,请稍后重试");
|
||||||
|
}
|
||||||
|
|
||||||
|
response.setStatus(HttpStatus.OK.value());
|
||||||
|
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||||
|
response.setCharacterEncoding("UTF-8");
|
||||||
|
response.getWriter().write(JSONObject.toJSONString(body));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,3 +4,4 @@ com.microservices.common.security.service.impl.RequestCustomServiceImpl
|
||||||
com.microservices.common.security.aspect.PreAuthorizeAspect
|
com.microservices.common.security.aspect.PreAuthorizeAspect
|
||||||
com.microservices.common.security.aspect.InnerAuthAspect
|
com.microservices.common.security.aspect.InnerAuthAspect
|
||||||
com.microservices.common.security.handler.GlobalExceptionHandler
|
com.microservices.common.security.handler.GlobalExceptionHandler
|
||||||
|
com.microservices.common.security.handler.SentinelBlockExceptionHandler
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ public class AuthFilter implements GlobalFilter, Ordered {
|
||||||
try {
|
try {
|
||||||
claims = JwtUtils.parseToken(token);
|
claims = JwtUtils.parseToken(token);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("令牌解析失败:{}", e.getMessage());
|
log.error("[鉴权异常处理]令牌解析失败:{}", e.getMessage());
|
||||||
return unauthorizedResponse(exchange, "令牌格式不正确!");
|
return unauthorizedResponse(exchange, "令牌格式不正确!");
|
||||||
}
|
}
|
||||||
if (claims == null) {
|
if (claims == null) {
|
||||||
|
|
@ -139,7 +139,7 @@ public class AuthFilter implements GlobalFilter, Ordered {
|
||||||
);
|
);
|
||||||
redisService.setCacheObject(redisKey, feignResult);
|
redisService.setCacheObject(redisKey, feignResult);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("获取用户【{}】身份列表时发生异常:{}", username, e.getMessage());
|
log.error("[鉴权异常处理]获取用户【{}】身份列表时发生异常:{}", username, e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -167,7 +167,7 @@ public class AuthFilter implements GlobalFilter, Ordered {
|
||||||
}
|
}
|
||||||
return genCookieByToken(token);
|
return genCookieByToken(token);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("检查该gitlink token【{}】是否登录时发生异常:{}", token, e.getMessage());
|
log.error("[鉴权异常处理]检查该token【{}】是否登录时发生异常:{}", token, e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -215,11 +215,11 @@ public class AuthFilter implements GlobalFilter, Ordered {
|
||||||
try {
|
try {
|
||||||
feignResult = future.get();
|
feignResult = future.get();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("异步请求获取本系统Token出错:{}", e.getMessage());
|
log.error("[鉴权异常处理]异步请求获取本系统Token出错:{}", e.getMessage());
|
||||||
throw new ServiceException("内部服务错误");
|
throw new ServiceException("内部服务错误");
|
||||||
}
|
}
|
||||||
if (StringUtils.isNull(feignResult) || R.FAIL == feignResult.getCode()) {
|
if (StringUtils.isNull(feignResult) || R.FAIL == feignResult.getCode()) {
|
||||||
log.error("Token获取出错:{}", feignResult.getMsg());
|
log.error("[鉴权异常处理]Token获取出错:{}", feignResult.getMsg());
|
||||||
throw new ServiceException("内部服务错误");
|
throw new ServiceException("内部服务错误");
|
||||||
}
|
}
|
||||||
if (R.SUCCESS == feignResult.getCode()) {
|
if (R.SUCCESS == feignResult.getCode()) {
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
||||||
String lowerUrl = request.getURI().getPath().toLowerCase();
|
String lowerUrl = request.getURI().getPath().toLowerCase();
|
||||||
ServerHttpResponse originalResponse = exchange.getResponse();
|
ServerHttpResponse originalResponse = exchange.getResponse();
|
||||||
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
|
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
|
||||||
|
|
||||||
// 当请求为Nacos时,Nacos返回的所有非JSON响应都会被自动转换为结构化的错误信息,同时将HTTP状态码设置为200,适合用于规范化微服务架构的响应格式。
|
// 当请求为Nacos时,Nacos返回的所有非JSON响应都会被自动转换为结构化的错误信息,同时将HTTP状态码设置为200,适合用于规范化微服务架构的响应格式。
|
||||||
if (lowerUrl.startsWith("/nacos")) {
|
if (lowerUrl.startsWith("/nacos")) {
|
||||||
|
|
||||||
|
|
@ -53,7 +54,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
||||||
return super.writeWith(body);
|
return super.writeWith(body);
|
||||||
}
|
}
|
||||||
if (status == HttpStatus.FORBIDDEN) {
|
if (status == HttpStatus.FORBIDDEN) {
|
||||||
log.error("nacos鉴权异常,已清理redis中nacos token");
|
log.error("[网关转发异常处理]nacos鉴权异常,已清理redis中nacos token");
|
||||||
// 设置新的状态码为 200
|
// 设置新的状态码为 200
|
||||||
setStatusCode(HttpStatus.OK);
|
setStatusCode(HttpStatus.OK);
|
||||||
// 设置响应内容类型为 JSON
|
// 设置响应内容类型为 JSON
|
||||||
|
|
@ -125,7 +126,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
||||||
}
|
}
|
||||||
synchronousSink.complete();
|
synchronousSink.complete();
|
||||||
}).flatMap(resStr -> {
|
}).flatMap(resStr -> {
|
||||||
log.error("Portainer响应处理异常,异常信息:{}", resStr);
|
log.error("[网关转发异常处理]Portainer响应处理异常,异常信息:{}", resStr);
|
||||||
originalResponse.setStatusCode(HttpStatus.OK);
|
originalResponse.setStatusCode(HttpStatus.OK);
|
||||||
byte[] bytes;
|
byte[] bytes;
|
||||||
if (JSON.isValid(resStr)) {
|
if (JSON.isValid(resStr)) {
|
||||||
|
|
@ -133,7 +134,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
||||||
if (resJson.containsKey("message")) {
|
if (resJson.containsKey("message")) {
|
||||||
String message = resJson.getString("message");
|
String message = resJson.getString("message");
|
||||||
if (StringUtils.isNotBlank(message) && message.contains("A valid authorisation token is missing")) {
|
if (StringUtils.isNotBlank(message) && message.contains("A valid authorisation token is missing")) {
|
||||||
log.error("Portainer鉴权异常,已清理redis中Portainer token");
|
log.error("[网关转发异常处理]Portainer鉴权异常,已清理redis中Portainer token");
|
||||||
//token失效清除redis缓存
|
//token失效清除redis缓存
|
||||||
redisService.deleteObject(CacheConstants.PORTAINER_TOKEN);
|
redisService.deleteObject(CacheConstants.PORTAINER_TOKEN);
|
||||||
bytes = JSON.toJSONBytes(AjaxResult.error(ExceptionMsgConstants.RETRY_ERROR));
|
bytes = JSON.toJSONBytes(AjaxResult.error(ExceptionMsgConstants.RETRY_ERROR));
|
||||||
|
|
@ -160,12 +161,12 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
||||||
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
|
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
|
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
|
||||||
HttpStatus status = getStatusCode() != null ? getStatusCode() : HttpStatus.INTERNAL_SERVER_ERROR;
|
HttpStatus status = getStatusCode();
|
||||||
if (!status.isError()) {
|
if (!status.isError()) {
|
||||||
return super.writeWith(body);
|
return super.writeWith(body);
|
||||||
}
|
}
|
||||||
if (status == HttpStatus.UNAUTHORIZED) {
|
if (status == HttpStatus.UNAUTHORIZED) {
|
||||||
log.error("sentinel鉴权异常,已清理redis中sentinel token");
|
log.error("[网关转发异常处理]sentinel鉴权异常,已清理redis中sentinel token");
|
||||||
// 设置新的状态码为 200
|
// 设置新的状态码为 200
|
||||||
setStatusCode(HttpStatus.OK);
|
setStatusCode(HttpStatus.OK);
|
||||||
// 设置响应内容类型为 JSON
|
// 设置响应内容类型为 JSON
|
||||||
|
|
@ -192,7 +193,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
||||||
}
|
}
|
||||||
synchronousSink.complete();
|
synchronousSink.complete();
|
||||||
}).flatMap(resStr -> {
|
}).flatMap(resStr -> {
|
||||||
log.error("Sentinel响应处理异常,异常信息:{}", resStr);
|
log.error("[网关转发异常处理]Sentinel响应处理异常,异常信息:{}", resStr);
|
||||||
byte[] bytes;
|
byte[] bytes;
|
||||||
bytes = JSON.toJSONBytes(AjaxResult.error(ExceptionMsgConstants.SYSTEM_EXEC_ERROR));
|
bytes = JSON.toJSONBytes(AjaxResult.error(ExceptionMsgConstants.SYSTEM_EXEC_ERROR));
|
||||||
setStatusCode(HttpStatus.OK);
|
setStatusCode(HttpStatus.OK);
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,14 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
||||||
public String portainerUsername;
|
public String portainerUsername;
|
||||||
@Value("${thirdPartyTools.portainer.auth.password:}")
|
@Value("${thirdPartyTools.portainer.auth.password:}")
|
||||||
public String portainerPassword;
|
public String portainerPassword;
|
||||||
|
@Value("${thirdPartyTools.rancher.auth.username:}")
|
||||||
|
public String rancherUsername;
|
||||||
|
@Value("${thirdPartyTools.rancher.auth.password:}")
|
||||||
|
public String rancherPassword;
|
||||||
@Value("${thirdPartyTools.portainer.endpoints:}")
|
@Value("${thirdPartyTools.portainer.endpoints:}")
|
||||||
public Integer portainerEndpoints;
|
public Integer portainerEndpoints;
|
||||||
|
@Value("${thirdPartyTools.retryTimes:1}")
|
||||||
|
public Integer retryTimes;
|
||||||
ThreadPoolExecutor threadPoolExecutor = CustomExecutorFactory.threadPoolExecutor;
|
ThreadPoolExecutor threadPoolExecutor = CustomExecutorFactory.threadPoolExecutor;
|
||||||
@Lazy
|
@Lazy
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|
@ -83,27 +89,81 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
||||||
if (redisService.hasKey(CacheConstants.SENTINEL_TOKEN)) {
|
if (redisService.hasKey(CacheConstants.SENTINEL_TOKEN)) {
|
||||||
sentinelCookie = redisService.getCacheObject(CacheConstants.SENTINEL_TOKEN);
|
sentinelCookie = redisService.getCacheObject(CacheConstants.SENTINEL_TOKEN);
|
||||||
} else {
|
} else {
|
||||||
// 网关采用异步架构,所以此处需要通过异步请求获取Sentinel Token
|
for (int i = 0; i < retryTimes; i++) {
|
||||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginSentinel(sentinelUsername, sentinelPassword));
|
// 网关采用异步架构,所以此处需要通过异步请求获取Sentinel Token
|
||||||
try {
|
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginSentinel(sentinelUsername, sentinelPassword));
|
||||||
Response response = future.get(1, TimeUnit.SECONDS);
|
try {
|
||||||
Map<String, Collection<String>> header = response.headers();
|
Response response = future.get(3, TimeUnit.SECONDS);
|
||||||
if (header != null && header.containsKey("set-cookie")) {
|
Map<String, Collection<String>> header = response.headers();
|
||||||
sentinelCookie = header.get("set-cookie").iterator().next();
|
if (header != null && header.containsKey("set-cookie")) {
|
||||||
//Sentinel登录状态默认30分钟失效,将Sentinel Token缓存过期时间调整为28分钟
|
sentinelCookie = header.get("set-cookie").iterator().next();
|
||||||
redisService.setCacheObject(CacheConstants.SENTINEL_TOKEN, sentinelCookie, 28L, TimeUnit.MINUTES);
|
//Sentinel登录状态默认30分钟失效,将Sentinel Token缓存过期时间调整为28分钟
|
||||||
|
redisService.setCacheObject(CacheConstants.SENTINEL_TOKEN, sentinelCookie, 28L, TimeUnit.MINUTES);
|
||||||
|
}
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
log.error("[网关转发异常处理]获取Sentinel Token超时");
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
log.error("[网关转发异常处理]获取Sentinel Token失败:{}", e.getMessage());
|
||||||
}
|
}
|
||||||
} catch (TimeoutException e) {
|
|
||||||
log.error("获取Sentinel Token超时");
|
if (StringUtils.isNotEmpty(sentinelCookie)) {
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
break;
|
||||||
log.error("获取Sentinel Token失败:{}", e.getMessage());
|
}
|
||||||
|
|
||||||
|
log.warn("[网关转发异常处理]获取Sentinel Token失败,进行第{}次重试中", i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(sentinelCookie)) {
|
if (StringUtils.isNotEmpty(sentinelCookie)) {
|
||||||
ServletUtils.removeHeader(mutate, TokenConstants.Cookie);
|
ServletUtils.removeHeader(mutate, TokenConstants.Cookie);
|
||||||
mutate.header(TokenConstants.Cookie, String.format("%s;%s;", cookie, sentinelCookie));
|
mutate.header(TokenConstants.Cookie, String.format("%s;%s;", cookie, sentinelCookie));
|
||||||
} else {
|
} else {
|
||||||
throw new ServiceException("Sentinel服务获取Token失败");
|
throw new ServiceException("[网关转发异常处理]Sentinel服务获取Token失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理Rancher请求
|
||||||
|
if (lowerUrl.startsWith("/rancher")) {
|
||||||
|
String rancherToken = null;
|
||||||
|
if (redisService.hasKey(CacheConstants.RANCHER_TOKEN)) {
|
||||||
|
rancherToken = redisService.getCacheObject(CacheConstants.RANCHER_TOKEN);
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < retryTimes; i++) {
|
||||||
|
JSONObject loginRancherBody = new JSONObject();
|
||||||
|
loginRancherBody.put("description", "api session");
|
||||||
|
loginRancherBody.put("responseType", "cookie");
|
||||||
|
loginRancherBody.put("username", rancherUsername);
|
||||||
|
loginRancherBody.put("password", rancherPassword);
|
||||||
|
|
||||||
|
// 网关采用异步架构,所以此处需要通过异步请求获取Rancher Token
|
||||||
|
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginRancher(loginRancherBody));
|
||||||
|
try {
|
||||||
|
Response response = future.get(3, TimeUnit.SECONDS);
|
||||||
|
Map<String, Collection<String>> header = response.headers();
|
||||||
|
if (header != null && header.containsKey("set-cookie")) {
|
||||||
|
String rancherCookie = header.get("set-cookie").iterator().next();
|
||||||
|
rancherToken = getValueByCookieKey(rancherCookie, TokenConstants.Rancher_Cookie_Token_Key);
|
||||||
|
//Rancher登录状态默认15小时失效,将Rancher Token缓存过期时间调整为14分钟
|
||||||
|
redisService.setCacheObject(CacheConstants.RANCHER_TOKEN, rancherToken, 14L, TimeUnit.HOURS);
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
log.error("[网关转发异常处理]获取Rancher Token超时");
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
log.error("[网关转发异常处理]获取Rancher Token失败:{}", e.getMessage());
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(rancherToken)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.warn("[网关转发异常处理]获取Rancher Token失败,进行第{}次重试中", i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(rancherToken)) {
|
||||||
|
ServletUtils.removeHeader(mutate, TokenConstants.AUTHENTICATION);
|
||||||
|
mutate.header(TokenConstants.AUTHENTICATION, TokenConstants.PREFIX + rancherToken);
|
||||||
|
} else {
|
||||||
|
throw new ServiceException("[网关转发异常处理]Rancher服务获取Token失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 处理Nacos请求
|
// 处理Nacos请求
|
||||||
|
|
@ -112,38 +172,44 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
||||||
if (redisService.hasKey(CacheConstants.NACOS_TOKEN)) {
|
if (redisService.hasKey(CacheConstants.NACOS_TOKEN)) {
|
||||||
nacosToken = redisService.getCacheObject(CacheConstants.NACOS_TOKEN);
|
nacosToken = redisService.getCacheObject(CacheConstants.NACOS_TOKEN);
|
||||||
} else {
|
} else {
|
||||||
Map<String, String> nacosMap = new HashMap<>();
|
for (int i = 0; i < retryTimes; i++) {
|
||||||
nacosMap.put("username", nacosUsername);
|
Map<String, String> nacosMap = new HashMap<>();
|
||||||
nacosMap.put("password", nacosPassword);
|
nacosMap.put("username", nacosUsername);
|
||||||
// 网关采用异步架构,所以此处需要通过异步请求获取Nacos Token
|
nacosMap.put("password", nacosPassword);
|
||||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginNacos(nacosMap));
|
// 网关采用异步架构,所以此处需要通过异步请求获取Nacos Token
|
||||||
try {
|
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginNacos(nacosMap));
|
||||||
Response res = future.get(1, TimeUnit.SECONDS);
|
try {
|
||||||
StringWriter writer = new StringWriter();
|
Response res = future.get(3, TimeUnit.SECONDS);
|
||||||
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
|
StringWriter writer = new StringWriter();
|
||||||
String str = writer.toString();
|
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
|
||||||
if (!JSON.isValid(str)) {
|
String str = writer.toString();
|
||||||
return exceptionResponse(exchange, str, res.status());
|
if (!JSON.isValid(str)) {
|
||||||
|
return exceptionResponse(exchange, str, res.status());
|
||||||
|
}
|
||||||
|
JSONObject resJsonObject = JSONObject.parseObject(str);
|
||||||
|
if (resJsonObject == null) {
|
||||||
|
return exceptionResponse(exchange, str, res.status());
|
||||||
|
}
|
||||||
|
nacosToken = resJsonObject.getString("accessToken");
|
||||||
|
Long tokenTtl = resJsonObject.getLong("tokenTtl");
|
||||||
|
if (nacosToken != null && tokenTtl != null) {
|
||||||
|
redisService.setCacheObject(CacheConstants.NACOS_TOKEN, nacosToken, tokenTtl - 10, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
log.error("[网关转发异常处理]获取Nacos Token超时");
|
||||||
|
} catch (InterruptedException | ExecutionException | IOException | NullPointerException e) {
|
||||||
|
log.error("[网关转发异常处理]获取Nacos Token失败:{}", e.getMessage());
|
||||||
}
|
}
|
||||||
JSONObject resJsonObject = JSONObject.parseObject(str);
|
if (StringUtils.isNotEmpty(nacosToken)) {
|
||||||
if (resJsonObject == null) {
|
break;
|
||||||
return exceptionResponse(exchange, str, res.status());
|
|
||||||
}
|
}
|
||||||
nacosToken = resJsonObject.getString("accessToken");
|
log.warn("[网关转发异常处理]获取Nacos Token失败,进行第{}次重试中", i + 1);
|
||||||
Long tokenTtl = resJsonObject.getLong("tokenTtl");
|
|
||||||
if (nacosToken != null && tokenTtl != null) {
|
|
||||||
redisService.setCacheObject(CacheConstants.NACOS_TOKEN, nacosToken, tokenTtl - 10, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
} catch (TimeoutException e) {
|
|
||||||
log.error("获取Nacos Token超时");
|
|
||||||
} catch (InterruptedException | ExecutionException | IOException | NullPointerException e) {
|
|
||||||
log.error("获取Nacos Token失败:{}", e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotEmpty(nacosToken)) {
|
if (StringUtils.isNotEmpty(nacosToken)) {
|
||||||
mutate.header(TokenConstants.Nacos_Token_Key, nacosToken);
|
mutate.header(TokenConstants.Nacos_Token_Key, nacosToken);
|
||||||
} else {
|
} else {
|
||||||
throw new ServiceException("Nacos服务获取Token失败");
|
throw new ServiceException("[网关转发异常处理]Nacos服务获取Token失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,7 +229,7 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
||||||
try {
|
try {
|
||||||
mutate.uri(new URI(url));
|
mutate.uri(new URI(url));
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
log.error("替换Portainer请求中Endpoints时发生异常:{}", e.getMessage());
|
log.error("[网关转发异常处理]替换Portainer请求中Endpoints时发生异常:{}", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -178,38 +244,44 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
||||||
if (redisService.hasKey(CacheConstants.PORTAINER_TOKEN)) {
|
if (redisService.hasKey(CacheConstants.PORTAINER_TOKEN)) {
|
||||||
portainerToken = redisService.getCacheObject(CacheConstants.PORTAINER_TOKEN);
|
portainerToken = redisService.getCacheObject(CacheConstants.PORTAINER_TOKEN);
|
||||||
} else {
|
} else {
|
||||||
// 网关采用异步架构,所以此处需要通过异步请求获取Portainer Token
|
for (int i = 0; i < 5; i++) {
|
||||||
JSONObject loginPortainerBody = new JSONObject();
|
// 网关采用异步架构,所以此处需要通过异步请求获取Portainer Token
|
||||||
loginPortainerBody.put("username", portainerUsername);
|
JSONObject loginPortainerBody = new JSONObject();
|
||||||
loginPortainerBody.put("password", portainerPassword);
|
loginPortainerBody.put("username", portainerUsername);
|
||||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginPortainer(loginPortainerBody));
|
loginPortainerBody.put("password", portainerPassword);
|
||||||
try {
|
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginPortainer(loginPortainerBody));
|
||||||
Response res = future.get(1, TimeUnit.SECONDS);
|
try {
|
||||||
StringWriter writer = new StringWriter();
|
Response res = future.get(1, TimeUnit.SECONDS);
|
||||||
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
|
StringWriter writer = new StringWriter();
|
||||||
String str = writer.toString();
|
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
|
||||||
if (!JSON.isValid(str)) {
|
String str = writer.toString();
|
||||||
return exceptionResponse(exchange, str, res.status());
|
if (!JSON.isValid(str)) {
|
||||||
}
|
return exceptionResponse(exchange, str, res.status());
|
||||||
JSONObject resJsonObject = JSONObject.parseObject(str);
|
}
|
||||||
portainerToken = resJsonObject.getString("jwt");
|
JSONObject resJsonObject = JSONObject.parseObject(str);
|
||||||
if (portainerToken == null) {
|
portainerToken = resJsonObject.getString("jwt");
|
||||||
return exceptionResponse(exchange, str, res.status());
|
if (portainerToken == null) {
|
||||||
}
|
return exceptionResponse(exchange, str, res.status());
|
||||||
String[] tokenSplit = portainerToken.split("\\.");
|
}
|
||||||
String tokenBodyStr = new String(Base64.getDecoder().decode(tokenSplit[1]), StandardCharsets.UTF_8);
|
String[] tokenSplit = portainerToken.split("\\.");
|
||||||
JSONObject tokenBody = JSONObject.parseObject(tokenBodyStr);
|
String tokenBodyStr = new String(Base64.getDecoder().decode(tokenSplit[1]), StandardCharsets.UTF_8);
|
||||||
Long expiration = tokenBody.getLong("exp");
|
JSONObject tokenBody = JSONObject.parseObject(tokenBodyStr);
|
||||||
Long now = new Date().getTime() / 1000;
|
Long expiration = tokenBody.getLong("exp");
|
||||||
|
Long now = new Date().getTime() / 1000;
|
||||||
|
|
||||||
long portainerTokenTtl = expiration - now;
|
long portainerTokenTtl = expiration - now;
|
||||||
if (portainerTokenTtl > 20) {
|
if (portainerTokenTtl > 20) {
|
||||||
redisService.setCacheObject(CacheConstants.PORTAINER_TOKEN, portainerToken, portainerTokenTtl - 10, TimeUnit.SECONDS);
|
redisService.setCacheObject(CacheConstants.PORTAINER_TOKEN, portainerToken, portainerTokenTtl - 10, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
log.error("[网关转发异常处理]获取Portainer Token超时");
|
||||||
|
} catch (InterruptedException | ExecutionException | IOException | NullPointerException e) {
|
||||||
|
log.error("[网关转发异常处理]获取Portainer Token失败:{}", e.getMessage());
|
||||||
}
|
}
|
||||||
} catch (TimeoutException e) {
|
if (StringUtils.isNotEmpty(portainerToken)) {
|
||||||
log.error("获取Portainer Token超时");
|
break;
|
||||||
} catch (InterruptedException | ExecutionException | IOException | NullPointerException e) {
|
}
|
||||||
log.error("获取Portainer Token失败:{}", e.getMessage());
|
log.warn("[网关转发异常处理]获取Portainer Token失败,进行第{}次重试中", i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotEmpty(portainerToken)) {
|
if (StringUtils.isNotEmpty(portainerToken)) {
|
||||||
|
|
@ -218,7 +290,7 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
||||||
mutate.header(TokenConstants.AUTHENTICATION, TokenConstants.PREFIX + portainerToken);
|
mutate.header(TokenConstants.AUTHENTICATION, TokenConstants.PREFIX + portainerToken);
|
||||||
mutate.header(TokenConstants.Cookie, String.format("%s;%s;", cookie, portainerToken));
|
mutate.header(TokenConstants.Cookie, String.format("%s;%s;", cookie, portainerToken));
|
||||||
} else {
|
} else {
|
||||||
throw new ServiceException("Portainer服务获取Token失败");
|
throw new ServiceException("[网关转发异常处理]Portainer服务获取Token失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -226,7 +298,23 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
||||||
|
|
||||||
|
|
||||||
private Mono<Void> exceptionResponse(ServerWebExchange exchange, String msg, int code) {
|
private Mono<Void> exceptionResponse(ServerWebExchange exchange, String msg, int code) {
|
||||||
log.error("[第三方工具请求处理异常]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), msg);
|
log.error("[网关转发异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), msg);
|
||||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), ExceptionMsgConstants.SYSTEM_EXEC_ERROR, code);
|
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), ExceptionMsgConstants.SYSTEM_EXEC_ERROR, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过指定Key获取Cookie中指定值
|
||||||
|
*/
|
||||||
|
private static String getValueByCookieKey(String cookie, String key) {
|
||||||
|
if (cookie != null) {
|
||||||
|
String[] cookies = StringUtils.split(cookie, ';');
|
||||||
|
for (String cookieItem : cookies) {
|
||||||
|
if (cookieItem.contains(key)) {
|
||||||
|
String token = StringUtils.remove(cookieItem, key + "=");
|
||||||
|
return StringUtils.remove(token, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ public class CmsDocController extends BaseController {
|
||||||
public AjaxResult editCmsDIr(@ApiParam(name = "id", value = "栏目Id") @PathVariable Long id,
|
public AjaxResult editCmsDIr(@ApiParam(name = "id", value = "栏目Id") @PathVariable Long id,
|
||||||
@ApiParam(name = "cmsDirUpdateVo", value = "栏目更新对象") @RequestBody CmsDirUpdateVo cmsDirUpdateVo) {
|
@ApiParam(name = "cmsDirUpdateVo", value = "栏目更新对象") @RequestBody CmsDirUpdateVo cmsDirUpdateVo) {
|
||||||
cmsDocService.updateCmsDir(id, cmsDirUpdateVo);
|
cmsDocService.updateCmsDir(id, cmsDirUpdateVo);
|
||||||
return success("异步更新栏目信息");
|
return success("栏目信息更新成功");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ public class OpenController extends BaseController {
|
||||||
public GenericsTableDataInfo<CmsDocBaseDto> docList(@ApiParam(name = "dirId", value = "栏目Id") @PathVariable("dirId") Long dirId
|
public GenericsTableDataInfo<CmsDocBaseDto> docList(@ApiParam(name = "dirId", value = "栏目Id") @PathVariable("dirId") Long dirId
|
||||||
, CmsDocSearchVo cmsDocSearchVo) {
|
, CmsDocSearchVo cmsDocSearchVo) {
|
||||||
cmsDocSearchVo.setIsOpen(true);
|
cmsDocSearchVo.setIsOpen(true);
|
||||||
List<CmsDocBaseDto> list = cmsDocService.selectCmsDocList(dirId, cmsDocSearchVo);
|
List<CmsDocBaseDto> list = cmsDocService.selectSetDefaultHeadImgCmsDocList(dirId, cmsDocSearchVo);
|
||||||
return getAllGenericsDataTableToPage(list);
|
return getAllGenericsDataTableToPage(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,9 @@ public class CmsDir implements Comparable<CmsDir> {
|
||||||
@ApiModelProperty(value = "排序", hidden = true)
|
@ApiModelProperty(value = "排序", hidden = true)
|
||||||
private Integer sort;
|
private Integer sort;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "文章头图")
|
||||||
|
private String headImg;
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
name = name.replaceAll(CmsConstants.DIR_SEPARATOR,
|
name = name.replaceAll(CmsConstants.DIR_SEPARATOR,
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,6 @@ public class CmsDirUpdateVo {
|
||||||
@ApiModelProperty(value = "顺序")
|
@ApiModelProperty(value = "顺序")
|
||||||
private Integer order;
|
private Integer order;
|
||||||
|
|
||||||
public CmsDir toCmsDir() {
|
@ApiModelProperty(value = "文章头图")
|
||||||
CmsDir cmsDir = new CmsDir();
|
private String headImg;
|
||||||
cmsDir.setName(name);
|
|
||||||
return cmsDir;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,7 @@ public class CmsDoc extends BaseSortEntity {
|
||||||
CmsDir cmsDir = new CmsDir();
|
CmsDir cmsDir = new CmsDir();
|
||||||
cmsDir.setId(id);
|
cmsDir.setId(id);
|
||||||
cmsDir.setName(name);
|
cmsDir.setName(name);
|
||||||
|
cmsDir.setHeadImg(headImg);
|
||||||
cmsDir.setSort(this.getSort());
|
cmsDir.setSort(this.getSort());
|
||||||
cmsDir.setCreatedAt(getCreateTime());
|
cmsDir.setCreatedAt(getCreateTime());
|
||||||
return cmsDir;
|
return cmsDir;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package com.microservices.cms.doc.domain.gitlink;
|
package com.microservices.cms.doc.domain.gitlink;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.exception.ServiceException;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -22,4 +24,12 @@ public class EntryDto implements Comparable<EntryDto> {
|
||||||
// 重写Comparable接口的compareTo方法,根据年龄升序排列,降序修改相减顺序即可
|
// 重写Comparable接口的compareTo方法,根据年龄升序排列,降序修改相减顺序即可
|
||||||
return Math.toIntExact(entryDto.getCommit().getCreated_at_unix() - this.commit.getCreated_at_unix());
|
return Math.toIntExact(entryDto.getCommit().getCreated_at_unix() - this.commit.getCreated_at_unix());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static EntryDto getEntryDtoFromJson(JSONObject subEntriesResult) {
|
||||||
|
FileEntryDto fileEntryDto = subEntriesResult.toJavaObject(FileEntryDto.class);
|
||||||
|
if (fileEntryDto == null || fileEntryDto.getEntries() == null) {
|
||||||
|
throw new ServiceException("该文章不存在");
|
||||||
|
}
|
||||||
|
return fileEntryDto.getEntries();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,17 @@ public interface CmsDocMapper {
|
||||||
*/
|
*/
|
||||||
public List<CmsDoc> selectCmsDocList(CmsDocSearchVo cmsDocSearchVo);
|
public List<CmsDoc> selectCmsDocList(CmsDocSearchVo cmsDocSearchVo);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询文章信息列表(设置默认头图为栏目头图)
|
||||||
|
*
|
||||||
|
* @param cmsDocSearchVo 文章信息
|
||||||
|
* @return 文章信息集合
|
||||||
|
*/
|
||||||
|
List<CmsDoc> selectCmsDocListSetDefaultHeadImg(CmsDocSearchVo cmsDocSearchVo);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增文章信息
|
* 新增文章信息
|
||||||
*
|
*
|
||||||
|
|
@ -172,4 +183,13 @@ public interface CmsDocMapper {
|
||||||
Long getNotAuditCmsCountByDeptId(Long deptId);
|
Long getNotAuditCmsCountByDeptId(Long deptId);
|
||||||
|
|
||||||
Long getCmsDocVisitsByDeptId(Long deptId);
|
Long getCmsDocVisitsByDeptId(Long deptId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据组织id获取专区下所有文章和栏目
|
||||||
|
* @param deptId 组织id
|
||||||
|
* @return 文章和栏目列表
|
||||||
|
*/
|
||||||
|
List<CmsDoc> selectCmsDocAndDirListByDept(Long deptId);
|
||||||
|
|
||||||
|
void updateCmsDocShaByPathAndDeptId(@Param("sha") String sha, @Param("filePath") String filePath, @Param("deptId") Long deptId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ public interface ICmsAsyncService {
|
||||||
|
|
||||||
void asyncCreateBranchAndDeleteFileAndCreatePR(CmsDoc newDocWithAudit, CmsProject cmsProject);
|
void asyncCreateBranchAndDeleteFileAndCreatePR(CmsDoc newDocWithAudit, CmsProject cmsProject);
|
||||||
|
|
||||||
void asyncMoveFileToNewDir(CmsProject cmsProject, CmsDoc oldCmsDir, CmsDoc newCmsDir);
|
void asyncMoveFileToNewDir(CmsProject cmsProject, CmsDoc oldCmsDir, String newCmsDirName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 推送文章数据到搜索引擎
|
* 推送文章数据到搜索引擎
|
||||||
|
|
|
||||||
|
|
@ -288,4 +288,10 @@ public interface ICmsDocService {
|
||||||
CmsDocBaseDto selectCmsDocBaseInfoById(Long id);
|
CmsDocBaseDto selectCmsDocBaseInfoById(Long id);
|
||||||
|
|
||||||
Long getCmsDocVisitsByDeptId(Long deptId);
|
Long getCmsDocVisitsByDeptId(Long deptId);
|
||||||
|
|
||||||
|
List<CmsDocBaseDto> selectSetDefaultHeadImgCmsDocList(Long dirId, CmsDocSearchVo cmsDocSearchVo);
|
||||||
|
|
||||||
|
List<CmsDoc> selectCmsDocAndDirListByDept(Long deptId);
|
||||||
|
|
||||||
|
void updateCmsDocShaByPathAndDeptId(String sha, String filePath, Long deptId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import com.microservices.cms.project.service.ICmsProjectService;
|
||||||
import com.microservices.cms.utils.CmsConstants;
|
import com.microservices.cms.utils.CmsConstants;
|
||||||
import com.microservices.cms.utils.CmsGitLinkRequestUrl;
|
import com.microservices.cms.utils.CmsGitLinkRequestUrl;
|
||||||
import com.microservices.cms.utils.CmsUtils;
|
import com.microservices.cms.utils.CmsUtils;
|
||||||
|
import com.microservices.cms.utils.CustomExecutorFactory;
|
||||||
import com.microservices.common.core.constant.CacheConstants;
|
import com.microservices.common.core.constant.CacheConstants;
|
||||||
import com.microservices.common.core.constant.Constants;
|
import com.microservices.common.core.constant.Constants;
|
||||||
import com.microservices.common.core.constant.SecurityConstants;
|
import com.microservices.common.core.constant.SecurityConstants;
|
||||||
|
|
@ -24,6 +25,7 @@ import com.microservices.common.core.exception.ServiceException;
|
||||||
import com.microservices.common.core.utils.DateUtils;
|
import com.microservices.common.core.utils.DateUtils;
|
||||||
import com.microservices.common.core.utils.StringUtils;
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
import com.microservices.common.core.utils.html.EscapeUtil;
|
import com.microservices.common.core.utils.html.EscapeUtil;
|
||||||
|
import com.microservices.common.core.utils.sign.Base64;
|
||||||
import com.microservices.common.core.utils.uuid.IdUtils;
|
import com.microservices.common.core.utils.uuid.IdUtils;
|
||||||
import com.microservices.common.httpClient.constant.GitLinkConstants;
|
import com.microservices.common.httpClient.constant.GitLinkConstants;
|
||||||
import com.microservices.common.httpClient.service.HttpAPIService;
|
import com.microservices.common.httpClient.service.HttpAPIService;
|
||||||
|
|
@ -47,6 +49,7 @@ import org.springframework.util.DigestUtils;
|
||||||
|
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
@ -93,6 +96,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
||||||
private RemoteZoneService remoteZoneService;
|
private RemoteZoneService remoteZoneService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private RequestConfig config;
|
private RequestConfig config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步设置文章更新时间
|
* 异步设置文章更新时间
|
||||||
*
|
*
|
||||||
|
|
@ -109,7 +113,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
||||||
} else {
|
} else {
|
||||||
redisService.setCacheObject(updateDocIntervalKey, cmsProject.getName(), 1L, TimeUnit.MINUTES);
|
redisService.setCacheObject(updateDocIntervalKey, cmsProject.getName(), 1L, TimeUnit.MINUTES);
|
||||||
}
|
}
|
||||||
CmsDocSearchVo cmsDocSearch=new CmsDocSearchVo();
|
CmsDocSearchVo cmsDocSearch = new CmsDocSearchVo();
|
||||||
cmsDocSearch.setDeptId(cmsProject.getDeptId());
|
cmsDocSearch.setDeptId(cmsProject.getDeptId());
|
||||||
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocList(cmsDocSearch);
|
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocList(cmsDocSearch);
|
||||||
for (EntryDto entryDto : entryDtoList) {
|
for (EntryDto entryDto : entryDtoList) {
|
||||||
|
|
@ -150,7 +154,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
||||||
webhook.put("eventCondition", "push");
|
webhook.put("eventCondition", "push");
|
||||||
webhook.put("http_method", "POST");
|
webhook.put("http_method", "POST");
|
||||||
webhook.put("secret", "");
|
webhook.put("secret", "");
|
||||||
webhook.put("url", gatewayUrl+"/cms/doc/open/dept/"+cmsProject.getDeptId());
|
webhook.put("url", gatewayUrl + "/cms/doc/open/dept/" + cmsProject.getDeptId());
|
||||||
webhook.put("events", new String[]{"push"});
|
webhook.put("events", new String[]{"push"});
|
||||||
jsonObject.put("webhook", webhook);
|
jsonObject.put("webhook", webhook);
|
||||||
//增加Webhook
|
//增加Webhook
|
||||||
|
|
@ -231,7 +235,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncDocAddedData(CmsProject cmsProject, List<String> addedList) {
|
private void syncDocAddedData(CmsProject cmsProject, List<String> addedList) {
|
||||||
for (String addedFilePath:addedList) {
|
for (String addedFilePath : addedList) {
|
||||||
try {
|
try {
|
||||||
String[] filePathList = addedFilePath.split("/");
|
String[] filePathList = addedFilePath.split("/");
|
||||||
if (filePathList.length != 2) {
|
if (filePathList.length != 2) {
|
||||||
|
|
@ -250,15 +254,15 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
||||||
syncCreateDoc(entry, dirName, cmsProject.getDeptId(), fileEntry.getLast_commit());
|
syncCreateDoc(entry, dirName, cmsProject.getDeptId(), fileEntry.getLast_commit());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}catch (Exception e){
|
} catch (Exception e) {
|
||||||
logger.error("[{}]同步新增文章发生异常:{}"
|
logger.error("[{}]同步新增文章发生异常:{}"
|
||||||
, cmsProject.getName(), e.getMessage());
|
, cmsProject.getName(), e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncDocRemovedData(CmsProject cmsProject,List<String> removedList) {
|
private void syncDocRemovedData(CmsProject cmsProject, List<String> removedList) {
|
||||||
for (String removedFilePath:removedList) {
|
for (String removedFilePath : removedList) {
|
||||||
try {
|
try {
|
||||||
String[] filePathList = removedFilePath.split("/");
|
String[] filePathList = removedFilePath.split("/");
|
||||||
if (filePathList.length != 2) {
|
if (filePathList.length != 2) {
|
||||||
|
|
@ -357,7 +361,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
||||||
cmsDocSearch.setDeptId(cmsDir.getDeptId());
|
cmsDocSearch.setDeptId(cmsDir.getDeptId());
|
||||||
cmsDocSearch.setDirName(cmsDir.getName());
|
cmsDocSearch.setDirName(cmsDir.getName());
|
||||||
cmsDocSearch.setIsDir(false);
|
cmsDocSearch.setIsDir(false);
|
||||||
List<CmsDoc> cmsDocList=cmsDocMapper.selectCmsDocList(cmsDocSearch);
|
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocList(cmsDocSearch);
|
||||||
//获取数据库所有文件的filePath
|
//获取数据库所有文件的filePath
|
||||||
List<String> databaseFilePathList = cmsDocList.stream().map(CmsDoc::getFilePath).collect(Collectors.toList());
|
List<String> databaseFilePathList = cmsDocList.stream().map(CmsDoc::getFilePath).collect(Collectors.toList());
|
||||||
//获取需要新增的文章
|
//获取需要新增的文章
|
||||||
|
|
@ -383,16 +387,16 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
||||||
@Override
|
@Override
|
||||||
public void asyncDocData(Long deptId, String bodyStr) {
|
public void asyncDocData(Long deptId, String bodyStr) {
|
||||||
//防止多次操作同时执行,将同步内容放入队列,根据先后时间执行同步动作
|
//防止多次操作同时执行,将同步内容放入队列,根据先后时间执行同步动作
|
||||||
String cmsSyncDeptIdKey=CacheConstants.CMS_SYNC_DEPT_ID_KEY+deptId;
|
String cmsSyncDeptIdKey = CacheConstants.CMS_SYNC_DEPT_ID_KEY + deptId;
|
||||||
//为当前同步操作生成UUID,若拿到的UUID为自身,则执行本次同步动作
|
//为当前同步操作生成UUID,若拿到的UUID为自身,则执行本次同步动作
|
||||||
String UUID= IdUtils.fastSimpleUUID();
|
String UUID = IdUtils.fastSimpleUUID();
|
||||||
redisService.leftPush(cmsSyncDeptIdKey, UUID);
|
redisService.leftPush(cmsSyncDeptIdKey, UUID);
|
||||||
//设置缓存过期时间,防止异常情况导致同步无法继续执行
|
//设置缓存过期时间,防止异常情况导致同步无法继续执行
|
||||||
redisService.expire(cmsSyncDeptIdKey, 3600, TimeUnit.SECONDS);
|
redisService.expire(cmsSyncDeptIdKey, 3600, TimeUnit.SECONDS);
|
||||||
String currentUUID = String.valueOf(redisService.listIndexOf(cmsSyncDeptIdKey, -1));
|
String currentUUID = String.valueOf(redisService.listIndexOf(cmsSyncDeptIdKey, -1));
|
||||||
//设置最大循环阈值,防止意外情况导致死循环(7200次,约1小时左右)
|
//设置最大循环阈值,防止意外情况导致死循环(7200次,约1小时左右)
|
||||||
int threshold=7200;
|
int threshold = 7200;
|
||||||
while (!UUID.equals(currentUUID)&&threshold!=0){
|
while (!UUID.equals(currentUUID) && threshold != 0) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
|
@ -402,41 +406,41 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
||||||
threshold--;
|
threshold--;
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try {
|
||||||
CmsProject cmsProject=cmsProjectService.selectCmsProjectByDeptId(deptId);
|
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(deptId);
|
||||||
JSONObject body=JSONObject.parseObject(bodyStr);
|
JSONObject body = JSONObject.parseObject(bodyStr);
|
||||||
//获取本次推送中Commit总数
|
//获取本次推送中Commit总数
|
||||||
Integer totalCommits=body.getInteger("total_commits");
|
Integer totalCommits = body.getInteger("total_commits");
|
||||||
//从webhook请求中获取本次提交内容
|
//从webhook请求中获取本次提交内容
|
||||||
JSONArray commits=body.getJSONArray("commits");
|
JSONArray commits = body.getJSONArray("commits");
|
||||||
//当commit总数大于提交的列表数量时,代表此次PUSH未携带所有commit,此时进行一次全量同步
|
//当commit总数大于提交的列表数量时,代表此次PUSH未携带所有commit,此时进行一次全量同步
|
||||||
if(totalCommits!=null
|
if (totalCommits != null
|
||||||
&&commits!=null
|
&& commits != null
|
||||||
&&totalCommits>commits.size()){
|
&& totalCommits > commits.size()) {
|
||||||
fullSyncDocData(cmsProject);
|
fullSyncDocData(cmsProject);
|
||||||
}else{
|
} else {
|
||||||
for (int i = commits.size()-1; i >=0 ; i--) {
|
for (int i = commits.size() - 1; i >= 0; i--) {
|
||||||
JSONObject commit=commits.getJSONObject(i);
|
JSONObject commit = commits.getJSONObject(i);
|
||||||
//获取新增的文件列表
|
//获取新增的文件列表
|
||||||
JSONArray addedList=commit.getJSONArray("added");
|
JSONArray addedList = commit.getJSONArray("added");
|
||||||
if(addedList!=null){
|
if (addedList != null) {
|
||||||
syncDocAddedData(cmsProject,addedList.toJavaList(String.class));
|
syncDocAddedData(cmsProject, addedList.toJavaList(String.class));
|
||||||
}
|
}
|
||||||
//获取删除的文件列表
|
//获取删除的文件列表
|
||||||
JSONArray removedList=commit.getJSONArray("removed");
|
JSONArray removedList = commit.getJSONArray("removed");
|
||||||
if(removedList!=null){
|
if (removedList != null) {
|
||||||
syncDocRemovedData(cmsProject,removedList.toJavaList(String.class));
|
syncDocRemovedData(cmsProject, removedList.toJavaList(String.class));
|
||||||
}
|
}
|
||||||
//获取更新的文件列表
|
//获取更新的文件列表
|
||||||
JSONArray modifiedList=commit.getJSONArray("modified");
|
JSONArray modifiedList = commit.getJSONArray("modified");
|
||||||
if(modifiedList!=null){
|
if (modifiedList != null) {
|
||||||
syncDocModifiedData(cmsProject, modifiedList.toJavaList(String.class));
|
syncDocModifiedData(cmsProject, modifiedList.toJavaList(String.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("同步文章时发送异常:{}", e.getMessage());
|
logger.error("同步文章时发送异常:{}", e.getMessage());
|
||||||
}finally {
|
} finally {
|
||||||
//本次同步执行完成后,再弹出该UUID
|
//本次同步执行完成后,再弹出该UUID
|
||||||
redisService.rightPop(cmsSyncDeptIdKey, 500, TimeUnit.MICROSECONDS);
|
redisService.rightPop(cmsSyncDeptIdKey, 500, TimeUnit.MICROSECONDS);
|
||||||
}
|
}
|
||||||
|
|
@ -469,12 +473,12 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void syncCreateDir(String dirName,EntryDto entry,CmsProject cmsProject,boolean isCreateKeep){
|
public void syncCreateDir(String dirName, EntryDto entry, CmsProject cmsProject, boolean isCreateKeep) {
|
||||||
CmsDoc cmsDir = new CmsDoc();
|
CmsDoc cmsDir = new CmsDoc();
|
||||||
cmsDir.setName(dirName);
|
cmsDir.setName(dirName);
|
||||||
cmsDir.setCreateTime(entry.getCommit().getCreated_at());
|
cmsDir.setCreateTime(entry.getCommit().getCreated_at());
|
||||||
boolean insertResult;
|
boolean insertResult;
|
||||||
if(isCreateKeep){
|
if (isCreateKeep) {
|
||||||
//若该栏目不存在,检查文件夹中是否存在.keep文件
|
//若该栏目不存在,检查文件夹中是否存在.keep文件
|
||||||
JSONObject subEntriesResult = gitLinkRequestHelper.doGet(
|
JSONObject subEntriesResult = gitLinkRequestHelper.doGet(
|
||||||
CmsGitLinkRequestUrl.GET_FILE_SUB_ENTRIES(cmsProject, cmsDir.getName(), CmsConstants.BRANCH_MASTER));
|
CmsGitLinkRequestUrl.GET_FILE_SUB_ENTRIES(cmsProject, cmsDir.getName(), CmsConstants.BRANCH_MASTER));
|
||||||
|
|
@ -484,14 +488,14 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
||||||
|
|
||||||
if (keepEntry != null) {
|
if (keepEntry != null) {
|
||||||
//若存在,则在数据库中创建该栏目
|
//若存在,则在数据库中创建该栏目
|
||||||
insertResult=createCmsDir(cmsDir,cmsProject.getDeptId(),keepEntry);
|
insertResult = createCmsDir(cmsDir, cmsProject.getDeptId(), keepEntry);
|
||||||
} else {
|
} else {
|
||||||
//若不存在,则在数据库中创建该栏目,同时在仓库的该文件夹下创建.keep文件
|
//若不存在,则在数据库中创建该栏目,同时在仓库的该文件夹下创建.keep文件
|
||||||
insertResult = cmsDocService.insertCmsDocDir(cmsProject.getDeptId(), cmsDir.copyToCmsDir());
|
insertResult = cmsDocService.insertCmsDocDir(cmsProject.getDeptId(), cmsDir.copyToCmsDir());
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
//若不自动创建,则在数据库中创建根据文件名该栏目
|
//若不自动创建,则在数据库中创建根据文件名该栏目
|
||||||
insertResult=createCmsDir(cmsDir,cmsProject.getDeptId(),entry);
|
insertResult = createCmsDir(cmsDir, cmsProject.getDeptId(), entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -500,7 +504,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean createCmsDir(CmsDoc cmsDir,Long deptId,EntryDto entry){
|
private boolean createCmsDir(CmsDoc cmsDir, Long deptId, EntryDto entry) {
|
||||||
cmsDir.setIsDir(true);
|
cmsDir.setIsDir(true);
|
||||||
cmsDir.setFilePath(cmsDir.getDirPath());
|
cmsDir.setFilePath(cmsDir.getDirPath());
|
||||||
cmsDir.setDeptId(deptId);
|
cmsDir.setDeptId(deptId);
|
||||||
|
|
@ -678,6 +682,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
||||||
requestBody);
|
requestBody);
|
||||||
cmsDoc.setAuditPrNumber(result.getString("pull_request_number") + "-" + result.getString("pull_request_id"));
|
cmsDoc.setAuditPrNumber(result.getString("pull_request_number") + "-" + result.getString("pull_request_id"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CmsDoc updateCmsDocDatabaseAndUpdateForGitLink(CmsDoc oldCmsDoc, CmsDocDto cmsDocDto, String branchName) {
|
public CmsDoc updateCmsDocDatabaseAndUpdateForGitLink(CmsDoc oldCmsDoc, CmsDocDto cmsDocDto, String branchName) {
|
||||||
if (oldCmsDoc == null) {
|
if (oldCmsDoc == null) {
|
||||||
|
|
@ -871,27 +876,87 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Async
|
public void asyncMoveFileToNewDir(CmsProject cmsProject, CmsDoc oldCmsDir, String newCmsDirName) {
|
||||||
public void asyncMoveFileToNewDir(CmsProject cmsProject, CmsDoc oldCmsDir, CmsDoc newCmsDir) {
|
|
||||||
try {
|
try {
|
||||||
remoteZoneService.lockCmsByDeptId(cmsProject.getDeptId(), 1, SecurityConstants.INNER);
|
JSONObject dirFilesJson = gitLinkRequestHelper.doGet(CmsGitLinkRequestUrl.GET_DIR_SUB_ENTRIES(
|
||||||
//创建新栏目
|
cmsProject,
|
||||||
String message = String.format("重命名栏目:由[%s]重命名为[%s]", oldCmsDir.getName(), newCmsDir.getName());
|
oldCmsDir.getName(),
|
||||||
cmsDocService.createFileByGitLink(newCmsDir, message, "");
|
CmsConstants.BRANCH_MASTER));
|
||||||
//在数据库中重命名该栏目,防止后续操作推送的WebHook重复创建栏目
|
List<EntryDto> entryDtoList = cmsDocService.getEntriesFromRequestResult(dirFilesJson, cmsProject, false);
|
||||||
cmsDocService.updateCmsCommonDatabase(newCmsDir, CmsConstants.BRANCH_MASTER);
|
CountDownLatch countDownLatch = new CountDownLatch(entryDtoList.size());
|
||||||
//将原栏目中所有文章移动到新栏目中
|
// 异步获取每篇文章内容
|
||||||
moveCmsDocToNewCmsDir(cmsProject, oldCmsDir.getName(), newCmsDir.getName(), message);
|
entryDtoList.forEach(entryDto -> {
|
||||||
//删除旧栏目
|
CustomExecutorFactory.threadPoolExecutor.execute(() -> {
|
||||||
deleteCmsDocByGitLink(cmsProject, oldCmsDir);
|
try {
|
||||||
|
JSONObject fileSubEntriesResult = gitLinkRequestHelper.doGet(
|
||||||
|
CmsGitLinkRequestUrl.GET_FILE_SUB_ENTRIES(
|
||||||
|
cmsProject,
|
||||||
|
entryDto.getPath(),
|
||||||
|
CmsConstants.BRANCH_MASTER));
|
||||||
|
EntryDto cmsDocEntryDto = EntryDto.getEntryDtoFromJson(fileSubEntriesResult);
|
||||||
|
entryDto.setContent(cmsDocEntryDto.getContent());
|
||||||
|
} finally {
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
countDownLatch.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.error("栏目重命名失败(将对应代码库中文章移动至新文件夹失败):{}", e.getMessage());
|
||||||
|
throw new ServiceException("栏目重命名失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (EntryDto entryDto : entryDtoList) {
|
||||||
|
JSONObject updateFileBody = new JSONObject();
|
||||||
|
updateFileBody.put("branch", CmsConstants.BRANCH_MASTER);
|
||||||
|
updateFileBody.put("message", "移动文章至新栏目");
|
||||||
|
updateFileBody.put("from_path", entryDto.getPath());
|
||||||
|
String newFilePath = newCmsDirName + "/" + entryDto.getName();
|
||||||
|
updateFileBody.put("filepath", newFilePath);
|
||||||
|
updateFileBody.put("base64_filepath", Base64.contentToBase64(newFilePath));
|
||||||
|
updateFileBody.put("sha", entryDto.getSha());
|
||||||
|
String content = entryDto.getContent();
|
||||||
|
if (content == null) {
|
||||||
|
content = "";
|
||||||
|
}
|
||||||
|
updateFileBody.put("content", content);
|
||||||
|
gitLinkRequestHelper.doPut(CmsGitLinkRequestUrl.UPDATE_FILE(cmsProject), updateFileBody);
|
||||||
|
}
|
||||||
|
CmsDoc newCmsDoc = oldCmsDir.copyToRenameCmsDir(newCmsDirName);
|
||||||
|
//在数据库中重命名该栏目
|
||||||
|
cmsDocService.updateCmsCommonDatabase(newCmsDoc, CmsConstants.BRANCH_MASTER);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("重命名栏目失败(原栏目名称[{}],新栏目名称[{}]):{}", oldCmsDir.getName(), newCmsDir.getName(), e.getMessage());
|
logger.error("重命名栏目失败(原栏目名称[{}],新栏目名称[{}]):{}", oldCmsDir.getName(), newCmsDirName, e.getMessage());
|
||||||
throw new ServiceException("重命名栏目失败(原栏目名称[" + oldCmsDir.getName() + "],新栏目名称[" + newCmsDir.getName() + "])");
|
throw new ServiceException("重命名栏目失败(原栏目名称[" + oldCmsDir.getName() + "],新栏目名称[" + newCmsDirName + "])");
|
||||||
} finally {
|
|
||||||
remoteZoneService.lockCmsByDeptId(cmsProject.getDeptId(), 0, SecurityConstants.INNER);
|
|
||||||
}
|
}
|
||||||
|
// finally {
|
||||||
|
// remoteZoneService.lockCmsByDeptId(cmsProject.getDeptId(), 0, SecurityConstants.INNER);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// @Async
|
||||||
|
// public void asyncMoveFileToNewDir(CmsProject cmsProject, CmsDoc oldCmsDir, CmsDoc newCmsDir) {
|
||||||
|
// try {
|
||||||
|
// remoteZoneService.lockCmsByDeptId(cmsProject.getDeptId(), 1, SecurityConstants.INNER);
|
||||||
|
// //创建新栏目
|
||||||
|
// String message = String.format("重命名栏目:由[%s]重命名为[%s]", oldCmsDir.getName(), newCmsDir.getName());
|
||||||
|
// cmsDocService.createFileByGitLink(newCmsDir, message, "");
|
||||||
|
// //在数据库中重命名该栏目,防止后续操作推送的WebHook重复创建栏目
|
||||||
|
// cmsDocService.updateCmsCommonDatabase(newCmsDir, CmsConstants.BRANCH_MASTER);
|
||||||
|
// //将原栏目中所有文章移动到新栏目中
|
||||||
|
// moveCmsDocToNewCmsDir(cmsProject, oldCmsDir.getName(), newCmsDir.getName(), message);
|
||||||
|
// //删除旧栏目
|
||||||
|
// deleteCmsDocByGitLink(cmsProject, oldCmsDir);
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// logger.error("重命名栏目失败(原栏目名称[{}],新栏目名称[{}]):{}", oldCmsDir.getName(), newCmsDir.getName(), e.getMessage());
|
||||||
|
// throw new ServiceException("重命名栏目失败(原栏目名称[" + oldCmsDir.getName() + "],新栏目名称[" + newCmsDir.getName() + "])");
|
||||||
|
// } finally {
|
||||||
|
// remoteZoneService.lockCmsByDeptId(cmsProject.getDeptId(), 0, SecurityConstants.INNER);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@Async
|
@Async
|
||||||
@Override
|
@Override
|
||||||
public void pushDocDataSearchEngine(CmsDoc cmsDoc) {
|
public void pushDocDataSearchEngine(CmsDoc cmsDoc) {
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
||||||
|
|
||||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(cmsDoc.getDeptId());
|
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(cmsDoc.getDeptId());
|
||||||
|
|
||||||
String branchName = DocAuditStatus.AUDIT_PASS.getAuditCode().equals(cmsDoc.getAuditStatus()) ? CmsConstants.BRANCH_MASTER : cmsDoc.getAuditTmpBranchName();
|
String branchName = DocAuditStatus.AUDIT_PASS.getAuditCode().equals(cmsDoc.getAuditStatus()) ? CmsConstants.BRANCH_MASTER : cmsDoc.getAuditTmpBranchName();
|
||||||
FileEntryDto fileEntryDto = getFileEntryDto(cmsProject, cmsDoc.getFilePath(), branchName);
|
FileEntryDto fileEntryDto = getFileEntryDto(cmsProject, cmsDoc.getFilePath(), branchName);
|
||||||
EntryDto entryDto = fileEntryDto.getEntries();
|
EntryDto entryDto = fileEntryDto.getEntries();
|
||||||
|
|
||||||
|
|
@ -197,20 +197,21 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
||||||
@Override
|
@Override
|
||||||
public void updateCmsDir(Long id, CmsDirUpdateVo cmsDirUpdateVo) {
|
public void updateCmsDir(Long id, CmsDirUpdateVo cmsDirUpdateVo) {
|
||||||
CmsDoc oldCmsDir = selectCmsDir(id);
|
CmsDoc oldCmsDir = selectCmsDir(id);
|
||||||
checkCmsLockStatus(oldCmsDir.getDeptId());
|
|
||||||
//设置栏目排序
|
//设置栏目排序
|
||||||
setCmsSort(cmsDirUpdateVo.getOrder(), oldCmsDir, false, null);
|
setCmsSort(cmsDirUpdateVo.getOrder(), oldCmsDir, false, null);
|
||||||
|
oldCmsDir.setHeadImg(cmsDirUpdateVo.getHeadImg());
|
||||||
updateCmsCommonDatabase(oldCmsDir, CmsConstants.BRANCH_MASTER);
|
updateCmsCommonDatabase(oldCmsDir, CmsConstants.BRANCH_MASTER);
|
||||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(oldCmsDir.getDeptId());
|
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(oldCmsDir.getDeptId());
|
||||||
CmsDoc newCmsDir = oldCmsDir.copyToRenameCmsDir(cmsDirUpdateVo.getName());
|
String newCmsDirName = cmsDirUpdateVo.getName();
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(newCmsDir.getName()) && !newCmsDir.getName().equals(oldCmsDir.getName())) {
|
if (StringUtils.isNotEmpty(newCmsDirName) && !newCmsDirName.equals(oldCmsDir.getName())) {
|
||||||
CmsDoc cmsDir = cmsDocMapper.selectCmsDocDirByNameAndDeptId(newCmsDir.getName(), oldCmsDir.getDeptId());
|
CmsDoc cmsDir = cmsDocMapper.selectCmsDocDirByNameAndDeptId(newCmsDirName, oldCmsDir.getDeptId());
|
||||||
if (cmsDir != null) {
|
if (cmsDir != null) {
|
||||||
throw new ServiceException("栏目名称已存在,不允许进行重命名(新栏目名称[" + newCmsDir.getName() + "])");
|
throw new ServiceException("栏目名称已存在,不允许进行重命名(新栏目名称[" + newCmsDirName + "])");
|
||||||
}
|
|
||||||
cmsAsyncService.asyncMoveFileToNewDir(cmsProject, oldCmsDir, newCmsDir);
|
|
||||||
}
|
}
|
||||||
|
// 异步修改栏目名称(将仓库内原文件夹下所有文章移动到新文件夹下)
|
||||||
|
cmsAsyncService.asyncMoveFileToNewDir(cmsProject, oldCmsDir, newCmsDirName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -237,7 +238,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
||||||
cmsDocSearchVo.setDirName(cmsDir.getName());
|
cmsDocSearchVo.setDirName(cmsDir.getName());
|
||||||
cmsDocSearchVo.setDeptId(cmsDir.getDeptId());
|
cmsDocSearchVo.setDeptId(cmsDir.getDeptId());
|
||||||
cmsDocSearchVo.setIsDir(false);
|
cmsDocSearchVo.setIsDir(false);
|
||||||
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocList(cmsDocSearchVo);
|
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocListSetDefaultHeadImg(cmsDocSearchVo);
|
||||||
List<CompletableFuture<CmsDocDetailDto>> futures = new ArrayList();
|
List<CompletableFuture<CmsDocDetailDto>> futures = new ArrayList();
|
||||||
for (CmsDoc cmsDoc : cmsDocList) {
|
for (CmsDoc cmsDoc : cmsDocList) {
|
||||||
CompletableFuture<CmsDocDetailDto> future = CompletableFuture.supplyAsync(() -> {
|
CompletableFuture<CmsDocDetailDto> future = CompletableFuture.supplyAsync(() -> {
|
||||||
|
|
@ -283,6 +284,21 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
||||||
return selectCmsDocListByDatabase(dirId, cmsDocSearchVo);
|
return selectCmsDocListByDatabase(dirId, cmsDocSearchVo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CmsDocBaseDto> selectSetDefaultHeadImgCmsDocList(Long dirId, CmsDocSearchVo cmsDocSearchVo) {
|
||||||
|
return selectCmsDocListSetDefaultHeadImgByDatabase(dirId, cmsDocSearchVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CmsDoc> selectCmsDocAndDirListByDept(Long deptId) {
|
||||||
|
return cmsDocMapper.selectCmsDocAndDirListByDept(deptId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateCmsDocShaByPathAndDeptId(String sha, String filePath, Long deptId) {
|
||||||
|
cmsDocMapper.updateCmsDocShaByPathAndDeptId(sha,filePath,deptId);
|
||||||
|
}
|
||||||
|
|
||||||
private List<CmsDocBaseDto> selectCmsDocListByDatabase(Long dirId, CmsDocSearchVo cmsDocSearchVo) {
|
private List<CmsDocBaseDto> selectCmsDocListByDatabase(Long dirId, CmsDocSearchVo cmsDocSearchVo) {
|
||||||
CmsDoc cmsDocDir = selectCmsDir(dirId);
|
CmsDoc cmsDocDir = selectCmsDir(dirId);
|
||||||
|
|
||||||
|
|
@ -295,6 +311,24 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
||||||
return cmsDocList.stream().map(CmsDoc::copyToCmsDocBaseDto).collect(Collectors.toList());
|
return cmsDocList.stream().map(CmsDoc::copyToCmsDocBaseDto).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置文章默认头图为栏目头图
|
||||||
|
* @param dirId 栏目id
|
||||||
|
* @param cmsDocSearchVo 文章查询条件
|
||||||
|
* @return 文章列表
|
||||||
|
*/
|
||||||
|
private List<CmsDocBaseDto> selectCmsDocListSetDefaultHeadImgByDatabase(Long dirId, CmsDocSearchVo cmsDocSearchVo) {
|
||||||
|
CmsDoc cmsDocDir = selectCmsDir(dirId);
|
||||||
|
|
||||||
|
cmsDocSearchVo.setDeptId(cmsDocDir.getDeptId());
|
||||||
|
cmsDocSearchVo.setDirName(cmsDocDir.getName());
|
||||||
|
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocListSetDefaultHeadImg(cmsDocSearchVo);
|
||||||
|
if (cmsDocList == null || cmsDocList.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return cmsDocList.stream().map(CmsDoc::copyToCmsDocBaseDto).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查专区资讯是否处于锁定状态,若处于则抛出异常
|
* 检查专区资讯是否处于锁定状态,若处于则抛出异常
|
||||||
*
|
*
|
||||||
|
|
@ -552,6 +586,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
||||||
throw new ServiceException("计算字符串Sha出错");
|
throw new ServiceException("计算字符串Sha出错");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCmsSort(Integer order, CmsDoc oldCmsDoc, boolean isChangeOnDir, String isHomePage) {
|
public void setCmsSort(Integer order, CmsDoc oldCmsDoc, boolean isChangeOnDir, String isHomePage) {
|
||||||
//调整文章/栏目顺序
|
//调整文章/栏目顺序
|
||||||
|
|
@ -697,7 +732,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
||||||
Long originCmsDocId = Long.parseLong(oldCmsDoc.getAuditType().split("-")[1]);
|
Long originCmsDocId = Long.parseLong(oldCmsDoc.getAuditType().split("-")[1]);
|
||||||
CmsDoc originCmsDoc = cmsDocMapper.selectCmsDocById(originCmsDocId);
|
CmsDoc originCmsDoc = cmsDocMapper.selectCmsDocById(originCmsDocId);
|
||||||
deleteTmpBranchIfBranchExist(oldCmsDoc);
|
deleteTmpBranchIfBranchExist(oldCmsDoc);
|
||||||
BeanUtils.copyProperties(originCmsDoc,oldCmsDoc);
|
BeanUtils.copyProperties(originCmsDoc, oldCmsDoc);
|
||||||
cmsDocMapper.deleteCmsDocById(id);
|
cmsDocMapper.deleteCmsDocById(id);
|
||||||
} else
|
} else
|
||||||
//文章审核类型:create 直接新增文章
|
//文章审核类型:create 直接新增文章
|
||||||
|
|
@ -724,11 +759,11 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
||||||
} else
|
} else
|
||||||
//更新已发布文章
|
//更新已发布文章
|
||||||
if (oldCmsDoc.getAuditStatus().equals(DocAuditStatus.AUDIT_PASS.getAuditCode())) {
|
if (oldCmsDoc.getAuditStatus().equals(DocAuditStatus.AUDIT_PASS.getAuditCode())) {
|
||||||
//1.创建一条auditType="update-原文章id",audit_status为2,其余字段与待更新文章一致的新文章数据
|
//1.创建一条auditType="update-原文章id",audit_status为2,其余字段与待更新文章一致的新文章数据
|
||||||
newDocWithAudit = insertDocWithAudit(oldCmsDoc,
|
newDocWithAudit = insertDocWithAudit(oldCmsDoc,
|
||||||
DocAndZoneOperation.OPERATION_UPDATE.getOperationCode() + "-" + id,
|
DocAndZoneOperation.OPERATION_UPDATE.getOperationCode() + "-" + id,
|
||||||
DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||||
}
|
}
|
||||||
cmsAsyncService.asyncUpdateBranchAndFileAndCreatePR(newDocWithAudit, cmsDocDto);
|
cmsAsyncService.asyncUpdateBranchAndFileAndCreatePR(newDocWithAudit, cmsDocDto);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -785,7 +820,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
||||||
gitLinkRequestHelper.doDelete(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()));
|
gitLinkRequestHelper.doDelete(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()));
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
//忽略分支不存在异常
|
//忽略分支不存在异常
|
||||||
if(!"分支不存在!".equals(e.getMessage())) {
|
if (!"分支不存在!".equals(e.getMessage())) {
|
||||||
throw new ServiceException(e.getMessage());
|
throw new ServiceException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -863,6 +898,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
||||||
cmsDoc.setIsDir(true);
|
cmsDoc.setIsDir(true);
|
||||||
cmsDoc.setFilePath(cmsDoc.getDirPath(cmsDir.getName()));
|
cmsDoc.setFilePath(cmsDoc.getDirPath(cmsDir.getName()));
|
||||||
cmsDoc.setDeptId(deptId);
|
cmsDoc.setDeptId(deptId);
|
||||||
|
cmsDoc.setHeadImg(cmsDir.getHeadImg());
|
||||||
cmsDoc.setName(cmsDir.getName());
|
cmsDoc.setName(cmsDir.getName());
|
||||||
return insertCommonCmsDoc(cmsDoc, "创建栏目:" + cmsDir.getName(), "");
|
return insertCommonCmsDoc(cmsDoc, "创建栏目:" + cmsDir.getName(), "");
|
||||||
}
|
}
|
||||||
|
|
@ -949,7 +985,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
||||||
List<CmsDoc> cmsDocList = cmsDocMapper.selectHotCmsDocList(cmsDocInput);
|
List<CmsDoc> cmsDocList = cmsDocMapper.selectHotCmsDocList(cmsDocInput);
|
||||||
if (cmsDocList != null) {
|
if (cmsDocList != null) {
|
||||||
//todo:需检查该文章是否在GitLink中存在
|
//todo:需检查该文章是否在GitLink中存在
|
||||||
return cmsDocList.stream().map(x -> x.copyToHotCmsDocDto()).collect(Collectors.toList());
|
return cmsDocList.stream().map(CmsDoc::copyToHotCmsDocDto).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
|
|
@ -990,7 +1026,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
||||||
for (CmsDoc cmsDir : cmsDirList) {
|
for (CmsDoc cmsDir : cmsDirList) {
|
||||||
CmsDocSearchVo cmsDocSearchVo = new CmsDocSearchVo();
|
CmsDocSearchVo cmsDocSearchVo = new CmsDocSearchVo();
|
||||||
cmsDocSearchVo.setIsOpen(isOpen);
|
cmsDocSearchVo.setIsOpen(isOpen);
|
||||||
List<CmsDocBaseDto> cmsDocBaseDtoList = selectCmsDocList(cmsDir.getId(), cmsDocSearchVo);
|
List<CmsDocBaseDto> cmsDocBaseDtoList = selectSetDefaultHeadImgCmsDocList(cmsDir.getId(), cmsDocSearchVo);
|
||||||
CmsDocOverviewDto cmsDocOverviewDto = new CmsDocOverviewDto();
|
CmsDocOverviewDto cmsDocOverviewDto = new CmsDocOverviewDto();
|
||||||
cmsDocOverviewDto.setId(cmsDir.getId());
|
cmsDocOverviewDto.setId(cmsDir.getId());
|
||||||
cmsDocOverviewDto.setName(cmsDir.getName());
|
cmsDocOverviewDto.setName(cmsDir.getName());
|
||||||
|
|
@ -1104,7 +1140,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
||||||
CmsDocSearchVo cmsDocSearch = new CmsDocSearchVo();
|
CmsDocSearchVo cmsDocSearch = new CmsDocSearchVo();
|
||||||
cmsDocSearch.setDeptId(deptId);
|
cmsDocSearch.setDeptId(deptId);
|
||||||
cmsDocSearch.setIsHomepage(CmsConstants.TRUE);
|
cmsDocSearch.setIsHomepage(CmsConstants.TRUE);
|
||||||
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocList(cmsDocSearch);
|
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocListSetDefaultHeadImg(cmsDocSearch);
|
||||||
List<CmsDocBaseDto> cmsDocBaseDtoList = new ArrayList<>();
|
List<CmsDocBaseDto> cmsDocBaseDtoList = new ArrayList<>();
|
||||||
for (CmsDoc cmsDoc : cmsDocList) {
|
for (CmsDoc cmsDoc : cmsDocList) {
|
||||||
CmsDocBaseDto cmsDocBaseDto = cmsDoc.copyToCmsDocBaseDto();
|
CmsDocBaseDto cmsDocBaseDto = cmsDoc.copyToCmsDocBaseDto();
|
||||||
|
|
|
||||||
|
|
@ -95,8 +95,12 @@ public class CmsProjectController extends BaseController {
|
||||||
@GetMapping("/getProjectByDeptId/{deptId}")
|
@GetMapping("/getProjectByDeptId/{deptId}")
|
||||||
public R<String> getProjectByDeptId(
|
public R<String> getProjectByDeptId(
|
||||||
@ApiParam(name = "deptId", value = "组织Id") @PathVariable(value = "deptId") Long deptId) {
|
@ApiParam(name = "deptId", value = "组织Id") @PathVariable(value = "deptId") Long deptId) {
|
||||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(deptId);
|
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptIdAndNoException(deptId);
|
||||||
return R.ok(JSONObject.toJSONString(cmsProject));
|
if (cmsProject == null) {
|
||||||
|
return R.ok(null);
|
||||||
|
} else {
|
||||||
|
return R.ok(JSONObject.toJSONString(cmsProject));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -170,4 +174,16 @@ public class CmsProjectController extends BaseController {
|
||||||
public R<Boolean> removeByDeptId(@PathVariable(value = "deptId") Long deptId) {
|
public R<Boolean> removeByDeptId(@PathVariable(value = "deptId") Long deptId) {
|
||||||
return R.ok(cmsProjectService.deleteCmsProjectByDeptId(deptId) > 0);
|
return R.ok(cmsProjectService.deleteCmsProjectByDeptId(deptId) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化专区对应项目
|
||||||
|
*/
|
||||||
|
@RequiresPermissions("zone:project:add")
|
||||||
|
@ApiOperation("初始化专区对应项目")
|
||||||
|
@Log(title = "初始化专区对应项目", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("initCmsProject/dept/{deptId}")
|
||||||
|
public AjaxResult initCmsProject(
|
||||||
|
@ApiParam(name = "deptId", value = "组织Id") @PathVariable(value = "deptId") Long deptId) {
|
||||||
|
return toAjax(cmsProjectService.initZoneCmsProjectByDept(deptId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,4 +78,8 @@ public interface ICmsProjectService {
|
||||||
Boolean updateCmsProjectByDept(SysDept dept);
|
Boolean updateCmsProjectByDept(SysDept dept);
|
||||||
|
|
||||||
boolean operateProtectedBranchByZoneAuditSetting(String userName, String identifier, Long deptId, String operationType);
|
boolean operateProtectedBranchByZoneAuditSetting(String userName, String identifier, Long deptId, String operationType);
|
||||||
|
|
||||||
|
boolean initZoneCmsProjectByDept(Long deptId);
|
||||||
|
|
||||||
|
CmsProject selectCmsProjectByDeptIdAndNoException(Long deptId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,23 @@
|
||||||
package com.microservices.cms.project.service.impl;
|
package com.microservices.cms.project.service.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.microservices.cms.doc.domain.CmsDir;
|
import com.microservices.cms.doc.domain.*;
|
||||||
import com.microservices.cms.doc.domain.CmsDocBaseDto;
|
|
||||||
import com.microservices.cms.doc.domain.CmsDocSearchVo;
|
|
||||||
import com.microservices.cms.doc.service.ICmsAsyncService;
|
import com.microservices.cms.doc.service.ICmsAsyncService;
|
||||||
import com.microservices.cms.doc.service.ICmsDocService;
|
import com.microservices.cms.doc.service.ICmsDocService;
|
||||||
import com.microservices.cms.project.domain.CmsProject;
|
import com.microservices.cms.project.domain.CmsProject;
|
||||||
import com.microservices.cms.project.mapper.CmsProjectMapper;
|
import com.microservices.cms.project.mapper.CmsProjectMapper;
|
||||||
import com.microservices.cms.project.service.ICmsProjectService;
|
import com.microservices.cms.project.service.ICmsProjectService;
|
||||||
|
import com.microservices.cms.utils.CmsConstants;
|
||||||
import com.microservices.cms.utils.CmsGitLinkRequestUrl;
|
import com.microservices.cms.utils.CmsGitLinkRequestUrl;
|
||||||
|
import com.microservices.common.core.constant.HttpStatus;
|
||||||
import com.microservices.common.core.constant.SecurityConstants;
|
import com.microservices.common.core.constant.SecurityConstants;
|
||||||
import com.microservices.common.core.enums.SystemRole;
|
import com.microservices.common.core.enums.SystemRole;
|
||||||
import com.microservices.common.core.exception.ServiceException;
|
import com.microservices.common.core.exception.ServiceException;
|
||||||
import com.microservices.common.core.utils.PinYinStringUtils;
|
import com.microservices.common.core.utils.PinYinStringUtils;
|
||||||
import com.microservices.common.core.utils.StringUtils;
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
import com.microservices.common.datascope.annotation.DataScope;
|
import com.microservices.common.datascope.annotation.DataScope;
|
||||||
|
import com.microservices.common.httpClient.domain.GitLinkRequestUrl;
|
||||||
import com.microservices.common.httpClient.util.GitLinkRequestHelper;
|
import com.microservices.common.httpClient.util.GitLinkRequestHelper;
|
||||||
import com.microservices.system.api.RemoteDeptService;
|
import com.microservices.system.api.RemoteDeptService;
|
||||||
import com.microservices.system.api.RemoteUserService;
|
import com.microservices.system.api.RemoteUserService;
|
||||||
|
|
@ -23,6 +25,7 @@ import com.microservices.system.api.domain.SysDept;
|
||||||
import com.microservices.system.api.domain.SysRole;
|
import com.microservices.system.api.domain.SysRole;
|
||||||
import com.microservices.system.api.domain.SysUser;
|
import com.microservices.system.api.domain.SysUser;
|
||||||
import com.microservices.system.api.utils.FeignUtils;
|
import com.microservices.system.api.utils.FeignUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
|
@ -37,6 +40,7 @@ import java.util.List;
|
||||||
* @author otto
|
* @author otto
|
||||||
* @date 2023-03-27
|
* @date 2023-03-27
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class CmsProjectServiceImpl implements ICmsProjectService {
|
public class CmsProjectServiceImpl implements ICmsProjectService {
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|
@ -228,6 +232,75 @@ public class CmsProjectServiceImpl implements ICmsProjectService {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean initZoneCmsProjectByDept(Long deptId) {
|
||||||
|
boolean initResult = false;
|
||||||
|
CmsProject cmsProject = cmsProjectMapper.selectCmsProjectByDeptId(deptId);
|
||||||
|
if (cmsProject != null) {
|
||||||
|
JSONObject project = null;
|
||||||
|
try {
|
||||||
|
project = gitLinkRequestHelper.doGet(CmsGitLinkRequestUrl.GET_PROJECT_DETAIL(cmsProject.getUsername(), cmsProject.getIdentifier()));
|
||||||
|
} catch (ServiceException e) {
|
||||||
|
if (!e.getCode().equals(HttpStatus.NOT_FOUND)) {
|
||||||
|
throw new ServiceException(e.getCode(), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (project != null) {
|
||||||
|
throw new ServiceException("专区对应项目已存在,不能重复初始化");
|
||||||
|
} else {
|
||||||
|
Long organizationId = getOrganizationId();
|
||||||
|
// 创建专区对应项目
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("user_id", organizationId);
|
||||||
|
jsonObject.put("name", cmsProject.getName());
|
||||||
|
jsonObject.put("repository_name", cmsProject.getIdentifier());
|
||||||
|
jsonObject.put("description", cmsProject.getDescription());
|
||||||
|
jsonObject.put("private", false);
|
||||||
|
//调用GitLink接口创建项目
|
||||||
|
JSONObject result = gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.CREATE_PROJECT(), jsonObject);
|
||||||
|
initResult = result != null && cmsProject.getIdentifier().equals(result.getString("identifier"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Long projectId = insertZoneCmsProjectByDept(deptId);
|
||||||
|
if (projectId != null && projectId > 0) {
|
||||||
|
cmsProject = cmsProjectMapper.selectCmsProjectById(projectId);
|
||||||
|
initResult = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (initResult) {
|
||||||
|
// 批量创建文章对应代码库文件
|
||||||
|
List<CmsDoc> cmsDocAndDirList = cmsDocService.selectCmsDocAndDirListByDept(deptId);
|
||||||
|
if (cmsDocAndDirList == null || cmsDocAndDirList.isEmpty()) {
|
||||||
|
return initResult;
|
||||||
|
}
|
||||||
|
JSONObject docCommitJson = new JSONObject();
|
||||||
|
docCommitJson.put("branch", CmsConstants.BRANCH_MASTER);
|
||||||
|
docCommitJson.put("message", "初始化专区文章对应代码库文件");
|
||||||
|
JSONArray docFiles = new JSONArray();
|
||||||
|
for (CmsDoc cmsDoc : cmsDocAndDirList) {
|
||||||
|
JSONObject docFile = new JSONObject();
|
||||||
|
docFile.put("action_type", "create");
|
||||||
|
docFile.put("content", "");
|
||||||
|
docFile.put("encoding", "text");
|
||||||
|
docFile.put("file_path", cmsDoc.getFilePath());
|
||||||
|
docFiles.add(docFile);
|
||||||
|
}
|
||||||
|
docCommitJson.put("files", docFiles);
|
||||||
|
JSONObject result = gitLinkRequestHelper.doPost(
|
||||||
|
CmsGitLinkRequestUrl.BATCH_COMMIT(cmsProject.getUsername(), cmsProject.getIdentifier())
|
||||||
|
, docCommitJson);
|
||||||
|
if (result == null) {
|
||||||
|
throw new ServiceException("专区对应项目初始化成功,但专区文章在项目中创建失败");
|
||||||
|
}
|
||||||
|
JSONArray resultContents = result.getJSONArray("contents");
|
||||||
|
for (int i = 0; i < resultContents.size(); i++) {
|
||||||
|
JSONObject contentJson = resultContents.getJSONObject(i);
|
||||||
|
cmsDocService.updateCmsDocShaByPathAndDeptId(contentJson.getString("sha"), contentJson.getString("path"), deptId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return initResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private String handleSpecialCharacters(String name) {
|
private String handleSpecialCharacters(String name) {
|
||||||
return StringUtils.replace(name, " ", "-");
|
return StringUtils.replace(name, " ", "-");
|
||||||
|
|
@ -242,6 +315,11 @@ public class CmsProjectServiceImpl implements ICmsProjectService {
|
||||||
return cmsProject;
|
return cmsProject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CmsProject selectCmsProjectByDeptIdAndNoException(Long deptId) {
|
||||||
|
return cmsProjectMapper.selectCmsProjectByDeptId(deptId);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean changeUserRole(Long userId, Long oldDeptId, Long newDeptId, Long oldRoleId, Long newRoleId) {
|
public Boolean changeUserRole(Long userId, Long oldDeptId, Long newDeptId, Long oldRoleId, Long newRoleId) {
|
||||||
SysUser sysUser = FeignUtils.getReturnData(remoteUserService.getSysUserByUserId(userId, SecurityConstants.INNER));
|
SysUser sysUser = FeignUtils.getReturnData(remoteUserService.getSysUserByUserId(userId, SecurityConstants.INNER));
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.microservices.cms.common.service.impl;
|
package com.microservices.cms.service.impl;
|
||||||
|
|
||||||
import com.microservices.cms.common.service.ISysUserService;
|
import com.microservices.cms.common.service.ISysUserService;
|
||||||
import com.microservices.common.core.constant.SecurityConstants;
|
import com.microservices.common.core.constant.SecurityConstants;
|
||||||
|
|
|
||||||
|
|
@ -148,19 +148,19 @@ public class CmsGitLinkRequestUrl extends GitLinkRequestUrl {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GitLinkRequestUrl CREATE_PROTECTED_BRANCHES(String username, String identifier, Map<String,String> params, List<String> pushWhitelistUsernames) throws URISyntaxException {
|
public static GitLinkRequestUrl CREATE_PROTECTED_BRANCHES(String username, String identifier, Map<String, String> params, List<String> pushWhitelistUsernames) throws URISyntaxException {
|
||||||
String path = buildUri(String.format("/api/%s/%s/protected_branches.json", username, identifier), params);
|
String path = buildUri(String.format("/api/%s/%s/protected_branches.json", username, identifier), params);
|
||||||
path = concatenateParametersAfterUrl(path, "push_whitelist_usernames[]", pushWhitelistUsernames);
|
path = concatenateParametersAfterUrl(path, "push_whitelist_usernames[]", pushWhitelistUsernames);
|
||||||
return getGitLinkRequestUrl(path);
|
return getGitLinkRequestUrl(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GitLinkRequestUrl UPDATE_PROTECTED_BRANCHES(String username, String identifier, Map<String,String> params, List<String> pushWhitelistUsernames) throws URISyntaxException {
|
public static GitLinkRequestUrl UPDATE_PROTECTED_BRANCHES(String username, String identifier, Map<String, String> params, List<String> pushWhitelistUsernames) throws URISyntaxException {
|
||||||
String path = buildUri(String.format("/api/%s/%s/protected_branches/master.json", username, identifier), params);
|
String path = buildUri(String.format("/api/%s/%s/protected_branches/master.json", username, identifier), params);
|
||||||
path = concatenateParametersAfterUrl(path, "push_whitelist_usernames[]", pushWhitelistUsernames);
|
path = concatenateParametersAfterUrl(path, "push_whitelist_usernames[]", pushWhitelistUsernames);
|
||||||
return getGitLinkRequestUrl(path);
|
return getGitLinkRequestUrl(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GitLinkRequestUrl DELETE_PROTECTED_BRANCHES(String username, String identifier, Map<String,String> params, List<String> pushWhitelistUsernames) throws URISyntaxException {
|
public static GitLinkRequestUrl DELETE_PROTECTED_BRANCHES(String username, String identifier, Map<String, String> params, List<String> pushWhitelistUsernames) throws URISyntaxException {
|
||||||
String path = buildUri(String.format("/api/%s/%s/protected_branches/master.json", username, identifier), params);
|
String path = buildUri(String.format("/api/%s/%s/protected_branches/master.json", username, identifier), params);
|
||||||
path = concatenateParametersAfterUrl(path, "push_whitelist_usernames[]", pushWhitelistUsernames);
|
path = concatenateParametersAfterUrl(path, "push_whitelist_usernames[]", pushWhitelistUsernames);
|
||||||
return getGitLinkRequestUrl(path);
|
return getGitLinkRequestUrl(path);
|
||||||
|
|
@ -197,4 +197,12 @@ public class CmsGitLinkRequestUrl extends GitLinkRequestUrl {
|
||||||
public static String ZONE_DOC_URL(String gitlinkUrl, String zoneKey, Long docId) {
|
public static String ZONE_DOC_URL(String gitlinkUrl, String zoneKey, Long docId) {
|
||||||
return EscapeUtil.removeExtraSlashOfUrl(String.format("%s/zone/%s/newdetail/%d", gitlinkUrl, zoneKey, docId));
|
return EscapeUtil.removeExtraSlashOfUrl(String.format("%s/zone/%s/newdetail/%d", gitlinkUrl, zoneKey, docId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GitLinkRequestUrl GET_PROJECT_DETAIL(String username, String identifier) {
|
||||||
|
return getAdminGitLinkRequestUrl(String.format("/api/%s/%s/detail.json", username, identifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GitLinkRequestUrl BATCH_COMMIT(String username, String identifier) {
|
||||||
|
return getAdminGitLinkRequestUrl(String.format("/api/v1/%s/%s/contents/batch.json", username, identifier));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.microservices.cms.utils;
|
||||||
|
|
||||||
|
import com.microservices.common.core.exception.ServiceException;
|
||||||
|
import com.microservices.common.core.threadPool.ThreadPoolExecutorWrap;
|
||||||
|
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程池工厂
|
||||||
|
*
|
||||||
|
* @author OTTO
|
||||||
|
*/
|
||||||
|
public class CustomExecutorFactory {
|
||||||
|
/**
|
||||||
|
* 创建线程池
|
||||||
|
* 存在并发处理的情况,设置核心线程为2,设置有界队列长度为100,最大线程数为10
|
||||||
|
* 当超出队列已满且达到最大线程数时抛出异常
|
||||||
|
* Ncpu=CPU数量
|
||||||
|
* Ucpu=目标CPU的使用率,0<=Ucpu<=1
|
||||||
|
* W/C=任务等待时间与任务计算时间的比率
|
||||||
|
* Nthreads =Ncpu*Ucpu*(1+W/C)
|
||||||
|
*/
|
||||||
|
public static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutorWrap(
|
||||||
|
5
|
||||||
|
, 10
|
||||||
|
, 10
|
||||||
|
, TimeUnit.SECONDS
|
||||||
|
, new ArrayBlockingQueue<>(100)
|
||||||
|
, Executors.defaultThreadFactory()
|
||||||
|
, (r, executor) -> {
|
||||||
|
throw new ServiceException("目前处理的人太多了,请稍后再试");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Tomcat
|
# Tomcat
|
||||||
server:
|
server:
|
||||||
port: 9116
|
port: 8080
|
||||||
|
|
||||||
# Spring
|
# Spring
|
||||||
spring:
|
spring:
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,50 @@
|
||||||
from cms_doc cd
|
from cms_doc cd
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
|
<sql id="selectCmsDocAliasSetDefaultHeadImgVo">
|
||||||
|
select cd.id,
|
||||||
|
cd.create_by,
|
||||||
|
cd.create_time,
|
||||||
|
cd.update_by,
|
||||||
|
cd.update_time,
|
||||||
|
cd.name,
|
||||||
|
cd.file_name,
|
||||||
|
cd.file_path,
|
||||||
|
cd.file_sha,
|
||||||
|
cd.file_size,
|
||||||
|
cd.file_url,
|
||||||
|
cd.html_url,
|
||||||
|
cd.visits,
|
||||||
|
cd.sort,
|
||||||
|
cd.publish_time,
|
||||||
|
cd.publish_user,
|
||||||
|
cd.publish_user_image,
|
||||||
|
cd.publish_user_url,
|
||||||
|
cd.publish_user_nickname,
|
||||||
|
cd.summary,
|
||||||
|
-- 处理文章和栏目头图为NULL或空字符串的情况
|
||||||
|
CASE
|
||||||
|
-- 文章头图不为空(非NULL且非空字符串)
|
||||||
|
WHEN cd.head_img IS NOT NULL AND TRIM(cd.head_img) != '' THEN cd.head_img
|
||||||
|
-- 栏目存在且头图不为空
|
||||||
|
WHEN dir.head_img IS NOT NULL AND TRIM(dir.head_img) != '' THEN dir.head_img
|
||||||
|
END AS head_img,
|
||||||
|
cd.dir_name,
|
||||||
|
cd.dept_id,
|
||||||
|
cd.issue_id,
|
||||||
|
cd.is_homepage,
|
||||||
|
cd.editor_type,
|
||||||
|
cd.keywords,
|
||||||
|
cd.is_dir
|
||||||
|
from cms_doc cd
|
||||||
|
left join cms_doc dir on cd.dir_name = dir.name and cd.dept_id = dir.dept_id
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectCmsDocAndDirListByDept" resultMap="CmsDocResult">
|
||||||
|
<include refid="selectCmsDocVo"/>
|
||||||
|
where dept_id=#{deptId}
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="selectCmsDocList" parameterType="com.microservices.cms.doc.domain.CmsDocSearchVo"
|
<select id="selectCmsDocList" parameterType="com.microservices.cms.doc.domain.CmsDocSearchVo"
|
||||||
resultMap="CmsDocResult">
|
resultMap="CmsDocResult">
|
||||||
<include refid="selectCmsDocVo"/>
|
<include refid="selectCmsDocVo"/>
|
||||||
|
|
@ -150,13 +194,13 @@
|
||||||
where file_path = #{filePath} and dept_id = #{deptId} and is_dir = 0
|
where file_path = #{filePath} and dept_id = #{deptId} and is_dir = 0
|
||||||
</select>
|
</select>
|
||||||
<select id="selectHotCmsDocList" parameterType="com.microservices.cms.doc.domain.CmsDoc" resultMap="CmsDocResult">
|
<select id="selectHotCmsDocList" parameterType="com.microservices.cms.doc.domain.CmsDoc" resultMap="CmsDocResult">
|
||||||
<include refid="selectCmsDocVo"/>
|
<include refid="selectCmsDocAliasSetDefaultHeadImgVo"/>
|
||||||
<include refid="selectListWhere"/>
|
<include refid="selectListWhereAlias"/>
|
||||||
ORDER BY
|
ORDER BY
|
||||||
visits DESC,
|
cd.visits DESC,
|
||||||
sort DESC,
|
cd.sort DESC,
|
||||||
update_time DESC,
|
cd.update_time DESC,
|
||||||
create_time DESC
|
cd.create_time DESC
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
<select id="selectCmsDocCount" resultType="java.lang.Integer">
|
<select id="selectCmsDocCount" resultType="java.lang.Integer">
|
||||||
|
|
@ -180,6 +224,23 @@
|
||||||
</where>
|
</where>
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
|
<sql id="selectListWhereAlias">
|
||||||
|
<where>
|
||||||
|
<if test="name != null and name != ''">and cd.name like concat('%', #{name}, '%')</if>
|
||||||
|
<if test="keywords != null and keywords != ''">and cd.keywords like concat('%', #{keywords}, '%')</if>
|
||||||
|
<if test="fileName != null and fileName != ''">and cd.file_name like concat('%', #{fileName}, '%')</if>
|
||||||
|
<if test="filePath != null and filePath != ''">and cd.file_path = #{filePath}</if>
|
||||||
|
<if test="publishTime != null ">and cd.publish_time = #{publishTime}</if>
|
||||||
|
<if test="isDir != null ">and cd.is_dir = #{isDir}</if>
|
||||||
|
<if test="dirName != null ">and cd.dir_name = #{dirName}</if>
|
||||||
|
<if test="deptId != null ">and cd.dept_id = #{deptId}</if>
|
||||||
|
<if test="isHomepage != null ">and cd.is_homepage = #{isHomepage}</if>
|
||||||
|
<if test="auditStatus != null and auditStatus != '-1' ">and cd.audit_status = #{auditStatus}</if>
|
||||||
|
<if test="auditStatus == null ">and cd.audit_status = '1'</if>
|
||||||
|
<if test="createBy != null and createBy != '' ">and cd.create_by = #{createBy}</if>
|
||||||
|
</where>
|
||||||
|
</sql>
|
||||||
|
|
||||||
<select id="selectCmsDocDirByDeptIdAndInName" resultMap="CmsDocResult">
|
<select id="selectCmsDocDirByDeptIdAndInName" resultMap="CmsDocResult">
|
||||||
<include refid="selectCmsDocVo"/>
|
<include refid="selectCmsDocVo"/>
|
||||||
where dept_id = #{deptId} and is_dir = 1
|
where dept_id = #{deptId} and is_dir = 1
|
||||||
|
|
@ -283,6 +344,15 @@
|
||||||
from cms_doc
|
from cms_doc
|
||||||
where dept_id = #{deptId};
|
where dept_id = #{deptId};
|
||||||
</select>
|
</select>
|
||||||
|
<select id="selectCmsDocListSetDefaultHeadImg" parameterType="com.microservices.cms.doc.domain.CmsDocSearchVo"
|
||||||
|
resultMap="CmsDocResult">
|
||||||
|
<include refid="selectCmsDocAliasSetDefaultHeadImgVo"/>
|
||||||
|
<include refid="selectListWhereAlias"/>
|
||||||
|
ORDER BY
|
||||||
|
cd.sort DESC,
|
||||||
|
cd.update_time DESC,
|
||||||
|
cd.create_time DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
<insert id="insertCmsDoc" parameterType="com.microservices.cms.doc.domain.CmsDoc" useGeneratedKeys="true"
|
<insert id="insertCmsDoc" parameterType="com.microservices.cms.doc.domain.CmsDoc" useGeneratedKeys="true"
|
||||||
keyProperty="id">
|
keyProperty="id">
|
||||||
|
|
@ -405,6 +475,12 @@
|
||||||
and dept_id = #{deptId}
|
and dept_id = #{deptId}
|
||||||
and is_dir = #{isDir};
|
and is_dir = #{isDir};
|
||||||
</update>
|
</update>
|
||||||
|
<update id="updateCmsDocShaByPathAndDeptId">
|
||||||
|
update cms_doc
|
||||||
|
set file_sha=#{sha}
|
||||||
|
where file_path=#{filePath}
|
||||||
|
and dept_id=#{deptId}
|
||||||
|
</update>
|
||||||
|
|
||||||
<delete id="deleteCmsDocById" parameterType="Long">
|
<delete id="deleteCmsDocById" parameterType="Long">
|
||||||
delete
|
delete
|
||||||
|
|
|
||||||
|
|
@ -87,10 +87,18 @@
|
||||||
<groupId>com.microservices</groupId>
|
<groupId>com.microservices</groupId>
|
||||||
<artifactId>microservices-common-security</artifactId>
|
<artifactId>microservices-common-security</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-swagger</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-core</artifactId>
|
<artifactId>spring-security-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-log</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.microservices</groupId>
|
<groupId>com.microservices</groupId>
|
||||||
<artifactId>microservices-common-core</artifactId>
|
<artifactId>microservices-common-core</artifactId>
|
||||||
|
|
@ -125,7 +133,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.hankcs</groupId>
|
<groupId>com.hankcs</groupId>
|
||||||
<artifactId>hanlp</artifactId>
|
<artifactId>hanlp</artifactId>
|
||||||
<version>portable-1.8.4</version>
|
<version>portable-1.3.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,17 @@ import com.microservices.common.log.enums.BusinessType;
|
||||||
import com.microservices.dms.achievementLibrary.domain.AchQueryVo;
|
import com.microservices.dms.achievementLibrary.domain.AchQueryVo;
|
||||||
import com.microservices.dms.achievementLibrary.domain.Achievements;
|
import com.microservices.dms.achievementLibrary.domain.Achievements;
|
||||||
import com.microservices.dms.achievementLibrary.service.IAchievementsService;
|
import com.microservices.dms.achievementLibrary.service.IAchievementsService;
|
||||||
|
import com.microservices.system.api.RemoteFileService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 成果Controller
|
* 成果Controller
|
||||||
*
|
*
|
||||||
|
|
@ -30,6 +33,9 @@ public class AchievementsController extends BaseController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private IAchievementsService achievementsService;
|
private IAchievementsService achievementsService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RemoteFileService remoteFileService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询成果列表
|
* 查询成果列表
|
||||||
*/
|
*/
|
||||||
|
|
@ -215,19 +221,20 @@ public class AchievementsController extends BaseController {
|
||||||
public AjaxResult getWatchFavoriteStatusById(Long id, Long userId) {
|
public AjaxResult getWatchFavoriteStatusById(Long id, Long userId) {
|
||||||
return success(achievementsService.getWatchFavoriteStatusById(id, userId));
|
return success(achievementsService.getWatchFavoriteStatusById(id, userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("根据成果ID,获取近7日成果点击数量(折线图)")
|
@ApiOperation("根据成果ID,获取近7日成果点击数量(折线图)")
|
||||||
@GetMapping("/get7AddClickById")
|
@GetMapping("/get7AddClickById")
|
||||||
public AjaxResult get7AddClickById(String id,@RequestParam(value = "clickType",required = false, defaultValue = "Achievements")
|
public AjaxResult get7AddClickById(String id, @RequestParam(value = "clickType", required = false, defaultValue = "Achievements")
|
||||||
String clickType) {
|
String clickType) {
|
||||||
return success(achievementsService.get7AddClickById(id,clickType));
|
return success(achievementsService.get7AddClickById(id, clickType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ApiOperation("根据专家id,获取近7日成果点击数量(折线图)")
|
@ApiOperation("根据专家id,获取近7日成果点击数量(折线图)")
|
||||||
@GetMapping("/getExpert7AddClickById")
|
@GetMapping("/getExpert7AddClickById")
|
||||||
public AjaxResult getExpert7AddClickById(String id,@RequestParam(value = "clickType",required = false, defaultValue = "Experts")
|
public AjaxResult getExpert7AddClickById(String id, @RequestParam(value = "clickType", required = false, defaultValue = "Experts")
|
||||||
String clickType) {
|
String clickType) {
|
||||||
return success(achievementsService.get7AddClickById(id,clickType));
|
return success(achievementsService.get7AddClickById(id, clickType));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation("根据成果ID,获取成果的相关行为数据统计(点击量、搜索量、附件下载量、收藏、关注)")
|
@ApiOperation("根据成果ID,获取成果的相关行为数据统计(点击量、搜索量、附件下载量、收藏、关注)")
|
||||||
|
|
@ -243,21 +250,24 @@ public class AchievementsController extends BaseController {
|
||||||
return success(achievementsService.getAllAreas(areaName));
|
return success(achievementsService.getAllAreas(areaName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiOperation("根据已有数据,获取融办名称数据")
|
||||||
|
@GetMapping("/getAllField2")
|
||||||
|
public AjaxResult getAllField2() {
|
||||||
|
return success(achievementsService.getAllField2());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ApiOperation("根据领域,将成果数据进行分类")
|
@ApiOperation("根据领域,将成果数据进行分类")
|
||||||
@GetMapping("/getAreaStatistic")
|
@GetMapping("/getAreaStatistic")
|
||||||
public AjaxResult getAreaStatistic(String areaKey)
|
public AjaxResult getAreaStatistic(String areaKey) {
|
||||||
{
|
|
||||||
return success(achievementsService.getAreaStatistic(areaKey));
|
return success(achievementsService.getAreaStatistic(areaKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ApiOperation("根据领域获取领域详情")
|
@ApiOperation("根据领域获取领域详情")
|
||||||
@GetMapping("/getAreaDetail")
|
@GetMapping("/getAreaDetail")
|
||||||
public AjaxResult getAreaDetail(String areaKey,String kyxmSum,String source)
|
public AjaxResult getAreaDetail(String areaKey, String kyxmSum, String source) {
|
||||||
{
|
return success(achievementsService.getAreaDetail(areaKey, kyxmSum, source));
|
||||||
return success(achievementsService.getAreaDetail(areaKey,kyxmSum,source));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -265,46 +275,59 @@ public class AchievementsController extends BaseController {
|
||||||
*/
|
*/
|
||||||
@ApiOperation(value = "获取开源项目的相关成果")
|
@ApiOperation(value = "获取开源项目的相关成果")
|
||||||
@GetMapping("/getRelatedAch")
|
@GetMapping("/getRelatedAch")
|
||||||
public AjaxResult getRelatedAch(Long id,Long sourceId)
|
public AjaxResult getRelatedAch(Long id, Long sourceId) {
|
||||||
{
|
return success(achievementsService.getRelatedAch(id, sourceId));
|
||||||
return success(achievementsService.getRelatedAch(id,sourceId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ApiOperation(value = "获取开源竞赛的相关成果")
|
@ApiOperation(value = "获取开源竞赛的相关成果")
|
||||||
@GetMapping("/getRelatedAchCompetition")
|
@GetMapping("/getRelatedAchCompetition")
|
||||||
public AjaxResult getRelatedAchCompetition(Long id,Long sourceId)
|
public AjaxResult getRelatedAchCompetition(Long id, Long sourceId) {
|
||||||
{
|
return success(achievementsService.getRelatedAchCompetition(id, sourceId));
|
||||||
return success(achievementsService.getRelatedAchCompetition(id,sourceId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ApiOperation(value = "获取创客任务的相关成果")
|
@ApiOperation(value = "获取创客任务的相关成果")
|
||||||
@GetMapping("/getRelatedAchTask")
|
@GetMapping("/getRelatedAchTask")
|
||||||
public AjaxResult getRelatedAchTask(Long id,Long sourceId)
|
public AjaxResult getRelatedAchTask(Long id, Long sourceId) {
|
||||||
{
|
return success(achievementsService.getRelatedAchTask(id, sourceId));
|
||||||
return success(achievementsService.getRelatedAchTask(id,sourceId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "获取专家-创客任务的相关成果")
|
@ApiOperation(value = "获取专家-创客任务的相关成果")
|
||||||
@GetMapping("/getRelatedAchTaskOfExpert")
|
@GetMapping("/getRelatedAchTaskOfExpert")
|
||||||
public AjaxResult getRelatedAchTaskOfExpert(Long expertId)
|
public AjaxResult getRelatedAchTaskOfExpert(Long expertId) {
|
||||||
{
|
|
||||||
return success(achievementsService.getRelatedAchTaskOfExpert(expertId));
|
return success(achievementsService.getRelatedAchTaskOfExpert(expertId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "获取专家-开源竞赛的相关成果")
|
@ApiOperation(value = "获取专家-开源竞赛的相关成果")
|
||||||
@GetMapping("/getRelatedAchCompetitionOfExpert")
|
@GetMapping("/getRelatedAchCompetitionOfExpert")
|
||||||
public AjaxResult getRelatedAchCompetitionOfExpert(Long expertId)
|
public AjaxResult getRelatedAchCompetitionOfExpert(Long expertId) {
|
||||||
{
|
|
||||||
return success(achievementsService.getRelatedAchCompetitionOfExpert(expertId));
|
return success(achievementsService.getRelatedAchCompetitionOfExpert(expertId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "搜索行为数据记录")
|
@ApiOperation(value = "搜索行为数据记录")
|
||||||
@GetMapping("/getSearchResult")
|
@GetMapping("/getSearchResult")
|
||||||
public AjaxResult getSearchResult(String achName,Long userId)
|
public AjaxResult getSearchResult(String achName, Long userId) {
|
||||||
{
|
return success(achievementsService.getSearchResult(achName, userId));
|
||||||
return success(achievementsService.getSearchResult(achName,userId));
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "融办名称分类数据统计")
|
||||||
|
@GetMapping("/getSource5Statistic")
|
||||||
|
public AjaxResult getSource5Statistic(String name) {
|
||||||
|
return success(achievementsService.getSource5Statistic(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入项目资源库数据
|
||||||
|
*/
|
||||||
|
@PostMapping("/importData")
|
||||||
|
@Log(title = "项目资源库", businessType = BusinessType.INSERT)
|
||||||
|
public AjaxResult importData(@RequestPart("file") MultipartFile file,
|
||||||
|
@RequestParam(value = "updateSupport", defaultValue = "false") boolean updateSupport) throws Exception {
|
||||||
|
if (file == null || file.isEmpty()) {
|
||||||
|
return AjaxResult.error("上传文件不能为空");
|
||||||
|
}
|
||||||
|
return AjaxResult.success(achievementsService.batchImportAchievementsZip(file, updateSupport));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import com.microservices.common.core.web.domain.AjaxResult;
|
||||||
import com.microservices.common.core.web.page.TableDataInfo;
|
import com.microservices.common.core.web.page.TableDataInfo;
|
||||||
import com.microservices.common.log.annotation.Log;
|
import com.microservices.common.log.annotation.Log;
|
||||||
import com.microservices.common.log.enums.BusinessType;
|
import com.microservices.common.log.enums.BusinessType;
|
||||||
|
import com.microservices.common.security.utils.SecurityUtils;
|
||||||
import com.microservices.dms.achievementLibrary.domain.SchoolEnterpriseAchievements;
|
import com.microservices.dms.achievementLibrary.domain.SchoolEnterpriseAchievements;
|
||||||
import com.microservices.dms.achievementLibrary.service.ISchoolEnterpriseAchievementsService;
|
import com.microservices.dms.achievementLibrary.service.ISchoolEnterpriseAchievementsService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
|
|
@ -15,9 +16,11 @@ import io.swagger.annotations.ApiImplicitParams;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校企成果Controller
|
* 校企成果Controller
|
||||||
|
|
@ -90,6 +93,21 @@ public class SchoolEnterpriseAchievementsController extends BaseController
|
||||||
return AjaxResult.success(schoolEnterpriseAchievementsService.insertSchoolEnterpriseAchievements(schoolEnterpriseAchievements));
|
return AjaxResult.success(schoolEnterpriseAchievementsService.insertSchoolEnterpriseAchievements(schoolEnterpriseAchievements));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/importData")
|
||||||
|
@Log(title = "校企成果", businessType = BusinessType.INSERT)
|
||||||
|
public AjaxResult importData(@RequestPart("file") MultipartFile file,
|
||||||
|
@RequestParam(value = "updateSupport", defaultValue = "false") boolean updateSupport) throws Exception {
|
||||||
|
ExcelUtil<SchoolEnterpriseAchievements> util = new ExcelUtil<>(SchoolEnterpriseAchievements.class);
|
||||||
|
// 1. 解析Excel,获取实体列表和图片Map
|
||||||
|
List<SchoolEnterpriseAchievements> list = util.importExcelWithImages(StringUtils.EMPTY, file.getInputStream(), 0);
|
||||||
|
Map<String, MultipartFile> imageMap = util.getExcelImageMap();
|
||||||
|
// 2. 调用业务层处理(传入实体列表和图片Map)
|
||||||
|
String operName = SecurityUtils.getUsername();
|
||||||
|
String message = schoolEnterpriseAchievementsService.batchInsertSchoolEnterpriseAchievements(list, imageMap, updateSupport, operName);
|
||||||
|
|
||||||
|
return AjaxResult.success(message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改校企成果
|
* 修改校企成果
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ public class AchQueryVo {
|
||||||
private String achievementName;//名称
|
private String achievementName;//名称
|
||||||
private Long userId;
|
private Long userId;
|
||||||
private String showAchievementName;
|
private String showAchievementName;
|
||||||
|
private String rongbanName;
|
||||||
public String getAreaQuery() {
|
public String getAreaQuery() {
|
||||||
return areaQuery;
|
return areaQuery;
|
||||||
}
|
}
|
||||||
|
|
@ -46,4 +47,12 @@ public class AchQueryVo {
|
||||||
public void setShowAchievementName(String showAchievementName) {
|
public void setShowAchievementName(String showAchievementName) {
|
||||||
this.showAchievementName = showAchievementName;
|
this.showAchievementName = showAchievementName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRongbanName() {
|
||||||
|
return rongbanName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRongbanName(String rongbanName) {
|
||||||
|
this.rongbanName = rongbanName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.microservices.dms.achievementLibrary.domain;
|
||||||
|
|
||||||
|
public class AchievementSourceStatisticVo {
|
||||||
|
private String rongbanName;
|
||||||
|
|
||||||
|
private String rongbanDesc;
|
||||||
|
//成果数
|
||||||
|
private Long achievementSum;
|
||||||
|
//点击量(浏览量)
|
||||||
|
private Long clickSum;
|
||||||
|
|
||||||
|
public String getRongbanName() {
|
||||||
|
return rongbanName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRongbanName(String rongbanName) {
|
||||||
|
this.rongbanName = rongbanName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRongbanDesc() {
|
||||||
|
return rongbanDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRongbanDesc(String rongbanDesc) {
|
||||||
|
this.rongbanDesc = rongbanDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getAchievementSum() {
|
||||||
|
return achievementSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAchievementSum(Long achievementSum) {
|
||||||
|
this.achievementSum = achievementSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getClickSum() {
|
||||||
|
return clickSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClickSum(Long clickSum) {
|
||||||
|
this.clickSum = clickSum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -38,21 +38,24 @@ public class Achievements extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
* 成果领域1
|
* 成果领域1
|
||||||
*/
|
*/
|
||||||
@Excel(name = "成果领域1")
|
@Excel(
|
||||||
|
name = "成果领域",
|
||||||
|
readConverterExp = "1=理论研究,2=政策法规,3=医学,4=电子信息,5=通信工程,6=计算机科学,7=软件工程,9=人工智能,10=知识图谱,12=大数据,23=机器人,24=无人系统,25=创意征集,26=文献翻译,27=成果转化,28=科技协同,29=科研组织模式,30=新兴领域,31=其他,32=电子元器件,33=测试仪器,34=军事历史,35=计算机网络"
|
||||||
|
)
|
||||||
private String field1;
|
private String field1;
|
||||||
//成果领域名称
|
//成果领域名称
|
||||||
private String field1Name;
|
private String field1Name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 成果领域2
|
* 融办名称
|
||||||
*/
|
*/
|
||||||
@Excel(name = "成果领域2")
|
@Excel(name = "融办名称")
|
||||||
private String field2;
|
private String field2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 成果领域3
|
* 融办描述
|
||||||
*/
|
*/
|
||||||
@Excel(name = "成果领域3")
|
@Excel(name = "融办描述")
|
||||||
private String field3;
|
private String field3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -64,7 +67,7 @@ public class Achievements extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
* 成果来源
|
* 成果来源
|
||||||
*/
|
*/
|
||||||
@Excel(name = "成果来源")
|
@Excel(name = "成果来源", readConverterExp = "1=开源项目,2=创客任务,3=开放竞赛,4=校企成果,5=省市融办")
|
||||||
private String source;
|
private String source;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -74,15 +77,15 @@ public class Achievements extends BaseEntity {
|
||||||
private Long sourceId;
|
private Long sourceId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 成果来源跳转链接
|
* 成果来源渠道
|
||||||
*/
|
*/
|
||||||
@Excel(name = "成果来源跳转链接")
|
@Excel(name = "成果来源渠道")
|
||||||
private String sourceLink;
|
private String sourceLink;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 成果标签
|
* 成果标签
|
||||||
*/
|
*/
|
||||||
@Excel(name = "成果标签")
|
@Excel(name = "成果标签", readConverterExp = "1=高校,2=企业,3=其他")
|
||||||
private String tags;
|
private String tags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -94,13 +97,13 @@ public class Achievements extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
* 发布单位
|
* 发布单位
|
||||||
*/
|
*/
|
||||||
@Excel(name = "发布单位")
|
@Excel(name = "单位名称")
|
||||||
private String publishingUnit;
|
private String publishingUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 成果地址
|
* 单位概况
|
||||||
*/
|
*/
|
||||||
@Excel(name = "成果地址")
|
@Excel(name = "单位概况")
|
||||||
private String address;
|
private String address;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -116,9 +119,9 @@ public class Achievements extends BaseEntity {
|
||||||
private String contactPerson;
|
private String contactPerson;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 联系电话
|
* 联系方式
|
||||||
*/
|
*/
|
||||||
@Excel(name = "联系电话")
|
@Excel(name = "联系方式")
|
||||||
private String contactNumber;
|
private String contactNumber;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -140,9 +143,9 @@ public class Achievements extends BaseEntity {
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 成果详情
|
* 成果简介
|
||||||
*/
|
*/
|
||||||
@Excel(name = "成果详情")
|
@Excel(name = "成果简介")
|
||||||
private String details;
|
private String details;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -167,7 +170,7 @@ public class Achievements extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
* 成果图片
|
* 成果图片
|
||||||
*/
|
*/
|
||||||
@Excel(name = "成果图片")
|
@Excel(name = "图片")
|
||||||
private String images;
|
private String images;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -177,10 +180,14 @@ public class Achievements extends BaseEntity {
|
||||||
private String attachments;
|
private String attachments;
|
||||||
|
|
||||||
//成果小类
|
//成果小类
|
||||||
|
@Excel(name = "成果图片视频")
|
||||||
private String ext1;
|
private String ext1;
|
||||||
//成果状态
|
//成果状态
|
||||||
|
|
||||||
|
@Excel(name = "应用图片视频")
|
||||||
private String ext2;
|
private String ext2;
|
||||||
//成果团队名称
|
//成果团队名称
|
||||||
|
@Excel(name = "应用情况")
|
||||||
private String ext3;
|
private String ext3;
|
||||||
|
|
||||||
private Long clickSum;
|
private Long clickSum;
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,10 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
* 成果领域1
|
* 成果领域1
|
||||||
*/
|
*/
|
||||||
@Excel(name = "成果领域1")
|
@Excel(
|
||||||
|
name = "成果领域",
|
||||||
|
readConverterExp = "1=理论研究,2=政策法规,3=医学,4=电子信息,5=通信工程,6=计算机科学,7=软件工程,9=人工智能,10=知识图谱,12=大数据,23=机器人,24=无人系统,25=创意征集,26=文献翻译,27=成果转化,28=科技协同,29=科研组织模式,30=新兴领域,31=其他,32=电子元器件,33=测试仪器,34=军事历史,35=计算机网络"
|
||||||
|
)
|
||||||
private String field1;
|
private String field1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -50,7 +53,7 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
* 成果类型
|
* 成果类型
|
||||||
*/
|
*/
|
||||||
@Excel(name = "成果类型")
|
@Excel(name = "成果类型", readConverterExp = "1=理论成果,2=技术成果,3=应用成果,4=软科学成果,5=文化艺术成果,6=社会服务成果,7=交叉领域成果")
|
||||||
private String achievementType;
|
private String achievementType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -74,7 +77,10 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
* 成果标签
|
* 成果标签
|
||||||
*/
|
*/
|
||||||
@Excel(name = "成果标签")
|
@Excel(
|
||||||
|
name = "成果标签",
|
||||||
|
readConverterExp = "1=高校,2=企业,3=其他"
|
||||||
|
)
|
||||||
private String tags;
|
private String tags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -159,7 +165,7 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
* 成果图片
|
* 成果图片
|
||||||
*/
|
*/
|
||||||
@Excel(name = "成果图片")
|
@Excel(name = "图片")
|
||||||
private String images;
|
private String images;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -169,10 +175,18 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
||||||
private String attachments;
|
private String attachments;
|
||||||
private Integer achievementStatus;
|
private Integer achievementStatus;
|
||||||
//成果小类型
|
//成果小类型
|
||||||
|
@Excel(
|
||||||
|
name = "成果小类型",
|
||||||
|
readConverterExp = "7=学术论文,8=学术专著,9=理论模型,10=发明专利,11=技术标准,12=软件系统,13=技术原型,14=产品设备,15=解决方案,16=示范工程,17=政策建议,18=咨询报告,19=行业标准,20=管理办法,21=文学作品,22=艺术作品,23=公益项目,24=社会调查报告,25=教育培训成果,26=理论模型+产品设备,27=学术论文+技术原型"
|
||||||
|
)
|
||||||
private String achievementLittleType;
|
private String achievementLittleType;
|
||||||
//成果状态
|
@Excel(
|
||||||
|
name = "成果状态",
|
||||||
|
readConverterExp = "1=已有阶段性成果,2=已有成熟成果,3=已公开发表,4=已对外发布,5=已开展应用,6=已形成商业化产品"
|
||||||
|
)
|
||||||
private String achievementCurStatus;
|
private String achievementCurStatus;
|
||||||
//团队名称
|
//团队名称
|
||||||
|
@Excel(name = "成果团队名称")
|
||||||
private String teamName;
|
private String teamName;
|
||||||
|
|
||||||
private List<AchievementTeam> teamList;
|
private List<AchievementTeam> teamList;
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,13 @@ import com.microservices.common.datasource.annotation.Master;
|
||||||
import com.microservices.common.datasource.annotation.Slave;
|
import com.microservices.common.datasource.annotation.Slave;
|
||||||
import com.microservices.dms.achievementLibrary.domain.*;
|
import com.microservices.dms.achievementLibrary.domain.*;
|
||||||
import com.microservices.dms.behaviorImage.domain.AchievementBehaviorSumVo;
|
import com.microservices.dms.behaviorImage.domain.AchievementBehaviorSumVo;
|
||||||
|
import com.microservices.dms.achievementLibrary.domain.AchievementSourceStatisticVo;
|
||||||
import com.microservices.dms.resourceLibrary.domain.CompetitionResourceLibrary;
|
import com.microservices.dms.resourceLibrary.domain.CompetitionResourceLibrary;
|
||||||
import com.microservices.dms.resourceLibrary.domain.TaskResourceLibrary;
|
import com.microservices.dms.resourceLibrary.domain.TaskResourceLibrary;
|
||||||
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
||||||
import org.apache.ibatis.annotations.MapKey;
|
import org.apache.ibatis.annotations.MapKey;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.springframework.beans.PropertyValues;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 成果Mapper接口
|
* 成果Mapper接口
|
||||||
|
|
@ -30,6 +30,7 @@ public interface AchievementsMapper {
|
||||||
* @return 成果
|
* @return 成果
|
||||||
*/
|
*/
|
||||||
public Achievements selectAchievementsById(Long id);
|
public Achievements selectAchievementsById(Long id);
|
||||||
|
public Achievements selectAchievementsByAchievementName(String achievementName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询成果列表
|
* 查询成果列表
|
||||||
|
|
@ -165,10 +166,14 @@ public interface AchievementsMapper {
|
||||||
List<KeyValVo<String, Long>> getExperts(@Param("s") Date s, @Param("e") Date e);
|
List<KeyValVo<String, Long>> getExperts(@Param("s") Date s, @Param("e") Date e);
|
||||||
|
|
||||||
List<KeyValueVo> getAllAreas(@Param("areaName") String areaName);
|
List<KeyValueVo> getAllAreas(@Param("areaName") String areaName);
|
||||||
|
List<KeyValueVo> getAllField2();
|
||||||
|
|
||||||
void updateRelationAchievements(@Param("source") String source,@Param("sourceId") Long sourceId);
|
void updateRelationAchievements(@Param("source") String source,@Param("sourceId") Long sourceId);
|
||||||
|
|
||||||
List<Map<String, Object>> getDockingUserInfoList(@Param("id") Long id);
|
List<Map<String, Object>> getDockingUserInfoList(@Param("id") Long id);
|
||||||
|
|
||||||
String getField1RemarkByParam(@Param("source")String source,@Param("areaKey") String areaKey);
|
String getField1RemarkByParam(@Param("source")String source,@Param("areaKey") String areaKey);
|
||||||
|
|
||||||
|
AchievementSourceStatisticVo getSource5Statistic(@Param("name") String name);
|
||||||
|
AchievementSourceStatisticVo getSource5Field2(@Param("name") String name);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,11 @@ import java.util.Map;
|
||||||
|
|
||||||
import com.microservices.dms.achievementLibrary.domain.*;
|
import com.microservices.dms.achievementLibrary.domain.*;
|
||||||
import com.microservices.dms.behaviorImage.domain.AchievementBehaviorSumVo;
|
import com.microservices.dms.behaviorImage.domain.AchievementBehaviorSumVo;
|
||||||
|
import com.microservices.dms.achievementLibrary.domain.AchievementSourceStatisticVo;
|
||||||
import com.microservices.dms.resourceLibrary.domain.CompetitionResourceLibrary;
|
import com.microservices.dms.resourceLibrary.domain.CompetitionResourceLibrary;
|
||||||
import com.microservices.dms.resourceLibrary.domain.TaskResourceLibrary;
|
import com.microservices.dms.resourceLibrary.domain.TaskResourceLibrary;
|
||||||
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 成果Service接口
|
* 成果Service接口
|
||||||
|
|
@ -106,6 +108,8 @@ public interface IAchievementsService {
|
||||||
|
|
||||||
int getSearchResult(String achName, Long userId);
|
int getSearchResult(String achName, Long userId);
|
||||||
|
|
||||||
|
AchievementSourceStatisticVo getSource5Statistic(String name);
|
||||||
|
|
||||||
List<KeyValueVo> getProjectAreasByName(String areaName);
|
List<KeyValueVo> getProjectAreasByName(String areaName);
|
||||||
|
|
||||||
List<String> getExpertAreasByName(String areaName);
|
List<String> getExpertAreasByName(String areaName);
|
||||||
|
|
@ -123,5 +127,9 @@ public interface IAchievementsService {
|
||||||
List<KeyValVo<String, Long>> get7DayAddExport(AchQueryVo achQueryVo);
|
List<KeyValVo<String, Long>> get7DayAddExport(AchQueryVo achQueryVo);
|
||||||
|
|
||||||
List<KeyValueVo> getAllAreas(String areaName);
|
List<KeyValueVo> getAllAreas(String areaName);
|
||||||
|
List<KeyValueVo> getAllField2();
|
||||||
|
|
||||||
|
String batchInsertAchievements(List<Achievements> list, boolean updateSupport, String operName);
|
||||||
|
|
||||||
|
String batchImportAchievementsZip(MultipartFile file, boolean updateSupport);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
package com.microservices.dms.achievementLibrary.service;
|
package com.microservices.dms.achievementLibrary.service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.microservices.dms.achievementLibrary.domain.SchoolEnterpriseAchievements;
|
import com.microservices.dms.achievementLibrary.domain.SchoolEnterpriseAchievements;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校企成果Service接口
|
* 校企成果Service接口
|
||||||
|
|
@ -64,4 +67,6 @@ public interface ISchoolEnterpriseAchievementsService
|
||||||
List<SchoolEnterpriseAchievements> listFront(SchoolEnterpriseAchievements schoolEnterpriseAchievements);
|
List<SchoolEnterpriseAchievements> listFront(SchoolEnterpriseAchievements schoolEnterpriseAchievements);
|
||||||
|
|
||||||
boolean getCheckSchoolAchName(SchoolEnterpriseAchievements schoolEnterpriseAchievements);
|
boolean getCheckSchoolAchName(SchoolEnterpriseAchievements schoolEnterpriseAchievements);
|
||||||
|
|
||||||
|
String batchInsertSchoolEnterpriseAchievements(List<SchoolEnterpriseAchievements> list, Map<String, MultipartFile> imageMap, boolean updateSupport, String operName);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,54 @@
|
||||||
package com.microservices.dms.achievementLibrary.service.impl;
|
package com.microservices.dms.achievementLibrary.service.impl;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.TypeReference;
|
import com.alibaba.fastjson.TypeReference;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.constant.SecurityConstants;
|
||||||
|
import com.microservices.common.core.domain.R;
|
||||||
import com.microservices.common.core.utils.DateUtils;
|
import com.microservices.common.core.utils.DateUtils;
|
||||||
import com.microservices.common.core.utils.StringUtils;
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
import com.microservices.common.httpClient.service.HttpAPIService;
|
import com.microservices.common.core.utils.poi.ExcelUtil;
|
||||||
import com.microservices.common.security.utils.SecurityUtils;
|
import com.microservices.common.security.utils.SecurityUtils;
|
||||||
import com.microservices.dms.achievementLibrary.domain.*;
|
import com.microservices.dms.achievementLibrary.domain.*;
|
||||||
import com.microservices.dms.achievementLibrary.mapper.SchoolEnterpriseAchievementsMapper;
|
|
||||||
import com.microservices.dms.behaviorImage.domain.AchievementBehaviorSumVo;
|
import com.microservices.dms.behaviorImage.domain.AchievementBehaviorSumVo;
|
||||||
import com.microservices.dms.behaviorImage.domain.AchievementImageVo;
|
import com.microservices.dms.behaviorImage.domain.AchievementImageVo;
|
||||||
|
import com.microservices.dms.achievementLibrary.domain.AchievementSourceStatisticVo;
|
||||||
import com.microservices.dms.behaviorImage.service.IBehaviorImageService;
|
import com.microservices.dms.behaviorImage.service.IBehaviorImageService;
|
||||||
import com.microservices.dms.resourceLibrary.domain.Clicker;
|
import com.microservices.dms.common.vo.AchievementSysFileVo;
|
||||||
import com.microservices.dms.resourceLibrary.domain.CompetitionResourceLibrary;
|
import com.microservices.dms.resourceLibrary.domain.*;
|
||||||
import com.microservices.dms.resourceLibrary.domain.Searcher;
|
|
||||||
import com.microservices.dms.resourceLibrary.domain.TaskResourceLibrary;
|
|
||||||
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
||||||
import com.microservices.dms.resourceLibrary.mapper.CompetitionResourceLibraryMapper;
|
|
||||||
import com.microservices.dms.resourceLibrary.mapper.ExpertResourceLibraryMapper;
|
import com.microservices.dms.resourceLibrary.mapper.ExpertResourceLibraryMapper;
|
||||||
import com.microservices.dms.resourceLibrary.mapper.ProjectResourceLibraryMapper;
|
|
||||||
import com.microservices.dms.resourceLibrary.mapper.TaskResourceLibraryMapper;
|
import com.microservices.dms.resourceLibrary.mapper.TaskResourceLibraryMapper;
|
||||||
|
import com.microservices.dms.utils.CustomMultipartFile;
|
||||||
import com.microservices.dms.utils.DateUtil;
|
import com.microservices.dms.utils.DateUtil;
|
||||||
|
import com.microservices.dms.utils.FileMultipartFile;
|
||||||
|
import com.microservices.system.api.RemoteFileService;
|
||||||
|
import com.microservices.system.api.domain.SysFile;
|
||||||
|
import com.microservices.system.api.domain.SysFileInfo;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.checkerframework.checker.units.qual.K;
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import com.microservices.dms.achievementLibrary.mapper.AchievementsMapper;
|
import com.microservices.dms.achievementLibrary.mapper.AchievementsMapper;
|
||||||
import com.microservices.dms.achievementLibrary.service.IAchievementsService;
|
import com.microservices.dms.achievementLibrary.service.IAchievementsService;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.activation.FileTypeMap;
|
||||||
|
|
||||||
import static com.microservices.dms.constant.BlockChainFunConstants.QUERY_REPO;
|
|
||||||
import static com.microservices.dms.utils.UrlUtil.getUrlPath;
|
import static com.microservices.dms.utils.UrlUtil.getUrlPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -46,6 +60,9 @@ import static com.microservices.dms.utils.UrlUtil.getUrlPath;
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AchievementsServiceImpl implements IAchievementsService {
|
public class AchievementsServiceImpl implements IAchievementsService {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(AchievementsServiceImpl.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AchievementsMapper achievementsMapper;
|
private AchievementsMapper achievementsMapper;
|
||||||
|
|
||||||
|
|
@ -59,6 +76,9 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private IBehaviorImageService behaviorImageService;
|
private IBehaviorImageService behaviorImageService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RemoteFileService remoteFileService;
|
||||||
|
|
||||||
@Value("${makerSpaceUrl}")
|
@Value("${makerSpaceUrl}")
|
||||||
public String makerSpaceUrl;
|
public String makerSpaceUrl;
|
||||||
|
|
||||||
|
|
@ -86,7 +106,7 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
||||||
img = "images/avatars/User/boy.jpg";
|
img = "images/avatars/User/boy.jpg";
|
||||||
}
|
}
|
||||||
a.setUserImg(img);
|
a.setUserImg(img);
|
||||||
if (StringUtils.isNotEmpty(a.getField1())) {
|
if (StringUtils.isNotEmpty(a.getField1()) && !a.getSource().equals("5")) {
|
||||||
String field1Name = achievementsMapper.getField1NameByParam(a.getSource(), a.getId());
|
String field1Name = achievementsMapper.getField1NameByParam(a.getSource(), a.getId());
|
||||||
if (StringUtils.isNotNull(field1Name)) {
|
if (StringUtils.isNotNull(field1Name)) {
|
||||||
a.setField1Name(field1Name);
|
a.setField1Name(field1Name);
|
||||||
|
|
@ -96,6 +116,8 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
||||||
|
|
||||||
a.setImages(buildFileInfoByIdents(a.getImages(), a.getSource()));
|
a.setImages(buildFileInfoByIdents(a.getImages(), a.getSource()));
|
||||||
a.setAttachments(buildFileInfoByIdents(a.getAttachments(), a.getSource()));
|
a.setAttachments(buildFileInfoByIdents(a.getAttachments(), a.getSource()));
|
||||||
|
// a.setExt1(buildFileInfoByIdentifiers(a.getExt1()));
|
||||||
|
// a.setExt2(buildFileInfoByIdentifiers(a.getExt2()));
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +141,7 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
||||||
}
|
}
|
||||||
a.setUserImg(img);
|
a.setUserImg(img);
|
||||||
//根据id获取领域名称
|
//根据id获取领域名称
|
||||||
if (StringUtils.isNotEmpty(a.getField1())) {
|
if (StringUtils.isNotEmpty(a.getField1()) && !a.getSource().equals("5")) {
|
||||||
String field1Name = achievementsMapper.getField1NameByParam(a.getSource(), a.getId());
|
String field1Name = achievementsMapper.getField1NameByParam(a.getSource(), a.getId());
|
||||||
if (StringUtils.isNotNull(field1Name)) {
|
if (StringUtils.isNotNull(field1Name)) {
|
||||||
a.setField1Name(field1Name);
|
a.setField1Name(field1Name);
|
||||||
|
|
@ -127,6 +149,8 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
||||||
}
|
}
|
||||||
a.setImages(buildFileInfoByIdents(a.getImages(), a.getSource()));
|
a.setImages(buildFileInfoByIdents(a.getImages(), a.getSource()));
|
||||||
a.setAttachments(buildFileInfoByIdents(a.getAttachments(), a.getSource()));
|
a.setAttachments(buildFileInfoByIdents(a.getAttachments(), a.getSource()));
|
||||||
|
// a.setExt1(buildFileInfoByIdentifiers(a.getExt1()));
|
||||||
|
// a.setExt2(buildFileInfoByIdentifiers(a.getExt2()));
|
||||||
|
|
||||||
//拼接对接的用户信息
|
//拼接对接的用户信息
|
||||||
List<Map<String,Object>> dockingUserInfo = achievementsMapper.getDockingUserInfoList(a.getId());
|
List<Map<String,Object>> dockingUserInfo = achievementsMapper.getDockingUserInfoList(a.getId());
|
||||||
|
|
@ -266,7 +290,7 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
||||||
}
|
}
|
||||||
a.setUserImg(img);
|
a.setUserImg(img);
|
||||||
//根据id获取领域名称
|
//根据id获取领域名称
|
||||||
if (StringUtils.isEmpty(achQueryVo.getSource()) && StringUtils.isNotEmpty(a.getField1())) {
|
if (StringUtils.isEmpty(achQueryVo.getSource()) && StringUtils.isNotEmpty(a.getField1()) && !a.getSource().equals("5")) {
|
||||||
String field1Name = achievementsMapper.getField1NameByParam(a.getSource(), a.getId());
|
String field1Name = achievementsMapper.getField1NameByParam(a.getSource(), a.getId());
|
||||||
if (StringUtils.isNotNull(field1Name)) {
|
if (StringUtils.isNotNull(field1Name)) {
|
||||||
a.setField1Name(field1Name);
|
a.setField1Name(field1Name);
|
||||||
|
|
@ -513,17 +537,19 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
||||||
@Override
|
@Override
|
||||||
public List<AchRelatedResult> getRelatedAchCompetition(Long id, Long sourceId) {
|
public List<AchRelatedResult> getRelatedAchCompetition(Long id, Long sourceId) {
|
||||||
List<AchRelatedResult> relatedResultList = new ArrayList<>();
|
List<AchRelatedResult> relatedResultList = new ArrayList<>();
|
||||||
//想根据开源项目id,获取对应的年度信息
|
if (sourceId !=null){
|
||||||
List<Long> allSourceId = achievementsMapper.getAllSourceIdCompetition(id, sourceId);
|
//想根据开源项目id,获取对应的年度信息
|
||||||
List<String> allYear = achievementsMapper.getDistinctYear(id, allSourceId);
|
List<Long> allSourceId = achievementsMapper.getAllSourceIdCompetition(id, sourceId);
|
||||||
if (StringUtils.isNotNull(allYear)) {
|
List<String> allYear = achievementsMapper.getDistinctYear(id, allSourceId);
|
||||||
//遍历年度信息,获取年度成果数据
|
if (StringUtils.isNotNull(allYear)) {
|
||||||
for (String paramYear : allYear) {
|
//遍历年度信息,获取年度成果数据
|
||||||
AchRelatedResult relatedResult = new AchRelatedResult();
|
for (String paramYear : allYear) {
|
||||||
relatedResult.setYear(paramYear);
|
AchRelatedResult relatedResult = new AchRelatedResult();
|
||||||
List<AchRelatedVo> tmpList = achievementsMapper.getRelatedAch(id, allSourceId, paramYear);
|
relatedResult.setYear(paramYear);
|
||||||
relatedResult.setAchRelatedVoList(tmpList);
|
List<AchRelatedVo> tmpList = achievementsMapper.getRelatedAch(id, allSourceId, paramYear);
|
||||||
relatedResultList.add(relatedResult);
|
relatedResult.setAchRelatedVoList(tmpList);
|
||||||
|
relatedResultList.add(relatedResult);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return relatedResultList;
|
return relatedResultList;
|
||||||
|
|
@ -532,17 +558,19 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
||||||
@Override
|
@Override
|
||||||
public List<AchRelatedResult> getRelatedAchTask(Long id, Long sourceId) {
|
public List<AchRelatedResult> getRelatedAchTask(Long id, Long sourceId) {
|
||||||
List<AchRelatedResult> relatedResultList = new ArrayList<>();
|
List<AchRelatedResult> relatedResultList = new ArrayList<>();
|
||||||
//想根据开源项目id,获取对应的年度信息
|
if (sourceId !=null){
|
||||||
List<Long> allSourceId = achievementsMapper.getAllSourceIdTask(id, sourceId);
|
//想根据开源项目id,获取对应的年度信息
|
||||||
List<String> allYear = achievementsMapper.getDistinctYear(id, allSourceId);
|
List<Long> allSourceId = achievementsMapper.getAllSourceIdTask(id, sourceId);
|
||||||
if (StringUtils.isNotNull(allYear)) {
|
List<String> allYear = achievementsMapper.getDistinctYear(id, allSourceId);
|
||||||
//遍历年度信息,获取年度成果数据
|
if (StringUtils.isNotNull(allYear)) {
|
||||||
for (String paramYear : allYear) {
|
//遍历年度信息,获取年度成果数据
|
||||||
AchRelatedResult relatedResult = new AchRelatedResult();
|
for (String paramYear : allYear) {
|
||||||
relatedResult.setYear(paramYear);
|
AchRelatedResult relatedResult = new AchRelatedResult();
|
||||||
List<AchRelatedVo> tmpList = achievementsMapper.getRelatedAch(id, allSourceId, paramYear);
|
relatedResult.setYear(paramYear);
|
||||||
relatedResult.setAchRelatedVoList(tmpList);
|
List<AchRelatedVo> tmpList = achievementsMapper.getRelatedAch(id, allSourceId, paramYear);
|
||||||
relatedResultList.add(relatedResult);
|
relatedResult.setAchRelatedVoList(tmpList);
|
||||||
|
relatedResultList.add(relatedResult);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return relatedResultList;
|
return relatedResultList;
|
||||||
|
|
@ -587,6 +615,15 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AchievementSourceStatisticVo getSource5Statistic(String name) {
|
||||||
|
AchievementSourceStatisticVo ronbanVo = achievementsMapper.getSource5Field2(name);
|
||||||
|
AchievementSourceStatisticVo statisticVo = achievementsMapper.getSource5Statistic(name);
|
||||||
|
ronbanVo.setClickSum(statisticVo.getClickSum());
|
||||||
|
ronbanVo.setAchievementSum(statisticVo.getAchievementSum());
|
||||||
|
return ronbanVo;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<KeyValueVo> getProjectAreasByName(String areaName) {
|
public List<KeyValueVo> getProjectAreasByName(String areaName) {
|
||||||
return achievementsMapper.getProjectAreasByName(areaName);
|
return achievementsMapper.getProjectAreasByName(areaName);
|
||||||
|
|
@ -629,4 +666,334 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
||||||
return resultVal;
|
return resultVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<KeyValueVo> getAllField2() {
|
||||||
|
List<KeyValueVo> resultVal = achievementsMapper.getAllField2();
|
||||||
|
return resultVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String batchInsertAchievements(List<Achievements> list, boolean updateSupport, String operName) {
|
||||||
|
if (list == null || list.isEmpty()) {
|
||||||
|
throw new RuntimeException("导入项目资源数据不能为空!");
|
||||||
|
}
|
||||||
|
int successNum = 0;
|
||||||
|
int failureNum = 0;
|
||||||
|
StringBuilder successMsg = new StringBuilder();
|
||||||
|
StringBuilder failureMsg = new StringBuilder();
|
||||||
|
|
||||||
|
for (Achievements achievements : list) {
|
||||||
|
try {
|
||||||
|
// 查重:根据项目名称查询
|
||||||
|
Achievements exist = achievementsMapper.selectAchievementsByAchievementName(achievements.getAchievementName());
|
||||||
|
if (null == exist) {
|
||||||
|
achievements.setStatus("1");
|
||||||
|
achievements.setCreateBy(operName);
|
||||||
|
achievements.setCreateTime(new Date());
|
||||||
|
achievements.setUpdateBy(operName);
|
||||||
|
achievements.setUpdateTime(new Date());
|
||||||
|
achievementsMapper.insertAchievements(achievements);
|
||||||
|
successNum++;
|
||||||
|
|
||||||
|
successMsg.append("<br/>").append(successNum).append("、项目 ").append(achievements.getAchievementName()).append(" 导入成功");
|
||||||
|
} else {
|
||||||
|
if (updateSupport) {
|
||||||
|
achievements.setStatus("1");
|
||||||
|
achievements.setId(exist.getId());
|
||||||
|
achievements.setCreateBy(exist.getCreateBy());
|
||||||
|
achievements.setCreateTime(exist.getCreateTime());
|
||||||
|
achievements.setUpdateBy(operName);
|
||||||
|
achievements.setUpdateTime(new Date());
|
||||||
|
achievementsMapper.updateAchievements(achievements);
|
||||||
|
successNum++;
|
||||||
|
successMsg.append("<br/>").append(successNum).append("、项目 ").append(achievements.getAchievementName()).append(" 更新成功");
|
||||||
|
} else {
|
||||||
|
failureNum++;
|
||||||
|
failureMsg.append("<br/>").append(failureNum).append("、项目 ").append(achievements.getAchievementName()).append(" 已存在(未开启更新)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
failureNum++;
|
||||||
|
String msg = "<br/>" + failureNum + "、项目 " + achievements.getAchievementName() + " 导入失败:";
|
||||||
|
failureMsg.append(msg).append(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组装最终提示信息
|
||||||
|
StringBuilder finalMsg = new StringBuilder();
|
||||||
|
if (successNum > 0) {
|
||||||
|
finalMsg.append("共 ").append(successNum).append(" 条数据导入/更新成功:").append(successMsg);
|
||||||
|
}
|
||||||
|
if (failureNum > 0) {
|
||||||
|
finalMsg.append("<br/>共 ").append(failureNum).append(" 条数据导入失败:").append(failureMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalMsg.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String batchImportAchievementsZip(MultipartFile file, boolean updateSupport) {
|
||||||
|
// 尝试多种编码
|
||||||
|
Charset[] charsets = {
|
||||||
|
StandardCharsets.UTF_8,
|
||||||
|
Charset.forName("GBK"),
|
||||||
|
Charset.forName("GB2312"),
|
||||||
|
Charset.forName("ISO-8859-1")
|
||||||
|
};
|
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
List<Achievements> excelDataList = new ArrayList<>();
|
||||||
|
Map<String, AchievementSysFileVo> mp4ImagesExt1 = new HashMap<>();
|
||||||
|
Map<String, AchievementSysFileVo> mp4ImagesExt2 = new HashMap<>();
|
||||||
|
Map<String, AchievementSysFileVo> attachmentMap = new HashMap<>();
|
||||||
|
|
||||||
|
for (Charset charset : charsets) {
|
||||||
|
ZipInputStream zipInputStream = null;
|
||||||
|
try {
|
||||||
|
zipInputStream = new ZipInputStream(file.getInputStream(), charset);
|
||||||
|
ZipEntry entry;
|
||||||
|
while ((entry = zipInputStream.getNextEntry()) != null) {
|
||||||
|
String entryName = entry.getName();
|
||||||
|
|
||||||
|
// 跳过目录条目
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统一路径分隔符(处理Windows和Unix)
|
||||||
|
String normalizedPath = entryName.replace('\\', '/');
|
||||||
|
String fileName = getFileName(normalizedPath);
|
||||||
|
String parentPath = getParentPath(normalizedPath);
|
||||||
|
|
||||||
|
// 1. 处理 Excel 文件
|
||||||
|
if (!entryName.startsWith("附件") && (entryName.endsWith(".xlsx") || entryName.endsWith(".xls"))) {
|
||||||
|
byte[] content = readZipEntryContent(zipInputStream);
|
||||||
|
try (InputStream excelStream = new ByteArrayInputStream(content)) {
|
||||||
|
ExcelUtil<Achievements> util = new ExcelUtil<>(Achievements.class);
|
||||||
|
List<Achievements> dataList = util.importExcel(excelStream);
|
||||||
|
excelDataList.addAll(dataList);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2. 处理 MP4 - 大文件建议保存到临时文件
|
||||||
|
|
||||||
|
else if (parentPath.startsWith("成果图片视频") && entryName.endsWith(".mp4")) {
|
||||||
|
File tempFile = saveToTempFile(zipInputStream, fileName);
|
||||||
|
String contentType = "video/mp4";
|
||||||
|
// 转换为MultipartFile并存储
|
||||||
|
MultipartFile videoFile = new FileMultipartFile(tempFile, fileName, contentType);
|
||||||
|
// 上传视频...
|
||||||
|
R<SysFile> fileResult = remoteFileService.upload(videoFile, "dms", "import", SecurityConstants.INNER);
|
||||||
|
if (R.SUCCESS == fileResult.getCode()) {
|
||||||
|
SysFile sysFile = fileResult.getData();
|
||||||
|
AchievementSysFileVo transferVo = new AchievementSysFileVo();
|
||||||
|
BeanUtils.copyProperties(sysFile, transferVo);
|
||||||
|
transferVo.setK(videoFile.getOriginalFilename());
|
||||||
|
transferVo.setV(sysFile.getUrl());
|
||||||
|
mp4ImagesExt1.put(fileName, transferVo);
|
||||||
|
}
|
||||||
|
// 清理临时文件
|
||||||
|
tempFile.delete();
|
||||||
|
} else if (parentPath.startsWith("应用图片视频") && entryName.endsWith(".mp4")) {
|
||||||
|
File tempFile = saveToTempFile(zipInputStream, fileName);
|
||||||
|
String contentType = "video/mp4";
|
||||||
|
// 转换为MultipartFile并存储
|
||||||
|
MultipartFile videoFile = new FileMultipartFile(tempFile, fileName, contentType);
|
||||||
|
// 上传视频...
|
||||||
|
R<SysFile> fileResult = remoteFileService.upload(videoFile, "dms", "import", SecurityConstants.INNER);
|
||||||
|
if (R.SUCCESS == fileResult.getCode()) {
|
||||||
|
SysFile sysFile = fileResult.getData();
|
||||||
|
AchievementSysFileVo transferVo = new AchievementSysFileVo();
|
||||||
|
BeanUtils.copyProperties(sysFile, transferVo);
|
||||||
|
transferVo.setK(videoFile.getOriginalFilename());
|
||||||
|
transferVo.setV(sysFile.getUrl());
|
||||||
|
mp4ImagesExt2.put(fileName, transferVo);
|
||||||
|
}
|
||||||
|
// 清理临时文件
|
||||||
|
tempFile.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 处理图片文件
|
||||||
|
else if (parentPath.startsWith("成果图片视频") && isImageFile(fileName)) {
|
||||||
|
byte[] content = readZipEntryContent(zipInputStream);
|
||||||
|
String suffix = "png";
|
||||||
|
if (entryName != null && entryName.contains(".")) {
|
||||||
|
suffix = entryName.substring(entryName.lastIndexOf(".") + 1);
|
||||||
|
}
|
||||||
|
String contentType = "image/" + suffix;
|
||||||
|
// 转换为MultipartFile并存储
|
||||||
|
MultipartFile imageFile = new CustomMultipartFile(content, fileName, contentType);
|
||||||
|
R<SysFile> fileResult = remoteFileService.upload(imageFile, "dms", "import", SecurityConstants.INNER);
|
||||||
|
if (R.SUCCESS == fileResult.getCode()) {
|
||||||
|
SysFile sysFile = fileResult.getData();
|
||||||
|
AchievementSysFileVo transferVo = new AchievementSysFileVo();
|
||||||
|
BeanUtils.copyProperties(sysFile, transferVo);
|
||||||
|
transferVo.setK(imageFile.getOriginalFilename());
|
||||||
|
transferVo.setV(sysFile.getUrl());
|
||||||
|
mp4ImagesExt1.put(fileName, transferVo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 3. 处理图片文件
|
||||||
|
else if (parentPath.startsWith("应用图片视频") && isImageFile(fileName)) {
|
||||||
|
byte[] content = readZipEntryContent(zipInputStream);
|
||||||
|
String suffix = "png";
|
||||||
|
if (entryName != null && entryName.contains(".")) {
|
||||||
|
suffix = entryName.substring(entryName.lastIndexOf(".") + 1);
|
||||||
|
}
|
||||||
|
String contentType = "image/" + suffix;
|
||||||
|
// 转换为MultipartFile并存储
|
||||||
|
MultipartFile imageFile = new CustomMultipartFile(content, fileName, contentType);
|
||||||
|
R<SysFile> fileResult = remoteFileService.upload(imageFile, "dms", "import", SecurityConstants.INNER);
|
||||||
|
if (R.SUCCESS == fileResult.getCode()) {
|
||||||
|
SysFile sysFile = fileResult.getData();
|
||||||
|
AchievementSysFileVo transferVo = new AchievementSysFileVo();
|
||||||
|
BeanUtils.copyProperties(sysFile, transferVo);
|
||||||
|
transferVo.setK(imageFile.getOriginalFilename());
|
||||||
|
transferVo.setV(sysFile.getUrl());
|
||||||
|
mp4ImagesExt2.put(fileName, transferVo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (parentPath.startsWith("附件")) {
|
||||||
|
File tempFile = saveToTempFile(zipInputStream, fileName);
|
||||||
|
String contentType = FileTypeMap.getDefaultFileTypeMap().getContentType(fileName);
|
||||||
|
// 转换为MultipartFile并存储
|
||||||
|
MultipartFile attachmentFile = new FileMultipartFile(tempFile, fileName, contentType);
|
||||||
|
// 上传视频...
|
||||||
|
R<SysFile> fileResult = remoteFileService.upload(attachmentFile, "dms", "import", SecurityConstants.INNER);
|
||||||
|
if (R.SUCCESS == fileResult.getCode()) {
|
||||||
|
SysFile sysFile = fileResult.getData();
|
||||||
|
AchievementSysFileVo transferVo = new AchievementSysFileVo();
|
||||||
|
BeanUtils.copyProperties(sysFile, transferVo);
|
||||||
|
transferVo.setK(attachmentFile.getOriginalFilename());
|
||||||
|
transferVo.setV(sysFile.getUrl());
|
||||||
|
attachmentMap.put(fileName, transferVo);
|
||||||
|
}
|
||||||
|
// 清理临时文件
|
||||||
|
tempFile.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
zipInputStream.closeEntry();
|
||||||
|
}
|
||||||
|
logger.info("✅ 使用 " + charset.displayName() + " 编码成功读取 ZIP");
|
||||||
|
|
||||||
|
excelDataList.forEach(achievements -> {
|
||||||
|
List<Object> mp4ImagesExt1List = mp4ImagesExt1.entrySet().stream()
|
||||||
|
.filter(item -> item.getKey().contains(achievements.getAchievementName()))
|
||||||
|
.map(Map.Entry::getValue)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
List<Object> mp4ImagesExt2List = mp4ImagesExt2.entrySet().stream()
|
||||||
|
.filter(item -> item.getKey().contains(achievements.getAchievementName()))
|
||||||
|
.map(Map.Entry::getValue)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
List<Object> filterAttachmentList = attachmentMap.entrySet().stream()
|
||||||
|
.filter(item -> item.getKey().contains(achievements.getAchievementName()))
|
||||||
|
.map(Map.Entry::getValue)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (!mp4ImagesExt1List.isEmpty()){
|
||||||
|
achievements.setExt1(JSONObject.toJSONString(mp4ImagesExt1List));
|
||||||
|
}
|
||||||
|
if (!mp4ImagesExt2List.isEmpty()){
|
||||||
|
achievements.setExt2(JSONObject.toJSONString(mp4ImagesExt2List));
|
||||||
|
}
|
||||||
|
if (!filterAttachmentList.isEmpty()){
|
||||||
|
achievements.setAttachments(JSONObject.toJSONString(filterAttachmentList));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 保存 Excel 数据到数据库
|
||||||
|
String operName = SecurityUtils.getUsername();
|
||||||
|
String message = excelDataList.isEmpty() ? "" : batchInsertAchievements(excelDataList, updateSupport, operName);
|
||||||
|
message = message + "<br/>压缩包共导入 " + (mp4ImagesExt1.size() + mp4ImagesExt2.size() + attachmentMap.size()) + " 个文件";
|
||||||
|
result.put("excelDataCount", excelDataList.size());
|
||||||
|
result.put("mp4ImagesExt1", mp4ImagesExt1);
|
||||||
|
result.put("mp4ImagesExt2", mp4ImagesExt2);
|
||||||
|
result.put("attachments", attachmentMap);
|
||||||
|
result.put("message", message);
|
||||||
|
return message;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("读取文件失败: " + e.getMessage());
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
logger.error("使用 " + charset.displayName() + " 编码失败: " + ex.getMessage());
|
||||||
|
} finally {
|
||||||
|
if (zipInputStream != null) {
|
||||||
|
try {
|
||||||
|
zipInputStream.close();
|
||||||
|
}catch (IOException exc){
|
||||||
|
exc.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存流内容到临时文件
|
||||||
|
*/
|
||||||
|
private File saveToTempFile(ZipInputStream zipInputStream, String fileName) throws IOException {
|
||||||
|
Path tempFile = Files.createTempFile("temp_", "_" + fileName);
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(tempFile.toFile())) {
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int len;
|
||||||
|
while ((len = zipInputStream.read(buffer)) != -1) {
|
||||||
|
fos.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tempFile.toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取 ZipEntry 的内容到字节数组(Java 8 兼容)
|
||||||
|
*/
|
||||||
|
private byte[] readZipEntryContent(ZipInputStream zipInputStream) throws IOException {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
byte[] buffer = new byte[8192]; // 8KB 缓冲区
|
||||||
|
int len;
|
||||||
|
while ((len = zipInputStream.read(buffer)) != -1) {
|
||||||
|
baos.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助方法:判断是否为图片
|
||||||
|
private boolean isImageFile(String fileName) {
|
||||||
|
String lower = fileName.toLowerCase();
|
||||||
|
return lower.endsWith(".jpg") || lower.endsWith(".jpeg") ||
|
||||||
|
lower.endsWith(".png") || lower.endsWith(".gif") || lower.endsWith(".bmp");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件名(去掉路径)
|
||||||
|
*/
|
||||||
|
private String getFileName(String path) {
|
||||||
|
if (path == null || path.isEmpty()) return "";
|
||||||
|
int lastSlash = path.lastIndexOf('/');
|
||||||
|
if (lastSlash >= 0) {
|
||||||
|
return path.substring(lastSlash + 1);
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取父路径(去掉文件名)
|
||||||
|
*/
|
||||||
|
private String getParentPath(String path) {
|
||||||
|
if (path == null || path.isEmpty()) return "";
|
||||||
|
int lastSlash = path.lastIndexOf('/');
|
||||||
|
if (lastSlash >= 0) {
|
||||||
|
return path.substring(0, lastSlash);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildFileInfoByIdentifiers(String identifiers) {
|
||||||
|
if (StringUtils.isEmpty(identifiers)) {
|
||||||
|
return identifiers;
|
||||||
|
}
|
||||||
|
R<List<SysFileInfo>> result = remoteFileService.getFileListByIdentifier(identifiers);
|
||||||
|
return JSON.toJSONString(result.getData());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,34 @@
|
||||||
package com.microservices.dms.achievementLibrary.service.impl;
|
package com.microservices.dms.achievementLibrary.service.impl;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.constant.SecurityConstants;
|
||||||
import com.microservices.common.core.constant.UserConstants;
|
import com.microservices.common.core.constant.UserConstants;
|
||||||
|
import com.microservices.common.core.domain.R;
|
||||||
import com.microservices.common.core.exception.ServiceException;
|
import com.microservices.common.core.exception.ServiceException;
|
||||||
import com.microservices.common.core.utils.DateUtils;
|
import com.microservices.common.core.utils.DateUtils;
|
||||||
import com.microservices.common.core.utils.StringUtils;
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
|
import com.microservices.common.datasource.annotation.Slave;
|
||||||
import com.microservices.common.security.utils.SecurityUtils;
|
import com.microservices.common.security.utils.SecurityUtils;
|
||||||
import com.microservices.dms.achievementLibrary.domain.AchievementTeam;
|
import com.microservices.dms.achievementLibrary.domain.AchievementTeam;
|
||||||
import com.microservices.dms.achievementLibrary.domain.Achievements;
|
import com.microservices.dms.achievementLibrary.domain.Achievements;
|
||||||
import com.microservices.dms.achievementLibrary.mapper.AchievementTeamMapper;
|
import com.microservices.dms.achievementLibrary.mapper.AchievementTeamMapper;
|
||||||
import com.microservices.dms.achievementLibrary.mapper.AchievementsMapper;
|
import com.microservices.dms.achievementLibrary.mapper.AchievementsMapper;
|
||||||
import com.microservices.dms.achievementLibrary.service.IAchievementsService;
|
import com.microservices.dms.achievementLibrary.service.IAchievementsService;
|
||||||
import com.microservices.system.api.domain.SysUser;
|
import com.microservices.system.api.RemoteFileService;
|
||||||
import com.microservices.system.api.model.LoginUser;
|
import com.microservices.system.api.model.LoginUser;
|
||||||
|
import org.apache.commons.fileupload.FileItem;
|
||||||
|
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import com.microservices.dms.achievementLibrary.mapper.SchoolEnterpriseAchievementsMapper;
|
import com.microservices.dms.achievementLibrary.mapper.SchoolEnterpriseAchievementsMapper;
|
||||||
import com.microservices.dms.achievementLibrary.domain.SchoolEnterpriseAchievements;
|
import com.microservices.dms.achievementLibrary.domain.SchoolEnterpriseAchievements;
|
||||||
import com.microservices.dms.achievementLibrary.service.ISchoolEnterpriseAchievementsService;
|
import com.microservices.dms.achievementLibrary.service.ISchoolEnterpriseAchievementsService;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.multipart.commons.CommonsMultipartFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校企成果Service业务层处理
|
* 校企成果Service业务层处理
|
||||||
|
|
@ -41,6 +50,9 @@ public class SchoolEnterpriseAchievementsServiceImpl implements ISchoolEnterpris
|
||||||
@Autowired
|
@Autowired
|
||||||
private AchievementsMapper achievementsMapper;
|
private AchievementsMapper achievementsMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RemoteFileService remoteFileService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询校企成果
|
* 查询校企成果
|
||||||
*
|
*
|
||||||
|
|
@ -124,6 +136,144 @@ public class SchoolEnterpriseAchievementsServiceImpl implements ISchoolEnterpris
|
||||||
return UserConstants.UNIQUE;
|
return UserConstants.UNIQUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入成果数据(包含图片处理)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
@Slave
|
||||||
|
public String batchInsertSchoolEnterpriseAchievements(List<SchoolEnterpriseAchievements> list,
|
||||||
|
Map<String, MultipartFile> imageMap,
|
||||||
|
boolean updateSupport,
|
||||||
|
String operName) {
|
||||||
|
if (list == null || list.isEmpty()) {
|
||||||
|
throw new RuntimeException("导入成果数据不能为空!");
|
||||||
|
}
|
||||||
|
int successNum = 0;
|
||||||
|
int failureNum = 0;
|
||||||
|
int imageErrorNum = 0; // 新增:图片处理失败数
|
||||||
|
StringBuilder successMsg = new StringBuilder();
|
||||||
|
StringBuilder failureMsg = new StringBuilder();
|
||||||
|
StringBuilder imageErrorMsg = new StringBuilder(); // 新增:图片错误信息
|
||||||
|
|
||||||
|
for (SchoolEnterpriseAchievements schoolEnterpriseAchievement : list) {
|
||||||
|
try {
|
||||||
|
// 处理图片字段(优化后:返回处理结果,不抛出异常)
|
||||||
|
String imageHandleResult = handleAchievementImage(schoolEnterpriseAchievement, imageMap);
|
||||||
|
if (imageHandleResult.contains("失败") || imageHandleResult.contains("异常")) {
|
||||||
|
imageErrorNum++;
|
||||||
|
imageErrorMsg.append("<br/>").append(imageErrorNum).append("、成果 ").append(schoolEnterpriseAchievement.getAchievementName()).append(" 图片处理失败:").append(imageHandleResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 原有查重和入库逻辑(不受图片处理影响)
|
||||||
|
SchoolEnterpriseAchievements exist = schoolEnterpriseAchievementsMapper.selectSchoolEnterpriseAchievementsByName(schoolEnterpriseAchievement.getAchievementName());
|
||||||
|
if (exist == null) {
|
||||||
|
schoolEnterpriseAchievement.setCreateBy(operName);
|
||||||
|
schoolEnterpriseAchievement.setCreateTime(new Date());
|
||||||
|
schoolEnterpriseAchievement.setUpdateBy(operName);
|
||||||
|
schoolEnterpriseAchievement.setUpdateTime(new Date());
|
||||||
|
schoolEnterpriseAchievement.setStatus("2");
|
||||||
|
schoolEnterpriseAchievementsMapper.insertSchoolEnterpriseAchievements(schoolEnterpriseAchievement);
|
||||||
|
successNum++;
|
||||||
|
successMsg.append("<br/>").append(successNum).append("、成果 ").append(schoolEnterpriseAchievement.getAchievementName()).append(" 导入成功");
|
||||||
|
} else {
|
||||||
|
if (updateSupport) {
|
||||||
|
schoolEnterpriseAchievement.setId(exist.getId());
|
||||||
|
schoolEnterpriseAchievement.setCreateBy(exist.getCreateBy());
|
||||||
|
schoolEnterpriseAchievement.setCreateTime(exist.getCreateTime());
|
||||||
|
schoolEnterpriseAchievement.setUpdateBy(operName);
|
||||||
|
schoolEnterpriseAchievement.setUpdateTime(new Date());
|
||||||
|
schoolEnterpriseAchievementsMapper.updateSchoolEnterpriseAchievements(schoolEnterpriseAchievement);
|
||||||
|
successNum++;
|
||||||
|
successMsg.append("<br/>").append(successNum).append("、成果 ").append(schoolEnterpriseAchievement.getAchievementName()).append(" 更新成功");
|
||||||
|
} else {
|
||||||
|
failureNum++;
|
||||||
|
failureMsg.append("<br/>").append(failureNum).append("、成果 ").append(schoolEnterpriseAchievement.getAchievementName()).append(" 已存在(未开启更新)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
failureNum++;
|
||||||
|
String msg = "<br/>" + failureNum + "、成果 " + schoolEnterpriseAchievement.getAchievementName() + " 导入失败:";
|
||||||
|
failureMsg.append(msg).append(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组装最终提示信息(包含图片处理错误)
|
||||||
|
StringBuilder finalMsg = new StringBuilder();
|
||||||
|
if (successNum > 0) {
|
||||||
|
finalMsg.append("共 ").append(successNum).append(" 条数据导入/更新成功:").append(successMsg);
|
||||||
|
}
|
||||||
|
if (failureNum > 0) {
|
||||||
|
finalMsg.append("<br/>共 ").append(failureNum).append(" 条数据导入失败:").append(failureMsg);
|
||||||
|
}
|
||||||
|
if (imageErrorNum > 0) {
|
||||||
|
finalMsg.append("<br/>共 ").append(imageErrorNum).append(" 条数据图片处理失败:").append(imageErrorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalMsg.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理成果图片:上传并格式化存储(FastJSON解析版)
|
||||||
|
* @param achievement 成果实体
|
||||||
|
* @param imageMap Excel解析出的图片映射表
|
||||||
|
* @return 图片处理结果提示(成功/失败信息)
|
||||||
|
*/
|
||||||
|
private String handleAchievementImage(SchoolEnterpriseAchievements achievement, Map<String, MultipartFile> imageMap) {
|
||||||
|
String imageCellKey = achievement.getImages();
|
||||||
|
if (StringUtils.isEmpty(imageCellKey) || !imageMap.containsKey(imageCellKey)) {
|
||||||
|
achievement.setImages("[]");
|
||||||
|
return "无图片,跳过处理";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
MultipartFile file = imageMap.get(imageCellKey);
|
||||||
|
byte[] fileBytes = file.getBytes();
|
||||||
|
|
||||||
|
if (fileBytes == null || fileBytes.length == 0) {
|
||||||
|
return "图片文件为空,跳过处理";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建 HashMap 参数
|
||||||
|
String originalFilename = StringUtils.isEmpty(file.getOriginalFilename())
|
||||||
|
? "excel_import_image_" + System.currentTimeMillis() + ".png"
|
||||||
|
: file.getOriginalFilename();
|
||||||
|
|
||||||
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.put("base64Data", Base64.getEncoder().encodeToString(fileBytes));
|
||||||
|
params.put("fileName", originalFilename);
|
||||||
|
params.put("contentType", file.getContentType());
|
||||||
|
params.put("size", fileBytes.length);
|
||||||
|
|
||||||
|
// 调用 Base64 上传接口
|
||||||
|
R<?> fileResult = remoteFileService.uploadBase64(params, "dms", "import", SecurityConstants.INNER);
|
||||||
|
|
||||||
|
// 解析结果(与原逻辑相同)
|
||||||
|
if (StringUtils.isNull(fileResult) || StringUtils.isNull(fileResult.getData())) {
|
||||||
|
String errorMsg = !StringUtils.isNull(fileResult) ? fileResult.getMsg() : "接口返回异常";
|
||||||
|
return "图片上传失败:" + errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject resultJson = JSONObject.parseObject(JSONObject.toJSONString(fileResult.getData()));
|
||||||
|
String fileOriginName = resultJson.getString("fileOriginName");
|
||||||
|
String url = resultJson.getString("downloadUrl");
|
||||||
|
Integer fileId = resultJson.getInteger("fileId");
|
||||||
|
|
||||||
|
if (StringUtils.isEmpty(fileOriginName) || StringUtils.isEmpty(url) || fileId == null) {
|
||||||
|
return "图片上传成功,但返回数据不完整";
|
||||||
|
}
|
||||||
|
|
||||||
|
String imageJson = String.format("[{\"k\":\"%s\",\"v\":\"%s\",\"id\":%d}]",
|
||||||
|
fileOriginName, url, fileId);
|
||||||
|
achievement.setImages(imageJson);
|
||||||
|
|
||||||
|
return "图片处理成功";
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "图片处理异常:" + e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改校企成果
|
* 修改校企成果
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.microservices.dms.common.vo;
|
||||||
|
|
||||||
|
import com.microservices.system.api.domain.SysFile;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class AchievementSysFileVo extends SysFile {
|
||||||
|
/**
|
||||||
|
* 文件名称
|
||||||
|
*/
|
||||||
|
private String k;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件地址
|
||||||
|
*/
|
||||||
|
private String v;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
package com.microservices.dms.resourceLibrary.controller;
|
package com.microservices.dms.resourceLibrary.controller;
|
||||||
|
|
||||||
import com.microservices.common.core.utils.PageUtils;
|
import com.microservices.common.core.utils.PageUtils;
|
||||||
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
import com.microservices.common.core.utils.poi.ExcelUtil;
|
import com.microservices.common.core.utils.poi.ExcelUtil;
|
||||||
import com.microservices.common.core.web.controller.BaseController;
|
import com.microservices.common.core.web.controller.BaseController;
|
||||||
import com.microservices.common.core.web.domain.AjaxResult;
|
import com.microservices.common.core.web.domain.AjaxResult;
|
||||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||||
import com.microservices.common.core.web.page.TableDataInfo;
|
import com.microservices.common.core.web.page.TableDataInfo;
|
||||||
|
import com.microservices.common.log.annotation.Log;
|
||||||
|
import com.microservices.common.log.enums.BusinessType;
|
||||||
|
import com.microservices.common.security.utils.SecurityUtils;
|
||||||
import com.microservices.dms.resourceLibrary.domain.CompetitionResourceLibrary;
|
import com.microservices.dms.resourceLibrary.domain.CompetitionResourceLibrary;
|
||||||
import com.microservices.dms.resourceLibrary.domain.vo.CompetitionListVo;
|
import com.microservices.dms.resourceLibrary.domain.vo.CompetitionListVo;
|
||||||
import com.microservices.dms.resourceLibrary.service.CompetitionResourceLibraryService;
|
import com.microservices.dms.resourceLibrary.service.CompetitionResourceLibraryService;
|
||||||
|
|
@ -17,6 +21,7 @@ import io.swagger.annotations.ApiImplicitParams;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -78,6 +83,17 @@ public class CompetitionResourceLibraryController extends BaseController {
|
||||||
util.exportExcel(response, list, "数据");
|
util.exportExcel(response, list, "数据");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/importData")
|
||||||
|
@Log(title = "竞赛资源库", businessType = BusinessType.INSERT)
|
||||||
|
public AjaxResult importData(@RequestPart("file") MultipartFile file,
|
||||||
|
@RequestParam(value = "updateSupport", defaultValue = "false") boolean updateSupport) throws Exception {
|
||||||
|
ExcelUtil<CompetitionResourceLibrary> util = new ExcelUtil<CompetitionResourceLibrary>(CompetitionResourceLibrary.class);
|
||||||
|
List<CompetitionResourceLibrary> list = util.importExcel(StringUtils.EMPTY, file.getInputStream(), 0);
|
||||||
|
String operName = SecurityUtils.getUsername();
|
||||||
|
String message = competitionResourceLibraryService.batchInsertCompetitionResourceLibrary(list, updateSupport, operName);
|
||||||
|
return AjaxResult.success(message);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/{id}")
|
@GetMapping(value = "/{id}")
|
||||||
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
||||||
return success(competitionResourceLibraryService.selectCompetitionResourceLibraryById(id));
|
return success(competitionResourceLibraryService.selectCompetitionResourceLibraryById(id));
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.microservices.dms.resourceLibrary.controller;
|
package com.microservices.dms.resourceLibrary.controller;
|
||||||
|
|
||||||
import com.microservices.common.core.utils.PageUtils;
|
import com.microservices.common.core.utils.PageUtils;
|
||||||
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
import com.microservices.common.core.utils.poi.ExcelUtil;
|
import com.microservices.common.core.utils.poi.ExcelUtil;
|
||||||
import com.microservices.common.core.web.controller.BaseController;
|
import com.microservices.common.core.web.controller.BaseController;
|
||||||
import com.microservices.common.core.web.domain.AjaxResult;
|
import com.microservices.common.core.web.domain.AjaxResult;
|
||||||
|
|
@ -8,16 +9,18 @@ import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||||
import com.microservices.common.core.web.page.TableDataInfo;
|
import com.microservices.common.core.web.page.TableDataInfo;
|
||||||
import com.microservices.dms.resourceLibrary.domain.ProjectResourceLibrary;
|
import com.microservices.dms.resourceLibrary.domain.ProjectResourceLibrary;
|
||||||
import com.microservices.dms.resourceLibrary.domain.vo.ProjectListVo;
|
import com.microservices.dms.resourceLibrary.domain.vo.ProjectListVo;
|
||||||
import com.microservices.dms.resourceLibrary.domain.vo.TaskListVo;
|
import com.microservices.common.log.annotation.Log;
|
||||||
|
import com.microservices.common.log.enums.BusinessType;
|
||||||
|
import com.microservices.common.security.utils.SecurityUtils;
|
||||||
import com.microservices.dms.resourceLibrary.domain.vo.UserActionDataVo;
|
import com.microservices.dms.resourceLibrary.domain.vo.UserActionDataVo;
|
||||||
import com.microservices.dms.resourceLibrary.service.ProjectResourceLibraryService;
|
import com.microservices.dms.resourceLibrary.service.ProjectResourceLibraryService;
|
||||||
import com.microservices.dms.resourceLibrary.service.TaskResourceLibraryService;
|
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiImplicitParam;
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
import io.swagger.annotations.ApiImplicitParams;
|
import io.swagger.annotations.ApiImplicitParams;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -122,6 +125,23 @@ public class ProjectResourceLibraryController extends BaseController {
|
||||||
util.exportExcel(response, list, "数据");
|
util.exportExcel(response, list, "数据");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入项目资源库数据
|
||||||
|
*/
|
||||||
|
@PostMapping("/importData")
|
||||||
|
@Log(title = "项目资源库", businessType = BusinessType.INSERT)
|
||||||
|
public AjaxResult importData(@RequestPart("file") MultipartFile file,
|
||||||
|
@RequestParam(value = "updateSupport", defaultValue = "false") boolean updateSupport) throws Exception {
|
||||||
|
ExcelUtil<ProjectResourceLibrary> util = new ExcelUtil<>(ProjectResourceLibrary.class);
|
||||||
|
// 解析Excel,获取实体列表
|
||||||
|
List<ProjectResourceLibrary> list = util.importExcel(StringUtils.EMPTY, file.getInputStream(), 0);
|
||||||
|
// 调用业务层处理
|
||||||
|
String operName = SecurityUtils.getUsername();
|
||||||
|
String message = projectResourceLibraryService.batchInsertProjectResourceLibrary(list, updateSupport, operName);
|
||||||
|
|
||||||
|
return AjaxResult.success(message);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/{id}")
|
@GetMapping(value = "/{id}")
|
||||||
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
||||||
return success(projectResourceLibraryService.selectProjectResourceLibraryById(id));
|
return success(projectResourceLibraryService.selectProjectResourceLibraryById(id));
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.microservices.dms.resourceLibrary.controller;
|
package com.microservices.dms.resourceLibrary.controller;
|
||||||
|
|
||||||
import com.microservices.common.core.utils.PageUtils;
|
import com.microservices.common.core.utils.PageUtils;
|
||||||
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
import com.microservices.common.core.utils.poi.ExcelUtil;
|
import com.microservices.common.core.utils.poi.ExcelUtil;
|
||||||
import com.microservices.common.core.web.controller.BaseController;
|
import com.microservices.common.core.web.controller.BaseController;
|
||||||
import com.microservices.common.core.web.domain.AjaxResult;
|
import com.microservices.common.core.web.domain.AjaxResult;
|
||||||
|
|
@ -8,6 +9,7 @@ import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||||
import com.microservices.common.core.web.page.TableDataInfo;
|
import com.microservices.common.core.web.page.TableDataInfo;
|
||||||
import com.microservices.common.log.annotation.Log;
|
import com.microservices.common.log.annotation.Log;
|
||||||
import com.microservices.common.log.enums.BusinessType;
|
import com.microservices.common.log.enums.BusinessType;
|
||||||
|
import com.microservices.common.security.utils.SecurityUtils;
|
||||||
import com.microservices.dms.resourceLibrary.domain.TaskResourceLibrary;
|
import com.microservices.dms.resourceLibrary.domain.TaskResourceLibrary;
|
||||||
import com.microservices.dms.resourceLibrary.domain.vo.TaskListVo;
|
import com.microservices.dms.resourceLibrary.domain.vo.TaskListVo;
|
||||||
import com.microservices.dms.resourceLibrary.domain.vo.UserActionDataVo;
|
import com.microservices.dms.resourceLibrary.domain.vo.UserActionDataVo;
|
||||||
|
|
@ -18,6 +20,7 @@ import io.swagger.annotations.ApiImplicitParams;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -134,6 +137,17 @@ public class TaskResourceLibraryController extends BaseController {
|
||||||
util.exportExcel(response, list, "数据");
|
util.exportExcel(response, list, "数据");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/importData")
|
||||||
|
@Log(title = "任务资源库", businessType = BusinessType.INSERT)
|
||||||
|
public AjaxResult importData(@RequestPart("file") MultipartFile file,
|
||||||
|
@RequestParam(value = "updateSupport", defaultValue = "false") boolean updateSupport) throws Exception {
|
||||||
|
ExcelUtil<TaskResourceLibrary> util = new ExcelUtil<TaskResourceLibrary>(TaskResourceLibrary.class);
|
||||||
|
List<TaskResourceLibrary> list = util.importExcel(StringUtils.EMPTY, file.getInputStream(), 0);
|
||||||
|
String operName = SecurityUtils.getUsername();
|
||||||
|
String message = taskResourceLibraryService.batchInsertTaskResourceLibrary(list, updateSupport, operName);
|
||||||
|
return AjaxResult.success(message);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/{id}")
|
@GetMapping(value = "/{id}")
|
||||||
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
||||||
return success(taskResourceLibraryService.selectTaskResourceLibraryById(id));
|
return success(taskResourceLibraryService.selectTaskResourceLibraryById(id));
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.microservices.common.core.annotation.Excel;
|
||||||
import com.microservices.common.core.web.domain.BaseEntity;
|
import com.microservices.common.core.web.domain.BaseEntity;
|
||||||
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
||||||
|
|
||||||
|
|
@ -19,10 +20,12 @@ public class CompetitionResourceLibrary extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
* 开放竞赛ID
|
* 开放竞赛ID
|
||||||
*/
|
*/
|
||||||
|
@Excel(name = "竞赛ID")
|
||||||
private Long openCompetitionId;
|
private Long openCompetitionId;
|
||||||
/**
|
/**
|
||||||
* 开放竞赛名称
|
* 开放竞赛名称
|
||||||
*/
|
*/
|
||||||
|
@Excel(name = "竞赛名称")
|
||||||
private String openCompetitionName;
|
private String openCompetitionName;
|
||||||
/**
|
/**
|
||||||
* 开放竞赛创建者
|
* 开放竞赛创建者
|
||||||
|
|
@ -31,23 +34,28 @@ public class CompetitionResourceLibrary extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
* 竞赛领域
|
* 竞赛领域
|
||||||
*/
|
*/
|
||||||
|
@Excel(name = "成果领域")
|
||||||
private String competitionField;
|
private String competitionField;
|
||||||
/**
|
/**
|
||||||
* 竞赛状态 status: 0 未上架 1上架
|
* 竞赛状态 status: 0 未上架 1上架
|
||||||
*/
|
*/
|
||||||
|
@Excel(name = "竞赛状态", readConverterExp = "0=未上架,1=上架")
|
||||||
private String competitionStatus;
|
private String competitionStatus;
|
||||||
/**
|
/**
|
||||||
* 竞赛提交名称
|
* 竞赛提交名称
|
||||||
*/
|
*/
|
||||||
|
@Excel(name = "作品名称")
|
||||||
private String competitionSubmissionName;
|
private String competitionSubmissionName;
|
||||||
/**
|
/**
|
||||||
* 作品提交时间
|
* 作品提交时间
|
||||||
*/
|
*/
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
@Excel(name = "作品提交时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date submissionTime;
|
private Date submissionTime;
|
||||||
/**
|
/**
|
||||||
* 提交者
|
* 提交者
|
||||||
*/
|
*/
|
||||||
|
@Excel(name = "提交人")
|
||||||
private String submitter;
|
private String submitter;
|
||||||
/**
|
/**
|
||||||
* 提交类型
|
* 提交类型
|
||||||
|
|
@ -76,11 +84,13 @@ public class CompetitionResourceLibrary extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
* 是否已转入成果库 0否 1是
|
* 是否已转入成果库 0否 1是
|
||||||
*/
|
*/
|
||||||
|
@Excel(name = "转入状态", readConverterExp = "0=未转入,1=已转入")
|
||||||
private Integer isTransferredToResultLibrary;
|
private Integer isTransferredToResultLibrary;
|
||||||
/**
|
/**
|
||||||
* 转入成果库时间
|
* 转入成果库时间
|
||||||
*/
|
*/
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
@Excel(name = "转入时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date transferredToResultLibraryTime;
|
private Date transferredToResultLibraryTime;
|
||||||
/**
|
/**
|
||||||
* 是否精选成果
|
* 是否精选成果
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.microservices.common.core.annotation.Excel;
|
||||||
import com.microservices.common.core.web.domain.BaseEntity;
|
import com.microservices.common.core.web.domain.BaseEntity;
|
||||||
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
||||||
|
|
||||||
|
|
@ -18,8 +19,10 @@ public class ProjectResourceLibrary extends BaseEntity {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private Long id;
|
private Long id;
|
||||||
//项目资源名称
|
//项目资源名称
|
||||||
|
@Excel(name = "项目名称")
|
||||||
private String projectName;
|
private String projectName;
|
||||||
//项目领域
|
//项目领域
|
||||||
|
@Excel(name = "成果领域")
|
||||||
private String projectDomain;
|
private String projectDomain;
|
||||||
//项目领域名称
|
//项目领域名称
|
||||||
private String projectDomainName;
|
private String projectDomainName;
|
||||||
|
|
@ -27,19 +30,24 @@ public class ProjectResourceLibrary extends BaseEntity {
|
||||||
private String identifier;
|
private String identifier;
|
||||||
private String userIdentifier;
|
private String userIdentifier;
|
||||||
//开源项目ID
|
//开源项目ID
|
||||||
|
@Excel(name = "项目ID")
|
||||||
private Long projectId;
|
private Long projectId;
|
||||||
//仓库ID
|
//仓库ID
|
||||||
private Long repositoryId;
|
private Long repositoryId;
|
||||||
//版本Id
|
//版本Id
|
||||||
private Long versionReleasesId;
|
private Long versionReleasesId;
|
||||||
//项目是否已公开
|
//项目是否已公开
|
||||||
|
@Excel(name = "是否公开", readConverterExp = "0=否,1=是")
|
||||||
private Long isPublic;
|
private Long isPublic;
|
||||||
//发版名称
|
//发版名称
|
||||||
|
@Excel(name = "发行版名称")
|
||||||
private String releaseName;
|
private String releaseName;
|
||||||
//发版时间
|
//发版时间
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
@Excel(name = "发版时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date releaseDate;
|
private Date releaseDate;
|
||||||
//发版人
|
//发版人
|
||||||
|
@Excel(name = "发版人")
|
||||||
private String releasePerson;
|
private String releasePerson;
|
||||||
//发版类型
|
//发版类型
|
||||||
private String releaseType;
|
private String releaseType;
|
||||||
|
|
@ -54,9 +62,11 @@ public class ProjectResourceLibrary extends BaseEntity {
|
||||||
//联系时间
|
//联系时间
|
||||||
private String contactPhone;
|
private String contactPhone;
|
||||||
//是否已转入成果库
|
//是否已转入成果库
|
||||||
|
@Excel(name = "转入状态", readConverterExp = "0=未转入,1=已转入")
|
||||||
private Long isTransferredToAchievement;
|
private Long isTransferredToAchievement;
|
||||||
//转入成果库时间
|
//转入成果库时间
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
@Excel(name = "转入时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date transferDate;
|
private Date transferDate;
|
||||||
//是否精选成果
|
//是否精选成果
|
||||||
private Long isSelectedAchievement;
|
private Long isSelectedAchievement;
|
||||||
|
|
|
||||||
|
|
@ -21,21 +21,28 @@ public class TaskResourceLibrary extends BaseEntity {
|
||||||
//
|
//
|
||||||
private Long id;
|
private Long id;
|
||||||
//创客任务ID
|
//创客任务ID
|
||||||
|
@Excel(name = "任务ID")
|
||||||
private Long taskId;
|
private Long taskId;
|
||||||
//
|
//
|
||||||
private Long paperId;
|
private Long paperId;
|
||||||
//创客任务名称
|
//创客任务名称
|
||||||
|
@Excel(name = "任务名称")
|
||||||
private String taskName;
|
private String taskName;
|
||||||
//任务领域
|
//任务领域
|
||||||
|
@Excel(name = "成果领域")
|
||||||
private String taskDomain;
|
private String taskDomain;
|
||||||
//创客任务金额
|
//创客任务金额
|
||||||
|
@Excel(name = "任务金额(元)")
|
||||||
private BigDecimal taskAmount;
|
private BigDecimal taskAmount;
|
||||||
//胜出交稿名称
|
//胜出交稿名称
|
||||||
|
@Excel(name = "成果编号")
|
||||||
private String submissionName;
|
private String submissionName;
|
||||||
//交稿时间
|
//交稿时间
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
@Excel(name = "交稿时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date submissionDate;
|
private Date submissionDate;
|
||||||
//交稿人
|
//交稿人
|
||||||
|
@Excel(name = "交稿人")
|
||||||
private String submitterName;
|
private String submitterName;
|
||||||
//交稿类型
|
//交稿类型
|
||||||
private String submissionType;
|
private String submissionType;
|
||||||
|
|
@ -50,9 +57,11 @@ public class TaskResourceLibrary extends BaseEntity {
|
||||||
//联系电话
|
//联系电话
|
||||||
private String contactPhone;
|
private String contactPhone;
|
||||||
//是否已转入成果库
|
//是否已转入成果库
|
||||||
|
@Excel(name = "转入状态", readConverterExp = "0=未转入,1=已转入")
|
||||||
private Long isTransferredToResultsLibrary;
|
private Long isTransferredToResultsLibrary;
|
||||||
//转入成果库时间
|
//转入成果库时间
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
|
@Excel(name = "转入时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date transferToResultsDate;
|
private Date transferToResultsDate;
|
||||||
//是否精选成果 0否 1是
|
//是否精选成果 0否 1是
|
||||||
private Long isSelectedResult;
|
private Long isSelectedResult;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ public interface CompetitionResourceLibraryMapper {
|
||||||
|
|
||||||
CompetitionResourceLibrary selectCompetitionResourceLibraryById(Long id);
|
CompetitionResourceLibrary selectCompetitionResourceLibraryById(Long id);
|
||||||
|
|
||||||
|
CompetitionResourceLibrary selectCompetitionResourceLibraryByCompetitionName(@Param("competitionName") String competitionName);
|
||||||
|
|
||||||
List<CompetitionResourceLibrary> selectCompetitionResourceLibraryList(CompetitionResourceLibrary competitionResourceLibrary);
|
List<CompetitionResourceLibrary> selectCompetitionResourceLibraryList(CompetitionResourceLibrary competitionResourceLibrary);
|
||||||
|
|
||||||
int insertCompetitionResourceLibrary(CompetitionResourceLibrary competitionResourceLibrary);
|
int insertCompetitionResourceLibrary(CompetitionResourceLibrary competitionResourceLibrary);
|
||||||
|
|
|
||||||
|
|
@ -73,4 +73,6 @@ public interface ProjectResourceLibraryMapper {
|
||||||
String getUserIdBYLogin(@Param("userId")String userId);
|
String getUserIdBYLogin(@Param("userId")String userId);
|
||||||
|
|
||||||
UserProjectTransferRecords selectIssueEndInfo(@Param("issueId") String issueId);
|
UserProjectTransferRecords selectIssueEndInfo(@Param("issueId") String issueId);
|
||||||
|
|
||||||
|
ProjectResourceLibrary selectProjectResourceLibraryByProjectName(@Param("projectName") String projectName);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,4 +110,6 @@ public interface TaskResourceLibraryMapper {
|
||||||
int delWatcher(Watcher watcher);
|
int delWatcher(Watcher watcher);
|
||||||
|
|
||||||
double getConvertedTaskAmount2();
|
double getConvertedTaskAmount2();
|
||||||
|
|
||||||
|
TaskResourceLibrary selectTaskResourceLibraryByTaskName(@Param("taskName") String taskName);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,4 +149,61 @@ public class CompetitionResourceLibraryService {
|
||||||
// 这里替换成你的实际逻辑
|
// 这里替换成你的实际逻辑
|
||||||
return competitionResourceLibraryMapper.getReviewCompetitionCount();
|
return competitionResourceLibraryMapper.getReviewCompetitionCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String batchInsertCompetitionResourceLibrary(List<CompetitionResourceLibrary> list, boolean updateSupport, String operName) {
|
||||||
|
if (list == null || list.isEmpty()) {
|
||||||
|
return "导入数据为空";
|
||||||
|
}
|
||||||
|
int successNum = 0;
|
||||||
|
int failureNum = 0;
|
||||||
|
StringBuilder successMsg = new StringBuilder();
|
||||||
|
StringBuilder failureMsg = new StringBuilder();
|
||||||
|
|
||||||
|
for (CompetitionResourceLibrary competitionResourceLibrary : list) {
|
||||||
|
try {
|
||||||
|
String competitionName = competitionResourceLibrary.getOpenCompetitionName();
|
||||||
|
if (competitionName == null || competitionName.trim().isEmpty()) {
|
||||||
|
failureNum++;
|
||||||
|
failureMsg.append("<br/>").append(failureNum).append("、竞赛名称为空,导入失败");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompetitionResourceLibrary existCompetition = competitionResourceLibraryMapper.selectCompetitionResourceLibraryByCompetitionName(competitionName);
|
||||||
|
|
||||||
|
if (existCompetition == null) {
|
||||||
|
// 不存在,插入
|
||||||
|
competitionResourceLibrary.setCreateBy(operName);
|
||||||
|
competitionResourceLibrary.setCreateTime(DateUtils.getNowDate());
|
||||||
|
competitionResourceLibraryMapper.insertCompetitionResourceLibrary(competitionResourceLibrary);
|
||||||
|
successNum++;
|
||||||
|
successMsg.append("<br/>").append(successNum).append("、竞赛 ").append(competitionName).append(" 导入成功");
|
||||||
|
} else if (updateSupport) {
|
||||||
|
// 存在且支持更新
|
||||||
|
competitionResourceLibrary.setId(existCompetition.getId());
|
||||||
|
competitionResourceLibrary.setUpdateBy(operName);
|
||||||
|
competitionResourceLibrary.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
competitionResourceLibraryMapper.updateCompetitionResourceLibrary(competitionResourceLibrary);
|
||||||
|
successNum++;
|
||||||
|
successMsg.append("<br/>").append(successNum).append("、竞赛 ").append(competitionName).append(" 更新成功");
|
||||||
|
} else {
|
||||||
|
failureNum++;
|
||||||
|
failureMsg.append("<br/>").append(failureNum).append("、竞赛 ").append(competitionName).append(" 已存在");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
failureNum++;
|
||||||
|
String msg = "<br/>" + failureNum + "、竞赛 " + competitionResourceLibrary.getOpenCompetitionName() + " 导入失败";
|
||||||
|
failureMsg.append(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failureNum > 0) {
|
||||||
|
failureMsg.insert(0, "导入完成,共 " + failureNum + " 条数据格式不正确:");
|
||||||
|
if (successNum > 0) {
|
||||||
|
failureMsg.append("<br/>成功导入 ").append(successNum).append(" 条数据");
|
||||||
|
}
|
||||||
|
return failureMsg.toString();
|
||||||
|
}
|
||||||
|
successMsg.insert(0, "导入成功,共 " + successNum + " 条数据:");
|
||||||
|
return successMsg.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,4 +140,62 @@ public class ProjectResourceLibraryService {
|
||||||
public long getTotalConversionCount() {
|
public long getTotalConversionCount() {
|
||||||
return projectResourceLibraryMapper.getTotalConversionCount();
|
return projectResourceLibraryMapper.getTotalConversionCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入项目资源库数据
|
||||||
|
*/
|
||||||
|
public String batchInsertProjectResourceLibrary(List<ProjectResourceLibrary> list, boolean updateSupport, String operName) {
|
||||||
|
if (list == null || list.isEmpty()) {
|
||||||
|
throw new RuntimeException("导入项目资源数据不能为空!");
|
||||||
|
}
|
||||||
|
int successNum = 0;
|
||||||
|
int failureNum = 0;
|
||||||
|
StringBuilder successMsg = new StringBuilder();
|
||||||
|
StringBuilder failureMsg = new StringBuilder();
|
||||||
|
|
||||||
|
for (ProjectResourceLibrary projectResourceLibrary : list) {
|
||||||
|
try {
|
||||||
|
// 查重:根据项目名称查询
|
||||||
|
ProjectResourceLibrary exist = projectResourceLibraryMapper.selectProjectResourceLibraryByProjectName(projectResourceLibrary.getProjectName());
|
||||||
|
if (exist == null) {
|
||||||
|
projectResourceLibrary.setCreateBy(operName);
|
||||||
|
projectResourceLibrary.setCreateTime(new Date());
|
||||||
|
projectResourceLibrary.setUpdateBy(operName);
|
||||||
|
projectResourceLibrary.setUpdateTime(new Date());
|
||||||
|
projectResourceLibraryMapper.insertProjectResourceLibrary(projectResourceLibrary);
|
||||||
|
successNum++;
|
||||||
|
successMsg.append("<br/>").append(successNum).append("、项目 ").append(projectResourceLibrary.getProjectName()).append(" 导入成功");
|
||||||
|
} else {
|
||||||
|
if (updateSupport) {
|
||||||
|
projectResourceLibrary.setId(exist.getId());
|
||||||
|
projectResourceLibrary.setCreateBy(exist.getCreateBy());
|
||||||
|
projectResourceLibrary.setCreateTime(exist.getCreateTime());
|
||||||
|
projectResourceLibrary.setUpdateBy(operName);
|
||||||
|
projectResourceLibrary.setUpdateTime(new Date());
|
||||||
|
projectResourceLibraryMapper.updateProjectResourceLibrary(projectResourceLibrary);
|
||||||
|
successNum++;
|
||||||
|
successMsg.append("<br/>").append(successNum).append("、项目 ").append(projectResourceLibrary.getProjectName()).append(" 更新成功");
|
||||||
|
} else {
|
||||||
|
failureNum++;
|
||||||
|
failureMsg.append("<br/>").append(failureNum).append("、项目 ").append(projectResourceLibrary.getProjectName()).append(" 已存在(未开启更新)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
failureNum++;
|
||||||
|
String msg = "<br/>" + failureNum + "、项目 " + projectResourceLibrary.getProjectName() + " 导入失败:";
|
||||||
|
failureMsg.append(msg).append(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组装最终提示信息
|
||||||
|
StringBuilder finalMsg = new StringBuilder();
|
||||||
|
if (successNum > 0) {
|
||||||
|
finalMsg.append("共 ").append(successNum).append(" 条数据导入/更新成功:").append(successMsg);
|
||||||
|
}
|
||||||
|
if (failureNum > 0) {
|
||||||
|
finalMsg.append("<br/>共 ").append(failureNum).append(" 条数据导入失败:").append(failureMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalMsg.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static com.microservices.dms.constant.TaskConstant.MARKER_SPACE_DOWNLOAD_API_BY_ID;
|
import static com.microservices.dms.constant.TaskConstant.MARKER_SPACE_DOWNLOAD_API_BY_ID;
|
||||||
|
|
||||||
|
|
@ -209,4 +211,61 @@ public class TaskResourceLibraryService {
|
||||||
public int delWatcher(Watcher watcher) {
|
public int delWatcher(Watcher watcher) {
|
||||||
return taskResourceLibraryMapper.delWatcher(watcher);
|
return taskResourceLibraryMapper.delWatcher(watcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String batchInsertTaskResourceLibrary(List<TaskResourceLibrary> list, boolean updateSupport, String operName) {
|
||||||
|
if (list == null || list.isEmpty()) {
|
||||||
|
return "导入数据为空";
|
||||||
|
}
|
||||||
|
int successNum = 0;
|
||||||
|
int failureNum = 0;
|
||||||
|
StringBuilder successMsg = new StringBuilder();
|
||||||
|
StringBuilder failureMsg = new StringBuilder();
|
||||||
|
|
||||||
|
for (TaskResourceLibrary taskResourceLibrary : list) {
|
||||||
|
try {
|
||||||
|
String taskName = taskResourceLibrary.getTaskName();
|
||||||
|
if (taskName == null || taskName.trim().isEmpty()) {
|
||||||
|
failureNum++;
|
||||||
|
failureMsg.append("<br/>").append(failureNum).append("、任务名称为空,导入失败");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskResourceLibrary existTask = taskResourceLibraryMapper.selectTaskResourceLibraryByTaskName(taskName);
|
||||||
|
|
||||||
|
if (existTask == null) {
|
||||||
|
// 不存在,插入
|
||||||
|
taskResourceLibrary.setCreateBy(operName);
|
||||||
|
taskResourceLibrary.setCreateTime(DateUtils.getNowDate());
|
||||||
|
taskResourceLibraryMapper.insertTaskResourceLibrary(taskResourceLibrary);
|
||||||
|
successNum++;
|
||||||
|
successMsg.append("<br/>").append(successNum).append("、任务 ").append(taskName).append(" 导入成功");
|
||||||
|
} else if (updateSupport) {
|
||||||
|
// 存在且支持更新
|
||||||
|
taskResourceLibrary.setId(existTask.getId());
|
||||||
|
taskResourceLibrary.setUpdateBy(operName);
|
||||||
|
taskResourceLibrary.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
taskResourceLibraryMapper.updateTaskResourceLibrary(taskResourceLibrary);
|
||||||
|
successNum++;
|
||||||
|
successMsg.append("<br/>").append(successNum).append("、任务 ").append(taskName).append(" 更新成功");
|
||||||
|
} else {
|
||||||
|
failureNum++;
|
||||||
|
failureMsg.append("<br/>").append(failureNum).append("、任务 ").append(taskName).append(" 已存在");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
failureNum++;
|
||||||
|
String msg = "<br/>" + failureNum + "、任务 " + taskResourceLibrary.getTaskName() + " 导入失败";
|
||||||
|
failureMsg.append(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failureNum > 0) {
|
||||||
|
failureMsg.insert(0, "导入完成,共 " + failureNum + " 条数据格式不正确:");
|
||||||
|
if (successNum > 0) {
|
||||||
|
failureMsg.append("<br/>成功导入 ").append(successNum).append(" 条数据");
|
||||||
|
}
|
||||||
|
return failureMsg.toString();
|
||||||
|
}
|
||||||
|
successMsg.insert(0, "导入成功,共 " + successNum + " 条数据:");
|
||||||
|
return successMsg.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
package com.microservices.dms.utils;
|
||||||
|
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义MultipartFile实现(通用版,无外部依赖)
|
||||||
|
*/
|
||||||
|
public class CustomMultipartFile implements MultipartFile {
|
||||||
|
private final byte[] content;
|
||||||
|
private final String filename;
|
||||||
|
private final String contentType;
|
||||||
|
|
||||||
|
public CustomMultipartFile(byte[] content, String filename, String contentType) {
|
||||||
|
this.content = content;
|
||||||
|
this.filename = filename;
|
||||||
|
this.contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "file";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOriginalFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return content == null || content.length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getSize() {
|
||||||
|
return content.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBytes() throws IOException {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
return new ByteArrayInputStream(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void transferTo(java.io.File dest) throws IOException, IllegalStateException {
|
||||||
|
try (java.io.OutputStream os = new java.io.FileOutputStream(dest)) {
|
||||||
|
os.write(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
package com.microservices.dms.utils;
|
||||||
|
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
public class FileMultipartFile implements MultipartFile {
|
||||||
|
|
||||||
|
private final File file;
|
||||||
|
// private final String name;
|
||||||
|
private final String originalFilename;
|
||||||
|
private final String contentType;
|
||||||
|
private byte[] content; // 延迟加载缓存
|
||||||
|
|
||||||
|
public FileMultipartFile(File file, String originalFilename, String contentType) {
|
||||||
|
this.file = file;
|
||||||
|
this.originalFilename = originalFilename;
|
||||||
|
this.contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 简化构造方法(自动推断文件名和ContentType)
|
||||||
|
public FileMultipartFile(File file) {
|
||||||
|
this.file = file;
|
||||||
|
this.originalFilename = file.getName();
|
||||||
|
this.contentType = guessContentType(file.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "file";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOriginalFilename() {
|
||||||
|
return originalFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return file.length() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getSize() {
|
||||||
|
return file.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getBytes() throws IOException {
|
||||||
|
if (content == null) {
|
||||||
|
content = Files.readAllBytes(file.toPath());
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
return new FileInputStream(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void transferTo(File dest) throws IOException, IllegalStateException {
|
||||||
|
try (InputStream is = new FileInputStream(file);
|
||||||
|
OutputStream os = new FileOutputStream(dest)) {
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int length;
|
||||||
|
while ((length = is.read(buffer)) > 0) {
|
||||||
|
os.write(buffer, 0, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助方法:根据文件扩展名猜测ContentType
|
||||||
|
private static String guessContentType(String fileName) {
|
||||||
|
if (fileName == null) return "application/octet-stream";
|
||||||
|
|
||||||
|
String lowerName = fileName.toLowerCase();
|
||||||
|
if (lowerName.endsWith(".mp4")) return "video/mp4";
|
||||||
|
if (lowerName.endsWith(".jpg") || lowerName.endsWith(".jpeg")) return "image/jpeg";
|
||||||
|
if (lowerName.endsWith(".png")) return "image/png";
|
||||||
|
if (lowerName.endsWith(".gif")) return "image/gif";
|
||||||
|
if (lowerName.endsWith(".pdf")) return "application/pdf";
|
||||||
|
if (lowerName.endsWith(".zip")) return "application/zip";
|
||||||
|
if (lowerName.endsWith(".xlsx")) return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||||
|
if (lowerName.endsWith(".xls")) return "application/vnd.ms-excel";
|
||||||
|
|
||||||
|
return "application/octet-stream";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Tomcat
|
# Tomcat
|
||||||
server:
|
server:
|
||||||
port: 9119
|
port: 8080
|
||||||
|
|
||||||
# Spring
|
# Spring
|
||||||
spring:
|
spring:
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
where a.id = #{id}
|
where a.id = #{id}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAchievementsByAchievementName" parameterType="String" resultType="com.microservices.dms.achievementLibrary.domain.Achievements">
|
||||||
|
select a.id,IFNULL(a.show_ach_name,a.achievement_name) as "showAchievementName",a.achievement_name,a.hot_rank,a.field_1,a.field_2,a.field_3,a.attachment_count,
|
||||||
|
a.is_expert_audit,a.achievement_type,a.source,a.source_id,a.ext1,a.ext2,a.ext3
|
||||||
|
,u.login as "userLogin",IFNULL(u.nickname,owner_name) as "userNickName",ue.gender as "gender",
|
||||||
|
a.source_link,a.tags,a.summary,a.publishing_unit,a.address,a.is_featured,a.contact_person,a.contact_number,a.owner_id,a.owner_name, a.status,a.details,
|
||||||
|
a.reviewer,a.review_date,a.review_comments, a.images,a.attachments,a.create_by,a.create_time,a.update_by,a.update_time
|
||||||
|
from achievements a
|
||||||
|
left join users u on a.owner_name = u.login
|
||||||
|
left join user_extensions ue on u.id = ue.user_id
|
||||||
|
where a.achievement_name = #{achievementName}
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="getFileInfoByIdents" resultType="java.util.Map">
|
<select id="getFileInfoByIdents" resultType="java.util.Map">
|
||||||
select file_identifier as k ,file_origin_name as v from sys_file_info
|
select file_identifier as k ,file_origin_name as v from sys_file_info
|
||||||
where file_identifier in
|
where file_identifier in
|
||||||
|
|
@ -307,7 +319,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
</where>
|
</where>
|
||||||
order by create_time desc
|
order by create_time desc
|
||||||
</if>
|
</if>
|
||||||
<if test='source=="2" or source=="3" or source=="4" '>
|
<if test='source=="2" or source=="3" or source=="4" or source=="5" '>
|
||||||
select a.id, IFNULL(a.show_ach_name,a.achievement_name) as "showAchievementName", a.achievement_name, a.summary, a.create_time, a.owner_name, a.tags, a.field_1, a.field_2, a.field_3, a.source, a.source_id,
|
select a.id, IFNULL(a.show_ach_name,a.achievement_name) as "showAchievementName", a.achievement_name, a.summary, a.create_time, a.owner_name, a.tags, a.field_1, a.field_2, a.field_3, a.source, a.source_id,
|
||||||
c.name as "field1Name",u.login as "userLogin",
|
c.name as "field1Name",u.login as "userLogin",
|
||||||
IFNULL(u.nickname,a.owner_name) as "userNickName",
|
IFNULL(u.nickname,a.owner_name) as "userNickName",
|
||||||
|
|
@ -326,6 +338,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<if test='areaQuery != null and areaQuery != "" '>
|
<if test='areaQuery != null and areaQuery != "" '>
|
||||||
and (a.field_1 = #{areaQuery} or a.field_2 = #{areaQuery} or a.field_3 = #{areaQuery})
|
and (a.field_1 = #{areaQuery} or a.field_2 = #{areaQuery} or a.field_3 = #{areaQuery})
|
||||||
</if>
|
</if>
|
||||||
|
<if test="rongbanName != null and rongbanName != ''"> and a.field_2 = #{rongbanName}</if>
|
||||||
</where>
|
</where>
|
||||||
order by a.create_time desc
|
order by a.create_time desc
|
||||||
</if>
|
</if>
|
||||||
|
|
@ -904,6 +917,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
GROUP BY r.name
|
GROUP BY r.name
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="getAllField2" resultType="com.microservices.dms.achievementLibrary.domain.KeyValueVo">
|
||||||
|
select distinct r.field_2 as "name", r.field_2 as "result" from achievements r where source="5"
|
||||||
|
</select>
|
||||||
|
|
||||||
<update id="updateRelationAchievements">
|
<update id="updateRelationAchievements">
|
||||||
<if test='source != null and source == "1"'>
|
<if test='source != null and source == "1"'>
|
||||||
update project_resource_library set is_transferred_to_achievement='0' ,transfer_date=null where id = #{sourceId}
|
update project_resource_library set is_transferred_to_achievement='0' ,transfer_date=null where id = #{sourceId}
|
||||||
|
|
@ -927,4 +944,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
left join personalities p on e.id = p.entity_id
|
left join personalities p on e.id = p.entity_id
|
||||||
where click_type='userDocking' and click_id = #{id}
|
where click_type='userDocking' and click_id = #{id}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
<select id="getSource5Statistic" parameterType="String" resultType="com.microservices.dms.achievementLibrary.domain.AchievementSourceStatisticVo">
|
||||||
|
SELECT
|
||||||
|
count( DISTINCT clickers.id ) AS clickSum,
|
||||||
|
count( DISTINCT achievements.id ) AS achievementSum
|
||||||
|
FROM
|
||||||
|
achievements LEFT JOIN clickers ON clickers.click_type = 'Achievements' AND click_id = achievements.id
|
||||||
|
WHERE
|
||||||
|
achievements.source = '5' and achievements.field_2 = #{name}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="getSource5Field2" parameterType="String" resultType="com.microservices.dms.achievementLibrary.domain.AchievementSourceStatisticVo">
|
||||||
|
SELECT field_2 as rongbanName, field_3 as rongbanDesc FROM achievements WHERE achievements.source = '5' and achievements.field_2 = #{name} order by id desc limit 1
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
@ -198,6 +198,11 @@
|
||||||
where id = #{id}
|
where id = #{id}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectCompetitionResourceLibraryByCompetitionName" parameterType="String" resultMap="CompetitionResourceLibraryResult">
|
||||||
|
<include refid="selectCompetitionResourceLibraryVo"/>
|
||||||
|
where open_competition_name = #{competitionName}
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="getAttachments" resultType="com.microservices.dms.resourceLibrary.domain.vo.KeyValVo">
|
<select id="getAttachments" resultType="com.microservices.dms.resourceLibrary.domain.vo.KeyValVo">
|
||||||
select uuid as v, filename as k
|
select uuid as v, filename as k
|
||||||
from attachments
|
from attachments
|
||||||
|
|
|
||||||
|
|
@ -473,7 +473,7 @@
|
||||||
from (
|
from (
|
||||||
(select count(1) as "auditSum"
|
(select count(1) as "auditSum"
|
||||||
from memos
|
from memos
|
||||||
where destroy_status is null and hidden = 0 and published_at is not null) a,
|
where destroy_status is null and hidden = 0 and published_at is not null AND root_id IS NULL) a,
|
||||||
(select count(1) as "allSum" from memos) b,
|
(select count(1) as "allSum" from memos) b,
|
||||||
(select count(1) as "currentYearSum"
|
(select count(1) as "currentYearSum"
|
||||||
from memos
|
from memos
|
||||||
|
|
|
||||||
|
|
@ -469,4 +469,44 @@
|
||||||
inner join projects p on i.project_id = p.id
|
inner join projects p on i.project_id = p.id
|
||||||
where issue_id = #{issueId} and status_id in ('1','2') and i.blockchain_token_num >0
|
where issue_id = #{issueId} and status_id in ('1','2') and i.blockchain_token_num >0
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectProjectResourceLibraryByProjectName" parameterType="String"
|
||||||
|
resultType="com.microservices.dms.resourceLibrary.domain.ProjectResourceLibrary">
|
||||||
|
select pl.id,
|
||||||
|
p.name as project_name,
|
||||||
|
p.identifier,
|
||||||
|
p.id as project_id,
|
||||||
|
r.id as repository_id,
|
||||||
|
v.id as version_releases_id,
|
||||||
|
p.is_public as is_public,
|
||||||
|
v.name as release_name,
|
||||||
|
v.updated_at as release_date,
|
||||||
|
(select login from users where id=v.user_id) as release_person,
|
||||||
|
(select login from users where id=v.user_id) as user_identifier,
|
||||||
|
IFNULL(pl.project_domain,p.project_category_id) as project_domain,
|
||||||
|
pl.release_type,
|
||||||
|
pl.release_unit,
|
||||||
|
v.body,
|
||||||
|
IFNULL( pl.release_summary,v.body) as release_summary,
|
||||||
|
IFNULL( pl.release_details,v.body) as release_details,
|
||||||
|
p.description as release_summary,
|
||||||
|
p.description as release_details,
|
||||||
|
pl.contact_person,
|
||||||
|
pl.contact_phone,
|
||||||
|
pl.is_transferred_to_achievement,
|
||||||
|
pl.transfer_date,
|
||||||
|
pl.is_selected_achievement,
|
||||||
|
pl.images,
|
||||||
|
v.zipball_url as attachments,
|
||||||
|
pl.create_by,
|
||||||
|
pl.create_time,
|
||||||
|
pl.update_by,
|
||||||
|
pl.update_time
|
||||||
|
from projects p
|
||||||
|
join repositories r on p.id = r.project_id
|
||||||
|
join version_releases v on r.id = v.repository_id
|
||||||
|
left join project_resource_library pl on v.id = pl.version_releases_id
|
||||||
|
where p.name = #{projectName}
|
||||||
|
limit 1
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
|
||||||
|
|
@ -513,6 +513,11 @@
|
||||||
where id = #{id}
|
where id = #{id}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectTaskResourceLibraryByTaskName" parameterType="String" resultMap="TaskResourceLibraryResult">
|
||||||
|
<include refid="selectTaskResourceLibraryVo"/>
|
||||||
|
where task_name = #{taskName}
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="getAttachments" resultType="com.microservices.dms.resourceLibrary.domain.vo.KeyValVo">
|
<select id="getAttachments" resultType="com.microservices.dms.resourceLibrary.domain.vo.KeyValVo">
|
||||||
select b.file_name as k, b.id as v
|
select b.file_name as k, b.id as v
|
||||||
from paper_details pd
|
from paper_details pd
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Tomcat
|
# Tomcat
|
||||||
server:
|
server:
|
||||||
port: 9198
|
port: 8080
|
||||||
|
|
||||||
# Spring
|
# Spring
|
||||||
spring:
|
spring:
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
select count(*)
|
select count(*)
|
||||||
from tasks
|
from tasks
|
||||||
where is_delete = 0 and `status` between 3 and 8
|
where is_delete = 0 and `status` between 3 and 8
|
||||||
|
and (`name` IS NULL OR NAME NOT REGEXP '[二三四五六七八九2-9]次[))]')
|
||||||
</select>
|
</select>
|
||||||
<select id="getTotalApplicantCount" resultType="java.lang.Integer">
|
<select id="getTotalApplicantCount" resultType="java.lang.Integer">
|
||||||
select count(*)
|
select count(*)
|
||||||
|
|
@ -57,6 +58,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
select COALESCE(SUM(bounty), 0)
|
select COALESCE(SUM(bounty), 0)
|
||||||
from tasks
|
from tasks
|
||||||
where is_delete = 0 and `status` between 3 and 8
|
where is_delete = 0 and `status` between 3 and 8
|
||||||
|
and (`name` IS NULL OR NAME NOT REGEXP '[二三四五六七八九2-9]次[))]')
|
||||||
</select>
|
</select>
|
||||||
<select id="getTaskPublishedCountsByYear" resultType="map">
|
<select id="getTaskPublishedCountsByYear" resultType="map">
|
||||||
SELECT
|
SELECT
|
||||||
|
|
@ -67,6 +69,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
WHERE
|
WHERE
|
||||||
is_delete = 0
|
is_delete = 0
|
||||||
AND STATUS BETWEEN 3 AND 8
|
AND STATUS BETWEEN 3 AND 8
|
||||||
|
and (`name` IS NULL OR NAME NOT REGEXP '[二三四五六七八九2-9]次[))]')
|
||||||
AND YEAR(created_at) IN (YEAR(CURDATE()) - 2, YEAR(CURDATE()),YEAR(CURDATE()) - 1, YEAR(CURDATE()))
|
AND YEAR(created_at) IN (YEAR(CURDATE()) - 2, YEAR(CURDATE()),YEAR(CURDATE()) - 1, YEAR(CURDATE()))
|
||||||
GROUP BY
|
GROUP BY
|
||||||
YEAR(created_at)
|
YEAR(created_at)
|
||||||
|
|
@ -82,6 +85,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
WHERE
|
WHERE
|
||||||
is_delete = 0
|
is_delete = 0
|
||||||
AND STATUS BETWEEN 3 AND 8
|
AND STATUS BETWEEN 3 AND 8
|
||||||
|
and (`name` IS NULL OR NAME NOT REGEXP '[二三四五六七八九2-9]次[))]')
|
||||||
AND YEAR(created_at) IN (YEAR(CURDATE()) - 2, YEAR(CURDATE()),YEAR(CURDATE()) - 1, YEAR(CURDATE()))
|
AND YEAR(created_at) IN (YEAR(CURDATE()) - 2, YEAR(CURDATE()),YEAR(CURDATE()) - 1, YEAR(CURDATE()))
|
||||||
GROUP BY
|
GROUP BY
|
||||||
YEAR(created_at)
|
YEAR(created_at)
|
||||||
|
|
@ -210,7 +214,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<select id="getPaidAwardAmount" resultType="java.lang.Float">
|
<select id="getPaidAwardAmount" resultType="java.lang.Float">
|
||||||
SELECT COALESCE(SUM(bounty), 0) AS total_bounty
|
SELECT COALESCE(SUM(bounty), 0) AS total_bounty
|
||||||
FROM tasks
|
FROM tasks
|
||||||
WHERE is_delete = 0 AND `status` = 8;
|
WHERE is_delete = 0 AND `status` = 8
|
||||||
|
and (`name` IS NULL OR NAME NOT REGEXP '[二三四五六七八九2-9]次[))]')
|
||||||
</select>
|
</select>
|
||||||
<select id="getTotalVisits" resultType="java.lang.Integer">
|
<select id="getTotalVisits" resultType="java.lang.Integer">
|
||||||
SELECT COALESCE(SUM(visits), 0) AS total_visits
|
SELECT COALESCE(SUM(visits), 0) AS total_visits
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,26 @@
|
||||||
package com.microservices.file.controller;
|
package com.microservices.file.controller;
|
||||||
|
|
||||||
import com.microservices.common.core.domain.R;
|
import com.microservices.common.core.domain.R;
|
||||||
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
import com.microservices.common.core.web.controller.BaseController;
|
import com.microservices.common.core.web.controller.BaseController;
|
||||||
import com.microservices.common.security.annotation.InnerAuth;
|
import com.microservices.common.security.annotation.InnerAuth;
|
||||||
import com.microservices.file.service.ISysFileInfoService;
|
import com.microservices.file.service.ISysFileInfoService;
|
||||||
import com.microservices.system.api.domain.SysFile;
|
import com.microservices.system.api.domain.SysFile;
|
||||||
import com.microservices.system.api.domain.SysFileInfo;
|
import com.microservices.system.api.domain.SysFileInfo;
|
||||||
|
import com.microservices.system.api.utils.StandardMultipartFile;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import springfox.documentation.annotations.ApiIgnore;
|
import springfox.documentation.annotations.ApiIgnore;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件请求处理
|
* 文件请求处理
|
||||||
*
|
*
|
||||||
|
|
@ -49,4 +55,56 @@ public class SysFileController extends BaseController {
|
||||||
return R.fail(e.getMessage());
|
return R.fail(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@InnerAuth
|
||||||
|
@PostMapping("/upload/base64")
|
||||||
|
public R<SysFileInfo> uploadBase64(@RequestBody Map<String, Object> params,
|
||||||
|
@RequestParam("type") String type,
|
||||||
|
@RequestParam("hierarchy") String hierarchy) {
|
||||||
|
try {
|
||||||
|
// 1. 提取参数
|
||||||
|
String base64Data = (String) params.get("base64Data");
|
||||||
|
String fileName = (String) params.get("fileName");
|
||||||
|
String contentType = (String) params.get("contentType");
|
||||||
|
|
||||||
|
// 2. 参数校验
|
||||||
|
if (StringUtils.isEmpty(base64Data)) {
|
||||||
|
return R.fail("base64Data不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Base64解码
|
||||||
|
byte[] fileBytes;
|
||||||
|
try {
|
||||||
|
fileBytes = Base64.getDecoder().decode(base64Data);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
log.error("Base64解码失败", e);
|
||||||
|
return R.fail("图片数据格式错误");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileBytes.length == 0) {
|
||||||
|
return R.fail("解码后文件为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 构造MultipartFile
|
||||||
|
String originalFilename = StringUtils.isEmpty(fileName)
|
||||||
|
? "base64_image_" + System.currentTimeMillis() + ".png"
|
||||||
|
: fileName;
|
||||||
|
|
||||||
|
MultipartFile multipartFile = new StandardMultipartFile(
|
||||||
|
fileBytes,
|
||||||
|
"file", // 字段名,与原接口一致
|
||||||
|
originalFilename,
|
||||||
|
contentType
|
||||||
|
);
|
||||||
|
|
||||||
|
// 5. 复用原有上传逻辑
|
||||||
|
SysFileInfo fileInfo = sysFileInfoService.upload(multipartFile, type, hierarchy);
|
||||||
|
|
||||||
|
return R.ok(fileInfo);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Base64上传文件失败", e);
|
||||||
|
return R.fail(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Tomcat
|
# Tomcat
|
||||||
server:
|
server:
|
||||||
port: 9111
|
port: 8080
|
||||||
|
|
||||||
# Spring
|
# Spring
|
||||||
spring:
|
spring:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Tomcat
|
# Tomcat
|
||||||
server:
|
server:
|
||||||
port: 9113
|
port: 8080
|
||||||
|
|
||||||
# Spring
|
# Spring
|
||||||
spring:
|
spring:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-modules</artifactId>
|
||||||
|
<version>3.6.2</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>microservices-modules-mon</artifactId>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
microservices-modules-mon运维监控模块
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- SpringCloud Alibaba Nacos -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- SpringCloud Alibaba Nacos Config -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- SpringCloud Alibaba Sentinel -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- SpringBoot Actuator -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Swagger UI -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.springfox</groupId>
|
||||||
|
<artifactId>springfox-swagger-ui</artifactId>
|
||||||
|
<version>${swagger.fox.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Mysql Connector -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Microservices Common Async -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-async</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Microservices Common DataSource -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-datasource</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Microservices Common DataScope -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-datascope</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Microservices Common Log -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-log</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Microservices Common Swagger -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-swagger</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microservices</groupId>
|
||||||
|
<artifactId>microservices-common-httpClient</artifactId>
|
||||||
|
<version>3.6.2</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>${project.artifactId}</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>repackage</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.microservices.mon;
|
||||||
|
|
||||||
|
import com.microservices.common.security.annotation.EnableCustomConfig;
|
||||||
|
import com.microservices.common.security.annotation.EnableRyFeignClients;
|
||||||
|
import com.microservices.common.swagger.annotation.EnableCustomSwagger2;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运维监控模块
|
||||||
|
*
|
||||||
|
* @author otto
|
||||||
|
*/
|
||||||
|
@EnableCustomConfig
|
||||||
|
@EnableCustomSwagger2
|
||||||
|
@EnableRyFeignClients
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableScheduling
|
||||||
|
public class MicroservicesMonApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(MicroservicesMonApplication.class, args);
|
||||||
|
System.out.println("(♥◠‿◠)ノ゙ 运维监控模块启动成功 ლ(´ڡ`ლ)゙ \n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
package com.microservices.mon.k8s.controller;
|
||||||
|
|
||||||
|
import com.microservices.common.core.web.controller.BaseController;
|
||||||
|
import com.microservices.common.core.web.domain.AjaxResult;
|
||||||
|
import com.microservices.common.core.web.domain.GenericsAjaxResult;
|
||||||
|
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||||
|
import com.microservices.mon.k8s.domain.*;
|
||||||
|
import com.microservices.mon.k8s.service.IK8sDashboardService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("dashboard")
|
||||||
|
@Api(tags = "微服务大屏")
|
||||||
|
@RefreshScope
|
||||||
|
public class DashboardController extends BaseController {
|
||||||
|
@Autowired
|
||||||
|
private IK8sDashboardService k8sDashboardService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取命名空间列表
|
||||||
|
*/
|
||||||
|
@ApiOperation(value = "获取命名空间列表")
|
||||||
|
@GetMapping("/namespace/list")
|
||||||
|
public GenericsTableDataInfo<K8sNamespace> namespaceList(@RequestParam(value = "search", required = false) @ApiParam(value = "根据应用名称查找") String search) {
|
||||||
|
return new GenericsTableDataInfo<>(k8sDashboardService.getNamespaceDetailList(true,search));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取集群节点列表")
|
||||||
|
@GetMapping("/cluster/Nodelist")
|
||||||
|
public GenericsTableDataInfo<K8sClusterNode> clusterNodeList() {
|
||||||
|
return new GenericsTableDataInfo<>(k8sDashboardService.getClusterNodeList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取应用容器Ip列表")
|
||||||
|
@GetMapping("/application/{kind}/{namespace}/{applicationName}/podIdList")
|
||||||
|
public GenericsTableDataInfo<String> applicationPodIdList(@PathVariable("kind") String kind, @PathVariable("namespace") String namespace, @PathVariable("applicationName") String applicationName) {
|
||||||
|
return new GenericsTableDataInfo<>(k8sDashboardService.getApplicationPodIdList(kind, namespace, applicationName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取集群状态数据")
|
||||||
|
@GetMapping("/cluster/status")
|
||||||
|
public GenericsAjaxResult<K8sClusterStatus> clusterStatus() {
|
||||||
|
return GenericsAjaxResult.success(k8sDashboardService.getClusterStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "集群每秒请求率(QPS)")
|
||||||
|
@GetMapping("/cluster/qps")
|
||||||
|
public GenericsTableDataInfo<MetricCommonData> clusterQps() {
|
||||||
|
return new GenericsTableDataInfo<>(k8sDashboardService.getClusterQps());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "最近24小时应用接口请求次数")
|
||||||
|
@GetMapping("/cluster/applicationRequestCount")
|
||||||
|
public GenericsTableDataInfo<ApplicationRequestCountData> applicationRequestCount() {
|
||||||
|
return new GenericsTableDataInfo<>(k8sDashboardService.getApplicationRequestCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取Pod容器状态")
|
||||||
|
@GetMapping("/cluster/podContainerStatus/{podName}")
|
||||||
|
public GenericsAjaxResult<K8sPodContainerStatus> podContainerStatus(@PathVariable("podName") String podName) {
|
||||||
|
return GenericsAjaxResult.success(k8sDashboardService.getPodContainerStatus(podName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取服务器节点状态")
|
||||||
|
@GetMapping("/cluster/nodeStatus/{nodeIp}")
|
||||||
|
public GenericsAjaxResult<K8sNodeStatus> nodeStatus(@PathVariable("nodeIp") String nodeIp) {
|
||||||
|
return GenericsAjaxResult.success(k8sDashboardService.getNodeStatus(nodeIp));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取微服务应用功能列表")
|
||||||
|
@GetMapping("/applicationFunction/{kind}/{namespace}/{applicationName}")
|
||||||
|
public GenericsTableDataInfo<ApplicationFunction> applicationFunction(@PathVariable("kind") String kind,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName,
|
||||||
|
@RequestParam("podIpList") @ApiParam(value = "Pod Ip列表(使用逗号分割的ip列表字符串)") String podIpList) {
|
||||||
|
return new GenericsTableDataInfo<>(k8sDashboardService.getApplicationFunction(kind, namespace, applicationName, podIpList));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,247 @@
|
||||||
|
package com.microservices.mon.k8s.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.utils.PageUtils;
|
||||||
|
import com.microservices.common.core.web.controller.BaseController;
|
||||||
|
import com.microservices.common.core.web.domain.AjaxResult;
|
||||||
|
import com.microservices.common.core.web.domain.GenericsAjaxResult;
|
||||||
|
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||||
|
import com.microservices.mon.k8s.domain.*;
|
||||||
|
import com.microservices.mon.k8s.domain.vo.ApplicationEnvTypeVo;
|
||||||
|
import com.microservices.mon.k8s.domain.vo.ApplicationTypeVo;
|
||||||
|
import com.microservices.mon.k8s.domain.vo.CommonTypeVo;
|
||||||
|
import com.microservices.mon.k8s.service.IMicroManagementService;
|
||||||
|
import io.swagger.annotations.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("micro")
|
||||||
|
@Api(tags = "微服务管理")
|
||||||
|
@RefreshScope
|
||||||
|
public class MicroManagementController extends BaseController {
|
||||||
|
@Autowired
|
||||||
|
private IMicroManagementService microManagementService;
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取可视化面板容器列表")
|
||||||
|
@GetMapping("/pod/list")
|
||||||
|
public GenericsTableDataInfo<K8sApplicationPod> podList() {
|
||||||
|
return new GenericsTableDataInfo<>(microManagementService.getPodList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取微服务运行状态监控数据")
|
||||||
|
@GetMapping("/pod/status/{podName}")
|
||||||
|
public GenericsAjaxResult<K8sPodContainerMetricOverview> podStatus(@PathVariable("podName") String podName,
|
||||||
|
@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||||
|
return GenericsAjaxResult.success(microManagementService.getPodStatus(podName, step));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取微服务应用详情")
|
||||||
|
@GetMapping("/application/{kind}/{namespace}/{applicationName}/detail")
|
||||||
|
public GenericsAjaxResult<K8sApplication> applicationDetail(@PathVariable("kind") String kind,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName) {
|
||||||
|
return GenericsAjaxResult.success(microManagementService.getApplicationDetail(kind, namespace, applicationName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "删除POD容器")
|
||||||
|
@DeleteMapping("/pod/{namespace}/{podName}")
|
||||||
|
public AjaxResult applicationDetail(@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("podName") String podName,
|
||||||
|
@RequestParam(value = "isForce", required = false) @ApiParam(value = "是否强制删除") Boolean isForce) {
|
||||||
|
return toAjax(microManagementService.deletePod(namespace, podName, isForce));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "操作应用")
|
||||||
|
@PutMapping("/application/{kind}/{namespace}/{applicationName}/operate/{operationKey}")
|
||||||
|
public AjaxResult operateApplication(@PathVariable("kind") String kind,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName,
|
||||||
|
@PathVariable("operationKey") String operationKey) {
|
||||||
|
return toAjax(microManagementService.operateApplication(kind, namespace, applicationName, operationKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取应用类型")
|
||||||
|
@GetMapping("/applicationType")
|
||||||
|
public GenericsTableDataInfo<ApplicationTypeVo> applicationType() {
|
||||||
|
return new GenericsTableDataInfo<>(microManagementService.getApplicationTypeList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "创建应用")
|
||||||
|
@PostMapping("/application/{kind}")
|
||||||
|
public AjaxResult createApplication(@PathVariable("kind") String kind,
|
||||||
|
@RequestBody String yamlContent) {
|
||||||
|
return AjaxResult.success(microManagementService.createApplication(kind, yamlContent));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取应用Yaml文件")
|
||||||
|
@GetMapping(value = "/application/{kind}/{namespace}/{applicationName}/yamlFile", produces = "application/yaml")
|
||||||
|
public JSONObject getApplicationYamlFile(@PathVariable("kind") String kind,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName) {
|
||||||
|
return microManagementService.getApplicationYamlFile(kind, namespace, applicationName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "编辑应用Yaml文件")
|
||||||
|
@PutMapping("/application/{kind}/{namespace}/{applicationName}")
|
||||||
|
public AjaxResult editApplication(@PathVariable("kind") String kind,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName,
|
||||||
|
@RequestBody String yamlContent) {
|
||||||
|
return toAjax(microManagementService.editApplication(kind, namespace, applicationName, yamlContent));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "删除应用")
|
||||||
|
@DeleteMapping("/application/{kind}/{namespace}/{applicationName}")
|
||||||
|
public AjaxResult deleteApplication(@PathVariable("kind") String kind,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName) {
|
||||||
|
return toAjax(microManagementService.deleteApplication(kind, namespace, applicationName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取应用环境变量")
|
||||||
|
@GetMapping(value = "/application/{kind}/{namespace}/{applicationName}/env")
|
||||||
|
public GenericsTableDataInfo<K8sApplicationEnv> getApplicationEnv(@PathVariable("kind") String kind,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName) {
|
||||||
|
return new GenericsTableDataInfo<>(microManagementService.getApplicationEnv(kind, namespace, applicationName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取应用环境变量相关可选参数")
|
||||||
|
@GetMapping(value = "/application/{namespace}/envOptionalParameters")
|
||||||
|
public GenericsTableDataInfo<K8sApplicationEnvOptionalParameter> getEnvOptionalParameters(@PathVariable("namespace") String namespace) {
|
||||||
|
return new GenericsTableDataInfo<>(microManagementService.getEnvOptionalParameters(namespace));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "更新应用环境变量")
|
||||||
|
@PutMapping("/application/{kind}/{namespace}/{applicationName}/env")
|
||||||
|
public AjaxResult updateApplicationEnv(@PathVariable("kind") String kind,
|
||||||
|
@PathVariable("namespace") String namespace,
|
||||||
|
@PathVariable("applicationName") String applicationName,
|
||||||
|
@RequestBody List<K8sApplicationEnv> k8sApplicationEnvList) {
|
||||||
|
return toAjax(microManagementService.updateApplicationEnv(kind, namespace, applicationName, k8sApplicationEnvList));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取应用环境变量类型")
|
||||||
|
@GetMapping(value = "/application/envTypes")
|
||||||
|
public GenericsTableDataInfo<ApplicationEnvTypeVo> getEnvTypes() {
|
||||||
|
return new GenericsTableDataInfo<>(microManagementService.getEnvTypes());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取网关路由配置")
|
||||||
|
@GetMapping(value = "/gateway/routeConfig")
|
||||||
|
public GenericsTableDataInfo<GatewayRouteConfig> getGatewayRouteConfig() {
|
||||||
|
return new GenericsTableDataInfo<>(microManagementService.getGatewayRouteConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "更新网关路由配置")
|
||||||
|
@PutMapping(value = "/gateway/routeConfig")
|
||||||
|
public AjaxResult updateGatewayRouteConfig(@RequestBody List<GatewayRouteConfig> gatewayRouteConfigList) {
|
||||||
|
return toAjax(microManagementService.updateGatewayRouteConfig(gatewayRouteConfigList));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取网关安全认证配置")
|
||||||
|
@GetMapping(value = "/gateway/safetyConfig")
|
||||||
|
public GenericsAjaxResult<GatewaySafetyConfig> getGatewaySafetyConfig() {
|
||||||
|
return GenericsAjaxResult.success(microManagementService.getGatewaySafetyConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "更新网关安全认证配置")
|
||||||
|
@PutMapping(value = "/gateway/safetyConfig")
|
||||||
|
public AjaxResult updateGatewaySafetyConfig(@RequestBody GatewaySafetyConfig gatewaySafetyConfig) {
|
||||||
|
return toAjax(microManagementService.updateGatewaySafetyConfig(gatewaySafetyConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取网关白名单配置")
|
||||||
|
@GetMapping(value = "/gateway/whitelistConfig")
|
||||||
|
public GenericsAjaxResult<GatewayWhitelistConfig> getGatewayWhitelistConfig() {
|
||||||
|
return GenericsAjaxResult.success(microManagementService.getGatewayWhitelistConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "更新网关白名单配置")
|
||||||
|
@PutMapping(value = "/gateway/whitelistConfig")
|
||||||
|
public AjaxResult updateGatewayWhitelistConfig(@RequestBody GatewayWhitelistConfig gatewayWhitelistConfig) {
|
||||||
|
return toAjax(microManagementService.updateGatewayWhitelistConfig(gatewayWhitelistConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取存在网关异常处理记录的日期列表")
|
||||||
|
@GetMapping(value = "/gateway/exceptionHandingDateList")
|
||||||
|
public GenericsTableDataInfo<String> getExceptionHandingDateList() {
|
||||||
|
return new GenericsTableDataInfo<>(microManagementService.getExceptionHandingDateList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取网关异常处理记录")
|
||||||
|
@GetMapping(value = "/gateway/exceptionHandingRecordList")
|
||||||
|
public GenericsTableDataInfo<String> getExceptionHandingRecordList(@RequestParam(value = "date", required = false) @ApiParam(value = "查看日期") String date) {
|
||||||
|
return new GenericsTableDataInfo<>(microManagementService.getExceptionHandingRecordList(date));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取网关限流跳转参数")
|
||||||
|
@GetMapping(value = "/gateway/flowLimitingPara")
|
||||||
|
public GenericsAjaxResult<JSONObject> getGatewayFlowLimitingPara() {
|
||||||
|
return GenericsAjaxResult.success(microManagementService.getGatewayFlowLimitingPara());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取链路追踪应用列表")
|
||||||
|
@GetMapping(value = "/application/linkTrackingList")
|
||||||
|
public GenericsTableDataInfo<LinkTrackingApplication> getLinkTrackingList(@RequestParam(value = "applicationName", required = false) @ApiParam(value = "应用名称") String applicationName) {
|
||||||
|
return new GenericsTableDataInfo<>(microManagementService.getLinkTrackingList(applicationName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取K8S事件关键活动操作列表")
|
||||||
|
@GetMapping(value = "/k8sEvent/keyActivitiesOperationList")
|
||||||
|
public GenericsTableDataInfo<CommonTypeVo> getKeyActivitiesOperationList() {
|
||||||
|
return new GenericsTableDataInfo<>(microManagementService.getK8SEventReasonList("Normal"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取K8S事件关键活动列表")
|
||||||
|
@GetMapping(value = "/k8sEvent/keyActivitiesList")
|
||||||
|
public GenericsTableDataInfo<K8SEvent> getKeyActivitiesList(@RequestParam(value = "reason", required = false) @ApiParam(value = "操作类型") String reason,
|
||||||
|
@RequestParam(value = "startTime", required = false) @ApiParam(value = "开始时间") Date startTime,
|
||||||
|
@RequestParam(value = "endTime", required = false) @ApiParam(value = "结束时间") Date endTime,
|
||||||
|
@RequestParam(value = "isAscOrderByOccurredTime", required = false) @ApiParam(value = "是否根据发生时间升序排序(默认根据发生时间降序排序)") Boolean isAscOrderByOccurredTime,
|
||||||
|
@RequestParam(value = "pageNum", required = false) @ApiParam(value = "当前记录起始索引") Integer pageNum,
|
||||||
|
@RequestParam(value = "pageSize", required = false) @ApiParam(value = "每页显示记录数") Integer pageSize) {
|
||||||
|
return microManagementService.getK8SEventList("Normal", reason, startTime, endTime, isAscOrderByOccurredTime, pageNum, pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取K8S事异常结束事件原因列表")
|
||||||
|
@GetMapping(value = "/k8sEvent/exceptionEndReasonList")
|
||||||
|
public GenericsTableDataInfo<CommonTypeVo> getExceptionEndReasonList() {
|
||||||
|
return new GenericsTableDataInfo<>(microManagementService.getK8SEventReasonList("Warning"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取K8S事件异常结束事件列表")
|
||||||
|
@GetMapping(value = "/k8sEvent/exceptionEndList")
|
||||||
|
public GenericsTableDataInfo<K8SEvent> getExceptionEndListList(@RequestParam(value = "reason", required = false) @ApiParam(value = "操作类型") String reason,
|
||||||
|
@RequestParam(value = "startTime", required = false) @ApiParam(value = "开始时间") Date startTime,
|
||||||
|
@RequestParam(value = "endTime", required = false) @ApiParam(value = "结束时间") Date endTime,
|
||||||
|
@RequestParam(value = "isAscOrderByOccurredTime", required = false) @ApiParam(value = "是否根据发生时间升序排序(默认根据发生时间降序排序)") Boolean isAscOrderByOccurredTime,
|
||||||
|
@RequestParam(value = "pageNum", required = false) @ApiParam(value = "当前记录起始索引") Integer pageNum,
|
||||||
|
@RequestParam(value = "pageSize", required = false) @ApiParam(value = "每页显示记录数") Integer pageSize) {
|
||||||
|
return microManagementService.getK8SEventList("Warning", reason, startTime, endTime, isAscOrderByOccurredTime, pageNum, pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取K8S资源对象列表")
|
||||||
|
@GetMapping(value = "/k8sEvent/resourceObjectList")
|
||||||
|
public GenericsTableDataInfo<CommonTypeVo> getResourceObjectList() {
|
||||||
|
return new GenericsTableDataInfo<>(microManagementService.getResourceObjectList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取K8S资源占用列表")
|
||||||
|
@GetMapping(value = "/k8sEvent/resourceUsageList")
|
||||||
|
@ApiImplicitParams({
|
||||||
|
@ApiImplicitParam(name = "pageNum", value = "当前记录起始索引", paramType = "query", dataType = "Integer"),
|
||||||
|
@ApiImplicitParam(name = "pageSize", value = "每页显示记录数", paramType = "query", dataType = "Integer")
|
||||||
|
})
|
||||||
|
public GenericsTableDataInfo<K8SResourceUsage> getResourceUsageList(@RequestParam(value = "searchResourceObject", required = false) @ApiParam(value = "资源对象") String searchResourceObject,
|
||||||
|
@RequestParam(value = "startTime", required = false) @ApiParam(value = "开始时间") Date startTime,
|
||||||
|
@RequestParam(value = "endTime", required = false) @ApiParam(value = "结束时间") Date endTime) {
|
||||||
|
return getAllGenericsDataTableToPage(microManagementService.getResourceUsageList(searchResourceObject, startTime, endTime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
package com.microservices.mon.k8s.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.web.controller.BaseController;
|
||||||
|
import com.microservices.common.core.web.domain.AjaxResult;
|
||||||
|
import com.microservices.common.core.web.domain.GenericsAjaxResult;
|
||||||
|
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||||
|
import com.microservices.mon.k8s.domain.*;
|
||||||
|
import com.microservices.mon.k8s.domain.vo.ApplicationEnvTypeVo;
|
||||||
|
import com.microservices.mon.k8s.domain.vo.ApplicationTypeVo;
|
||||||
|
import com.microservices.mon.k8s.service.IMicroManagementService;
|
||||||
|
import com.microservices.mon.k8s.service.IMicroStatusService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("microStatus")
|
||||||
|
@Api(tags = "微服务状态监控")
|
||||||
|
@RefreshScope
|
||||||
|
public class MicroStatusController extends BaseController {
|
||||||
|
@Autowired
|
||||||
|
private IMicroStatusService microStatusService;
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取容器启停状态")
|
||||||
|
@GetMapping("/podStartStopStatus")
|
||||||
|
public GenericsAjaxResult<K8sPodStartStopStatus> getPodStartStopStatus() {
|
||||||
|
return GenericsAjaxResult.success(microStatusService.getPodStartStopStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取容器CPU使用率")
|
||||||
|
@GetMapping("/podCpuUsage")
|
||||||
|
public GenericsTableDataInfo<K8sPodContainerMetric> getPodCpuUsage(@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||||
|
return new GenericsTableDataInfo<>(microStatusService.getPodCpuUsage(step));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取容器内存使用情况")
|
||||||
|
@GetMapping("/podMemoryUsage")
|
||||||
|
public GenericsTableDataInfo<K8sPodContainerMetric> getPodMemoryUsage(@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||||
|
return new GenericsTableDataInfo<>(microStatusService.getPodMemoryUsage(step));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取容器硬盘读取情况")
|
||||||
|
@GetMapping("/podDiskReads")
|
||||||
|
public GenericsTableDataInfo<K8sPodContainerMetric> getPodDiskReads(@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||||
|
return new GenericsTableDataInfo<>(microStatusService.getPodDiskReads(step));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取容器硬盘写入情况")
|
||||||
|
@GetMapping("/podDiskWrites")
|
||||||
|
public GenericsTableDataInfo<K8sPodContainerMetric> getPodDiskWrites(@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||||
|
return new GenericsTableDataInfo<>(microStatusService.getPodDiskWrites(step));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取容器网络接收情况")
|
||||||
|
@GetMapping("/podNetworkReception")
|
||||||
|
public GenericsTableDataInfo<K8sPodContainerMetric> getPodNetworkReception(@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||||
|
return new GenericsTableDataInfo<>(microStatusService.getPodNetworkReception(step));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation(value = "获取容器网络发送情况")
|
||||||
|
@GetMapping("/podNetworkTransmission")
|
||||||
|
public GenericsTableDataInfo<K8sPodContainerMetric> getPodNetworkTransmission(@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||||
|
return new GenericsTableDataInfo<>(microStatusService.getPodNetworkTransmission(step));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import com.microservices.common.core.exception.ServiceException;
|
||||||
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author OTTO
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum ApplicationEnvType {
|
||||||
|
|
||||||
|
KEY_VALUE_PAIR("keyValuePair", "键值对"),
|
||||||
|
RESOURCE("resource", "资源字段"),
|
||||||
|
CONFIG_MAP_KEY("configMapKey", "ConfigMap键"),
|
||||||
|
SECRET_KEY("secretKey", "Secret键"),
|
||||||
|
POD_FIELD("podField", "容器字段"),
|
||||||
|
SECRET("secret", "Secret整体"),
|
||||||
|
CONFIGMAP("configMap", "ConfigMap整体");
|
||||||
|
|
||||||
|
private final String key;
|
||||||
|
private final String alias;
|
||||||
|
|
||||||
|
ApplicationEnvType(String key, String alias) {
|
||||||
|
this.key = key;
|
||||||
|
this.alias = alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApplicationEnvType getApplicationEnvTypeByKey(String type) {
|
||||||
|
for (ApplicationEnvType applicationEnvType : ApplicationEnvType.values()) {
|
||||||
|
if (StringUtils.equals(applicationEnvType.getKey(), type)) {
|
||||||
|
return applicationEnvType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ServiceException("该应用环境变量类型不存在(环境变量类型[%s])", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("应用功能")
|
||||||
|
public class ApplicationFunction {
|
||||||
|
@ApiModelProperty(value = "应用功能标识")
|
||||||
|
private String key;
|
||||||
|
@ApiModelProperty(value = "应用功能名称")
|
||||||
|
private String name;
|
||||||
|
@ApiModelProperty(value = "应用功能访问所需参数")
|
||||||
|
private JSONObject variables;
|
||||||
|
|
||||||
|
public void setKeyAndName(ApplicationFunctionType applicationFunctionType) {
|
||||||
|
this.key = applicationFunctionType.getKey();
|
||||||
|
this.name = applicationFunctionType.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import com.microservices.common.core.exception.ServiceException;
|
||||||
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author OTTO
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum ApplicationFunctionType {
|
||||||
|
LINK_TRACKING("LinkTracking", "链路追踪", "mon-skywalking-key"),
|
||||||
|
FLOW_CONTROL("FlowControl", "流量控制", "mon-sentinel-key"),
|
||||||
|
CONFIGURATION_MANAGEMENT("ConfigurationManagement", "配置管理", ""),
|
||||||
|
REGISTRATION_CENTER("RegistrationCenter", "注册中心", "mon-nacos-key"),
|
||||||
|
GATEWAY_MANAGEMENT("GatewayManagement", "网关管理", "mon-gateway-key"),
|
||||||
|
START_AND_STOP_MANAGEMENT("StartAndStopManagement", "启停管理", "");
|
||||||
|
private final String key;
|
||||||
|
private final String name;
|
||||||
|
private final String k8sLabel;
|
||||||
|
|
||||||
|
ApplicationFunctionType(String key, String name, String k8sLabel) {
|
||||||
|
this.key = key;
|
||||||
|
this.name = name;
|
||||||
|
this.k8sLabel = k8sLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApplicationFunctionType getByLabelsKey(String k8sLabel) {
|
||||||
|
if (StringUtils.isNotEmpty(k8sLabel)) {
|
||||||
|
for (ApplicationFunctionType type : ApplicationFunctionType.values()) {
|
||||||
|
if (type.getK8sLabel().equals(k8sLabel)) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("应用请求次数对象")
|
||||||
|
public class ApplicationRequestCountData {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "序号")
|
||||||
|
private Integer number;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "应用名称")
|
||||||
|
private String applicationAlias;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "请求次数")
|
||||||
|
private Long requestCount;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
|
import com.microservices.mon.k8s.domain.vo.RancherApplicationVo;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author OTTO
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum ApplicationStartAndStopType {
|
||||||
|
START("start", "启动", false),
|
||||||
|
STOP("stop", "停止", false),
|
||||||
|
FORCE_STOP("forceStop", "强制停止", false),
|
||||||
|
RESTART("restart", "重启", true),
|
||||||
|
PAUSED("paused", "暂停", true),
|
||||||
|
RESUME("resume", "恢复", true);
|
||||||
|
private final String key;
|
||||||
|
private final String name;
|
||||||
|
private final Boolean isDaemonSetOperation;
|
||||||
|
|
||||||
|
ApplicationStartAndStopType(String key, String name, Boolean isDaemonSetOperation) {
|
||||||
|
this.key = key;
|
||||||
|
this.name = name;
|
||||||
|
this.isDaemonSetOperation = isDaemonSetOperation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JSONArray getOperationList(String kind, K8sApplication k8sApplication) {
|
||||||
|
JSONArray jsonArray = new JSONArray();
|
||||||
|
if (k8sApplication == null) {
|
||||||
|
return jsonArray;
|
||||||
|
}
|
||||||
|
for (ApplicationStartAndStopType value : values()) {
|
||||||
|
if ("DaemonSet".equals(kind) && !value.isDaemonSetOperation) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean shouldAdd = false;
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case START:
|
||||||
|
if (k8sApplication.getReplicas() == null || k8sApplication.getReplicas() == 0) {
|
||||||
|
shouldAdd = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STOP:
|
||||||
|
case FORCE_STOP:
|
||||||
|
case RESTART:
|
||||||
|
if (k8sApplication.getReplicas() != null && k8sApplication.getReplicas() > 0) {
|
||||||
|
shouldAdd = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PAUSED:
|
||||||
|
if (!k8sApplication.getPaused()) {
|
||||||
|
shouldAdd = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RESUME:
|
||||||
|
if (k8sApplication.getPaused()) {
|
||||||
|
shouldAdd = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldAdd) {
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("operationKey", value.getKey());
|
||||||
|
jsonObject.put("operationName", value.getName());
|
||||||
|
jsonArray.add(jsonObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jsonArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean containsKey(String operationKey) {
|
||||||
|
for (ApplicationStartAndStopType value : values()) {
|
||||||
|
if (StringUtils.equals(value.getKey(), operationKey)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApplicationStartAndStopType getByKey(String operationKey) {
|
||||||
|
for (ApplicationStartAndStopType value : values()) {
|
||||||
|
if (StringUtils.equals(value.getKey(), operationKey)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import com.microservices.common.core.exception.ServiceException;
|
||||||
|
import com.microservices.common.core.utils.StringUtils;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author OTTO
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum ApplicationType {
|
||||||
|
DAEMON_SET("DaemonSet", "apps.daemonsets", "确保每个节点(或指定节点)上都运行一个容器副本", "daemonsets"),
|
||||||
|
DEPLOYMENT("Deployment", "apps.deployments", "管理无状态应用的容器副本,支持声明式更新和回滚", "deployments"),
|
||||||
|
STATEFUL_SET("StatefulSet", "apps.statefulsets", "管理有状态应用,为容器提供稳定的标识和持久化存储", "statefulsets");
|
||||||
|
private final String key;
|
||||||
|
private final String fullName;
|
||||||
|
private final String description;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
ApplicationType(String key, String fullName, String description, String name) {
|
||||||
|
this.key = key;
|
||||||
|
this.fullName = fullName;
|
||||||
|
this.description = description;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApplicationType getApplicationTypeByKey(String key) {
|
||||||
|
for (ApplicationType value : ApplicationType.values()) {
|
||||||
|
if (StringUtils.equalsIgnoreCase(value.getKey(), key)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ServiceException("该应用类型不存在(应用类型[%s])", key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean isApplicationType(String key) {
|
||||||
|
for (ApplicationType value : ApplicationType.values()) {
|
||||||
|
if (StringUtils.equalsIgnoreCase(value.getKey(), key)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("网关路由配置")
|
||||||
|
public class GatewayRouteConfig {
|
||||||
|
@ApiModelProperty(value = "路由标识")
|
||||||
|
private String id;
|
||||||
|
@ApiModelProperty(value = "目标地址")
|
||||||
|
private String uri;
|
||||||
|
@ApiModelProperty(value = "转发规则")
|
||||||
|
private List<String> predicates;
|
||||||
|
@ApiModelProperty(value = "过滤规则")
|
||||||
|
private List<String> filters;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("网关安全认证配置")
|
||||||
|
public class GatewaySafetyConfig {
|
||||||
|
@ApiModelProperty(value = "允许请求来源")
|
||||||
|
private List<String> allowedOriginPatterns;
|
||||||
|
@ApiModelProperty(value = "允许请求头")
|
||||||
|
private List<String> allowedHeaders;
|
||||||
|
@ApiModelProperty(value = "预检请求缓存时间")
|
||||||
|
private Integer maxAge=360000;
|
||||||
|
@ApiModelProperty(value = "允许请求方法")
|
||||||
|
private List<String> allowedMethods;
|
||||||
|
@ApiModelProperty(value = "允许证书")
|
||||||
|
private Boolean allowCredentials = true;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("网关白名单配置")
|
||||||
|
public class GatewayWhitelistConfig {
|
||||||
|
@ApiModelProperty(value = "白名单列表")
|
||||||
|
private List<String> whites;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
package com.microservices.mon.k8s.domain;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("K8S事件")
|
||||||
|
public class K8SEvent {
|
||||||
|
@ApiModelProperty(value = "事件id")
|
||||||
|
private String docId;
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@ApiModelProperty(value = "发生时间")
|
||||||
|
private Date occurredTime;
|
||||||
|
@ApiModelProperty(value = "操作类型/异常原因")
|
||||||
|
private String reason;
|
||||||
|
@ApiModelProperty(value = "事件发生对象")
|
||||||
|
private String object;
|
||||||
|
@ApiModelProperty(value = "事件发生子对象")
|
||||||
|
private String childObject;
|
||||||
|
@ApiModelProperty(value = "所处命名空间")
|
||||||
|
private String namespace;
|
||||||
|
@ApiModelProperty(value = "运行结果/详细信息")
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public static GenericsTableDataInfo<K8SEvent> toK8SEventTable(JSONObject esQueryRes) {
|
||||||
|
List<K8SEvent> k8SEventList = new ArrayList<>();
|
||||||
|
Long total = getK8SEventTotal(esQueryRes, k8SEventList);
|
||||||
|
return new GenericsTableDataInfo<>(k8SEventList, total);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<K8SEvent> toK8SEventList(JSONObject esQueryRes) {
|
||||||
|
List<K8SEvent> k8SEventList = new ArrayList<>();
|
||||||
|
getK8SEventTotal(esQueryRes, k8SEventList);
|
||||||
|
return k8SEventList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Long getK8SEventTotal(JSONObject esQueryRes, List<K8SEvent> k8SEventList) {
|
||||||
|
Long total = 0L;
|
||||||
|
if (esQueryRes.getJSONObject("hits") != null && esQueryRes.getJSONObject("hits").getJSONArray("hits") != null) {
|
||||||
|
JSONObject hits = esQueryRes.getJSONObject("hits");
|
||||||
|
JSONArray dataHits = hits.getJSONArray("hits");
|
||||||
|
|
||||||
|
for (int i = 0; i < dataHits.size(); i++) {
|
||||||
|
JSONObject dataHit = dataHits.getJSONObject(i);
|
||||||
|
K8SEvent k8SEvent = new K8SEvent();
|
||||||
|
k8SEvent.setDocId(dataHit.getString("_id"));
|
||||||
|
JSONObject source = dataHit.getJSONObject("_source");
|
||||||
|
k8SEvent.setOccurredTime(source.getDate("lastTimestamp"));
|
||||||
|
k8SEvent.setReason(source.getString("reason"));
|
||||||
|
if (source.getJSONObject("involvedObject") != null) {
|
||||||
|
JSONObject involvedObject = source.getJSONObject("involvedObject");
|
||||||
|
k8SEvent.setObject(String.format("%s:%s", involvedObject.getString("kind"), involvedObject.getString("name")));
|
||||||
|
k8SEvent.setChildObject(involvedObject.getString("fieldPath"));
|
||||||
|
k8SEvent.setNamespace(involvedObject.getString("namespace"));
|
||||||
|
}
|
||||||
|
|
||||||
|
k8SEvent.setMessage(source.getString("message"));
|
||||||
|
k8SEventList.add(k8SEvent);
|
||||||
|
}
|
||||||
|
total = hits.getJSONObject("total").getLong("value");
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue