Compare commits
269 Commits
dev_monito
...
master
| Author | SHA1 | Date |
|---|---|---|
|
|
c641ae6ab2 | |
|
|
7e5127b078 | |
|
|
0e13149981 | |
|
|
fd0d726a33 | |
|
|
58387872f0 | |
|
|
b62c7a6164 | |
|
|
62d4418679 | |
|
|
ca4c8bb614 | |
|
|
76f865624e | |
|
|
9d1d5527c8 | |
|
|
7a44a2113d | |
|
|
1bf9522d8f | |
|
|
5aa499f4de | |
|
|
35d5b1318e | |
|
|
4ccc743bd2 | |
|
|
84f624fdb7 | |
|
|
e43fb391fa | |
|
|
fc9e511aa0 | |
|
|
0abc43f033 | |
|
|
9fe4c69487 | |
|
|
d2d2f7368c | |
|
|
77125630e5 | |
|
|
ab53fa6ee0 | |
|
|
45f77beb73 | |
|
|
62c56097e2 | |
|
|
66c8132fe3 | |
|
|
f0725c78a1 | |
|
|
7093cda7bb | |
|
|
2a075ab571 | |
|
|
eba2082e2b | |
|
|
2cf4762b2c | |
|
|
b43c6384d3 | |
|
|
4d378d560d | |
|
|
6006440878 | |
|
|
4bbd80f739 | |
|
|
06633ff0a8 | |
|
|
6688c1f0e1 | |
|
|
93fb7eacf0 | |
|
|
5d6a64a4cc | |
|
|
887f4d1616 | |
|
|
49576e5ad0 | |
|
|
666c9c7b5e | |
|
|
95e5178de8 | |
|
|
8ce9a96fee | |
|
|
43572e7698 | |
|
|
3a5c9e03cf | |
|
|
bb2f414aa4 | |
|
|
76fa1f5447 | |
|
|
5e20807aed | |
|
|
83566e947a | |
|
|
f3a718d75a | |
|
|
7c6614bddb | |
|
|
c2b992c990 | |
|
|
0e63d5efcd | |
|
|
29c09c7091 | |
|
|
7506ec7cb2 | |
|
|
0132d56eb2 | |
|
|
93edb6b138 | |
|
|
3599ac3d4a | |
|
|
44e7ed5605 | |
|
|
b1d46f9471 | |
|
|
9b0b8c4362 | |
|
|
f9d779704a | |
|
|
2fa5be38b2 | |
|
|
22f3a8dc6b | |
|
|
df594efd9a | |
|
|
d2e0c54cdd | |
|
|
dc65b2d299 | |
|
|
d62d474848 | |
|
|
388423d53c | |
|
|
adbb5d04db | |
|
|
ee2ae04586 | |
|
|
2decec46ee | |
|
|
4402c972c9 | |
|
|
14748b4253 | |
|
|
ac22a5ba15 | |
|
|
f80bc0219c | |
|
|
941f30d6b3 | |
|
|
19dd235a26 | |
|
|
dea2c5e4d6 | |
|
|
5f1e8ddaf9 | |
|
|
1f3f3546a6 | |
|
|
f2d18d8334 | |
|
|
f491cd4753 | |
|
|
7bf2a532b3 | |
|
|
87a79ee7f4 | |
|
|
c358ffcfb7 | |
|
|
3e4f489914 | |
|
|
e559bcc48a | |
|
|
3b599bed3f | |
|
|
8c68611369 | |
|
|
1ef0cdcef2 | |
|
|
75ca1eff4d | |
|
|
8a69939e84 | |
|
|
77e3a9e0d3 | |
|
|
effaebe0d4 | |
|
|
1a8b537dae | |
|
|
86c3f502f1 | |
|
|
0ddac0b423 | |
|
|
9543d7fa38 | |
|
|
e7fcf69c9a | |
|
|
b26081dc17 | |
|
|
21658c6b66 | |
|
|
80e7b1f1b3 | |
|
|
85b19136a8 | |
|
|
e28691709f | |
|
|
2bb93099b5 | |
|
|
d98998422d | |
|
|
e7478556d4 | |
|
|
22ac8bec90 | |
|
|
bd34c5beae | |
|
|
33dd51c5f1 | |
|
|
ebe565af2e | |
|
|
30a3119580 | |
|
|
68673c355a | |
|
|
6c1a4589e7 | |
|
|
bc4d402c88 | |
|
|
21868ae523 | |
|
|
1ac64877f8 | |
|
|
9fa1545e11 | |
|
|
845993f7c8 | |
|
|
2edc3bacc7 | |
|
|
fc08a962ce | |
|
|
541b43d768 | |
|
|
6bb1b3c6eb | |
|
|
b784d44e26 | |
|
|
012ed2b25b | |
|
|
7219a66b5a | |
|
|
24b117a5a2 | |
|
|
590bc076c1 | |
|
|
41baf01039 | |
|
|
e3d33c0507 | |
|
|
3e10ed1b54 | |
|
|
883fdfdb75 | |
|
|
da4c832e82 | |
|
|
92bea2ec47 | |
|
|
ff38c7a6a0 | |
|
|
16fc7fd3ee | |
|
|
f61117526e | |
|
|
a00cdb4238 | |
|
|
c61346b4d9 | |
|
|
c734737e32 | |
|
|
fc6d67b1ed | |
|
|
1ea5e87767 | |
|
|
f1bb7f7b3f | |
|
|
0f97696614 | |
|
|
fcfd415fdc | |
|
|
e12afda308 | |
|
|
d882970a32 | |
|
|
eb22a4ebeb | |
|
|
fcd190bfac | |
|
|
5b05d90522 | |
|
|
40620e18b5 | |
|
|
7ffbdad4bc | |
|
|
31ad557697 | |
|
|
8f5b4f1882 | |
|
|
820ecc2d61 | |
|
|
a75d2b55fd | |
|
|
c218b86a39 | |
|
|
94fb839f2c | |
|
|
d631abe3a1 | |
|
|
e2ab5396ea | |
|
|
6982b6451d | |
|
|
3b178aa0a6 | |
|
|
b62c85f373 | |
|
|
215d7b6914 | |
|
|
6e29169fa4 | |
|
|
6c0c459d60 | |
|
|
18d0a9ce3e | |
|
|
7930e4a155 | |
|
|
77d8a8ae23 | |
|
|
8dfac68f66 | |
|
|
eef0e81d11 | |
|
|
054905987f | |
|
|
91ce2fff08 | |
|
|
08f6aaa414 | |
|
|
7582c5cb11 | |
|
|
f7229b6d42 | |
|
|
2fe06ea788 | |
|
|
ffc5f2e26e | |
|
|
01eb5464e4 | |
|
|
13d34fb2e9 | |
|
|
6830387bb8 | |
|
|
b429c568f5 | |
|
|
e2347e6609 | |
|
|
9305ae91c6 | |
|
|
7dbbbbb090 | |
|
|
7f0d3d4dcb | |
|
|
6c62ba619b | |
|
|
6fb9c13bba | |
|
|
900dcdf4d7 | |
|
|
a6a656820a | |
|
|
0bd824966e | |
|
|
543689fc61 | |
|
|
d8c951f9e0 | |
|
|
f6f2ee0f5d | |
|
|
7376dcbef4 | |
|
|
fbb40e3359 | |
|
|
5318bc1a8e | |
|
|
cbb08235f3 | |
|
|
dc6428df41 | |
|
|
b39ea22a43 | |
|
|
9404cc38e3 | |
|
|
beb6c6e727 | |
|
|
8270bcacd6 | |
|
|
2897c163f3 | |
|
|
16cb2b3477 | |
|
|
354c10f841 | |
|
|
0cf376a45d | |
|
|
431cd7404d | |
|
|
181546fab2 | |
|
|
3389e839a1 | |
|
|
fded90d57c | |
|
|
a0384614d3 | |
|
|
cd483c065d | |
|
|
822505b989 | |
|
|
9799da2fef | |
|
|
43149d52bf | |
|
|
aff24c83d2 | |
|
|
1c6563f915 | |
|
|
4f5f9a283c | |
|
|
a688c9b836 | |
|
|
77cd5bbc3a | |
|
|
e493757e2b | |
|
|
e80a0ded7a | |
|
|
c3962a9e3d | |
|
|
481c3ddfbd | |
|
|
d30cfd56f2 | |
|
|
8c1832780f | |
|
|
cc52682aa8 | |
|
|
fec5dd7f3b | |
|
|
8f2ff93dca | |
|
|
8850ed8fbc | |
|
|
45bcfeafca | |
|
|
4126803cbe | |
|
|
cf03c82425 | |
|
|
9f1d89da49 | |
|
|
9301975900 | |
|
|
33ff6795d1 | |
|
|
27bd86998c | |
|
|
1f4b5c6140 | |
|
|
56424116ae | |
|
|
995e5016fe | |
|
|
5e8f9fec06 | |
|
|
ed0912a1a6 | |
|
|
5e9bc67cb7 | |
|
|
22a212a72a | |
|
|
37dcb5b98c | |
|
|
1141da00bf | |
|
|
4847718321 | |
|
|
cdead12a04 | |
|
|
e906a46eec | |
|
|
53e5c8c13b | |
|
|
ee43cbeaa8 | |
|
|
8aa1e777bb | |
|
|
8d8294ba6f | |
|
|
5ef10bfc1f | |
|
|
b71ec53ab1 | |
|
|
b6034b469c | |
|
|
66ffcc7595 | |
|
|
f015936a45 | |
|
|
f86d3213cd | |
|
|
7b4ee072dd | |
|
|
f336e702ac | |
|
|
613bc5fc07 | |
|
|
a4bdcb1547 | |
|
|
365ab34101 | |
|
|
8faedfebe0 | |
|
|
9edc2b8be9 |
|
|
@ -9,6 +9,8 @@ import com.microservices.system.api.factory.RemoteCmsFallbackFactory;
|
|||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户服务
|
||||
*
|
||||
|
|
@ -158,4 +160,22 @@ public interface RemoteCmsService {
|
|||
@GetMapping("/doc/getJSONObject/{cmsDocId}")
|
||||
R<JSONObject> selectCmsDocJSONObjectById(@PathVariable(value = "cmsDocId") Long cmsDocId
|
||||
, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
@PutMapping("/project/changeOrgRole/user/{userId}/operate/{operate}")
|
||||
R<Boolean> changeUserOrgRole(@PathVariable("userId") Long userId, @PathVariable("operate") int operate
|
||||
, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
/**
|
||||
* 首页文章合并列表(接收置顶文章 docId 有序列表,返回合并去重后的结果)
|
||||
* 供 Zone 服务 /open/getTopDoc 改造后调用
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param topDocIds 置顶文章 docId 有序列表
|
||||
* @param source 来源
|
||||
* @return 合并后的首页文章 JSONObject 列表
|
||||
*/
|
||||
@PostMapping("/doc/homePageDocMergeList/{zoneId}")
|
||||
R<List<JSONObject>> selectHomePageDocMergeList(@PathVariable("zoneId") Long zoneId,
|
||||
@RequestBody List<Long> topDocIds,
|
||||
@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public interface RemoteDeptService {
|
|||
* 根据组织id删除部门
|
||||
*
|
||||
* @param deptId 部门id
|
||||
* @param source 请求来源
|
||||
* @param source 请求来源
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@DeleteMapping("/dept/deleteDeptByDeptId")
|
||||
|
|
@ -105,7 +105,7 @@ public interface RemoteDeptService {
|
|||
* 通过用户名查询用户下组织及组织对应角色列表
|
||||
*
|
||||
* @param deptId 组织ID
|
||||
* @param source 请求来源
|
||||
* @param source 请求来源
|
||||
* @return 用户下组织及组织对应角色列表
|
||||
*/
|
||||
@GetMapping("/SysUserDeptRole/userByDeptId/{deptId}/list")
|
||||
|
|
@ -115,7 +115,7 @@ public interface RemoteDeptService {
|
|||
/**
|
||||
* 查询组织编号下拥有传入角色权限字符串的用户名
|
||||
*
|
||||
* @param deptId 组织编号
|
||||
* @param deptId 组织编号
|
||||
* @param roleKeys 角色权限字符串
|
||||
* @return 组织下拥有传入角色权限字符串的用户名列表
|
||||
*/
|
||||
|
|
@ -126,7 +126,7 @@ public interface RemoteDeptService {
|
|||
* 检查用户是否在指定部门下具有指定角色
|
||||
*
|
||||
* @param currentDeptId 组织编号
|
||||
* @param roleKey 角色权限字符串
|
||||
* @param roleKey 角色权限字符串
|
||||
* @return 组织下拥有传入角色权限字符串的用户名列表
|
||||
*/
|
||||
@GetMapping("/SysUserDeptRole/checkUserInDeptHasRole")
|
||||
|
|
@ -143,6 +143,17 @@ public interface RemoteDeptService {
|
|||
@GetMapping("/SysUserDeptRole/checkUserInDeptHasPerms")
|
||||
R<Boolean> checkUserInDeptHasPerms(@RequestParam("currentDeptId") Long currentDeptId, @RequestParam("userId") Long userId, @RequestParam("perms") String perms, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
/**
|
||||
* 检查用户是否在指定部门或指定部门的父级部门下具有指定菜单权限
|
||||
*
|
||||
* @param deptId 指定组织id
|
||||
* @param userId 用户id
|
||||
* @param perms 菜单权限
|
||||
* @return 用户是否在指定部门下具有菜单权限 是true 否false
|
||||
*/
|
||||
@GetMapping("/SysUserDeptRole/checkUserInDeptOrParentDeptHasPerms")
|
||||
R<Boolean> checkUserInDeptOrParentDeptHasPerms(@RequestParam("deptId") Long deptId, @RequestParam("userId") Long userId, @RequestParam("perms") String perms, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
/**
|
||||
* 检查用户是否在指定部门下
|
||||
*
|
||||
|
|
@ -152,4 +163,7 @@ public interface RemoteDeptService {
|
|||
*/
|
||||
@GetMapping("/SysUserDeptRole/checkUserInDept")
|
||||
R<Boolean> checkUserInDept(@RequestParam("currentDeptId") Long currentDeptId, @RequestParam("userId") Long userId, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
@GetMapping("/SysUserDeptRole/getSysUserDeptRoleByDeptIdAndUserId")
|
||||
R<SysUserDeptRole> getSysUserDeptRoleByDeptIdAndUserId(@RequestParam("deptId") Long deptId, @RequestParam("userId") Long userId, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
package com.microservices.system.api;
|
||||
|
||||
import com.microservices.common.core.constant.ServiceNameConstants;
|
||||
import com.microservices.common.core.domain.R;
|
||||
import com.microservices.system.api.domain.SysDictData;
|
||||
import com.microservices.system.api.factory.RemoteDictFallbackFactory;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文件服务
|
||||
*
|
||||
* @author microservices
|
||||
*/
|
||||
@FeignClient(contextId = "remoteDictDataService", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteDictFallbackFactory.class)
|
||||
public interface RemoteDictDataService {
|
||||
/**
|
||||
* 根据字典类型查询字典数据信息
|
||||
*/
|
||||
@GetMapping(value = "/dict/data/type/{dictType}")
|
||||
R<List<SysDictData>> dictType(@PathVariable("dictType") String dictType);
|
||||
|
||||
}
|
||||
|
|
@ -14,7 +14,6 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文件服务
|
||||
|
|
@ -35,17 +34,6 @@ public interface RemoteFileService {
|
|||
@RequestParam("hierarchy") String hierarchy,
|
||||
@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列表获取文件列表
|
||||
*
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ package com.microservices.system.api;
|
|||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
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.model.GraphqlQueryVo;
|
||||
import feign.Response;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -28,14 +28,6 @@ public interface RemoteGatewayService {
|
|||
@PostMapping("/sentinel/auth/login")
|
||||
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
|
||||
*
|
||||
|
|
@ -51,45 +43,4 @@ public interface RemoteGatewayService {
|
|||
*/
|
||||
@PostMapping("/portainer/api/auth")
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,124 +0,0 @@
|
|||
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);
|
||||
}
|
||||
|
|
@ -57,6 +57,15 @@ public interface RemoteUserService {
|
|||
@GetMapping("/user/getSysUserByUserId/{userId}")
|
||||
public R<SysUser> getSysUserByUserId(@PathVariable("userId") Long userId, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
/**
|
||||
* 通过用户ID数组批量获取用户信息(POST方法,解决URL长度限制)
|
||||
*
|
||||
* @param userIds 用户ID数组
|
||||
* @param source 请求来源
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/user/getSysUserListByUserIds")
|
||||
R<List<SysUser>> postSysUserListByUserIds(@RequestBody Long[] userIds, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
/**
|
||||
* 组织下新增用户身份
|
||||
|
|
@ -64,7 +73,7 @@ public interface RemoteUserService {
|
|||
* @param deptId
|
||||
* @param userId
|
||||
* @param roleKey
|
||||
* @param source 请求来源
|
||||
* @param source 请求来源
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/SysUserDeptRole/dept/{deptId}/user/{userId}/role/{roleKey}")
|
||||
|
|
@ -74,14 +83,13 @@ public interface RemoteUserService {
|
|||
, @PathVariable("roleKey") String roleKey
|
||||
, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
|
||||
/**
|
||||
* 组织下删除用户身份
|
||||
*
|
||||
* @param deptId
|
||||
* @param userId
|
||||
* @param roleKey
|
||||
* @param source 请求来源
|
||||
* @param source 请求来源
|
||||
* @return 结果
|
||||
*/
|
||||
@DeleteMapping("/SysUserDeptRole/dept/{deptId}/user/{userId}/role/{roleKey}")
|
||||
|
|
@ -91,18 +99,16 @@ public interface RemoteUserService {
|
|||
@PathVariable("roleKey") String roleKey,
|
||||
@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
|
||||
/**
|
||||
* 注册用户信息
|
||||
*
|
||||
* @param sysUser 用户信息
|
||||
* @param source 请求来源
|
||||
* @param source 请求来源
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/user/register")
|
||||
public R<Boolean> registerUserInfo(@RequestBody SysUser sysUser, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
|
||||
/**
|
||||
* 通过GitLinkToken获取本系统Token
|
||||
*
|
||||
|
|
@ -123,7 +129,6 @@ public interface RemoteUserService {
|
|||
@GetMapping("/SysUserDeptRole/userByUserName/{userName}/list")
|
||||
public R<List<SysUserDeptRole>> getSysUserDeptRoleListByUserName(@PathVariable("userName") String userName, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
|
||||
/**
|
||||
* 通过用户名查询用户下第一个身份
|
||||
*
|
||||
|
|
@ -195,7 +200,7 @@ public interface RemoteUserService {
|
|||
/**
|
||||
* 通过GitLink用户Id创建用户
|
||||
*
|
||||
* @param gitLinkUserId GitLink用户Id
|
||||
* @param gitLinkUserId GitLinkUserId
|
||||
* @param source 请求来源
|
||||
* @return 系统用户
|
||||
*/
|
||||
|
|
@ -206,7 +211,7 @@ public interface RemoteUserService {
|
|||
* 根据角色Key获取菜单权限集合
|
||||
*
|
||||
* @param roleKey 角色Key
|
||||
* @param source 请求来源
|
||||
* @param source 请求来源
|
||||
* @return 菜单权限集合
|
||||
*/
|
||||
@GetMapping("/menu/roleMenuPermissionByRoleKey/{roleKey}")
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 内容管理服务降级处理
|
||||
*
|
||||
|
|
@ -83,6 +85,16 @@ public class RemoteCmsFallbackFactory implements FallbackFactory<RemoteCmsServic
|
|||
public R<JSONObject> selectCmsDocJSONObjectById(Long cmsDocId, String source) {
|
||||
return R.fail("获取文章JSON对象失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<Boolean> changeUserOrgRole(Long userId, int operate, String source) {
|
||||
return R.fail("更新组织权限失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<List<JSONObject>> selectHomePageDocMergeList(Long zoneId, List<Long> topDocIds, String source) {
|
||||
return R.fail("获取首页文章合并列表失败:" + throwable.getMessage());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,10 +83,20 @@ public class RemoteDeptFallbackFactory implements FallbackFactory<RemoteDeptServ
|
|||
return R.fail("检查用户是否在指定部门下具有指定菜单权限失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<Boolean> checkUserInDeptOrParentDeptHasPerms(Long deptId, Long userId, String perms, String source) {
|
||||
return R.fail("检查用户是否在指定部门或指定部门的父级部门下具有指定菜单权限失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<Boolean> checkUserInDept(Long currentDeptId, Long userId, String source) {
|
||||
return R.fail("检查用户是否在指定部门下失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<SysUserDeptRole> getSysUserDeptRoleByDeptIdAndUserId(Long deptId, Long userId, String source) {
|
||||
return R.fail("获取用户在指定部门下的角色失败:" + throwable.getMessage());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
package com.microservices.system.api.factory;
|
||||
|
||||
import com.microservices.common.core.domain.R;
|
||||
import com.microservices.system.api.RemoteDictDataService;
|
||||
import com.microservices.system.api.domain.SysDictData;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 字典服务降级处理
|
||||
*
|
||||
* @author microservices
|
||||
*/
|
||||
@Component
|
||||
public class RemoteDictFallbackFactory implements FallbackFactory<RemoteDictDataService> {
|
||||
private static final Logger log = LoggerFactory.getLogger(RemoteDictFallbackFactory.class);
|
||||
|
||||
@Override
|
||||
public RemoteDictDataService create(Throwable throwable) {
|
||||
log.error("字典服务调用失败:{}", throwable.getMessage());
|
||||
return new RemoteDictDataService() {
|
||||
@Override
|
||||
public R<List<SysDictData>> dictType(String dictType) {
|
||||
return R.fail("获取字典列表失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,6 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文件服务降级处理
|
||||
|
|
@ -37,11 +36,6 @@ public class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileServ
|
|||
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
|
||||
public R<List<SysFileInfo>> getFileList(String fileIds) {
|
||||
return R.fail("获取文件列表失败:" + throwable.getMessage());
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
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.model.GraphqlQueryVo;
|
||||
import feign.Response;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -27,12 +25,7 @@ public class RemoteGatewayFallbackFactory implements FallbackFactory<RemoteGatew
|
|||
return new RemoteGatewayService() {
|
||||
|
||||
@Override
|
||||
public Response loginSentinel(String username, String password) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response loginRancher(JSONObject loginBody) {
|
||||
public Response loginSentinel(String password, String username) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -43,66 +36,7 @@ public class RemoteGatewayFallbackFactory implements FallbackFactory<RemoteGatew
|
|||
|
||||
@Override
|
||||
public Response loginPortainer(JSONObject loginBody) {
|
||||
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) {
|
||||
System.out.println(throwable.getMessage());
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,133 +0,0 @@
|
|||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +52,12 @@ public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserServ
|
|||
return R.fail("获取用户失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<List<SysUser>> postSysUserListByUserIds(Long[] userIds, String source) {
|
||||
|
||||
return R.fail("批量获取用户失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<Boolean> addUserIdentify(Long deptId, Long userId, String roleKey, String source) {
|
||||
return R.fail("组织下新增用户身份失败:" + throwable.getMessage());
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
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,24 +3,20 @@ package com.microservices.system.api.utils;
|
|||
import com.microservices.common.core.domain.R;
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import feign.Response;
|
||||
|
||||
/**
|
||||
* @author otto
|
||||
*/
|
||||
public class FeignUtils {
|
||||
public static <T> T getReturnData(R<T> result) {
|
||||
public static <T> T getReturnData(R<T> result){
|
||||
if (StringUtils.isNull(result)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (R.FAIL == result.getCode()) {
|
||||
if (R.FAIL == result.getCode())
|
||||
{
|
||||
throw new ServiceException(result.getMsg());
|
||||
}
|
||||
return result.getData();
|
||||
}
|
||||
|
||||
public static Boolean isSuccess(Response response) {
|
||||
return response != null && response.status() >= 200 && response.status() < 300;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
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,5 +6,3 @@ com.microservices.system.api.factory.RemoteCmsFallbackFactory
|
|||
com.microservices.system.api.factory.RemoteZoneFallbackFactory
|
||||
com.microservices.system.api.factory.RemotePmsFallbackFactory
|
||||
com.microservices.system.api.factory.RemoteGatewayFallbackFactory
|
||||
com.microservices.system.api.factory.RemoteRancherFallbackFactory
|
||||
com.microservices.system.api.factory.RemoteDictFallbackFactory
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 8080
|
||||
port: 9110
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
|
|
|
|||
|
|
@ -80,6 +80,10 @@ public class CacheConstants {
|
|||
* 通过组织Id获取专区详情JSON对象
|
||||
*/
|
||||
public final static String ZONE_JSON_OF_DEPT_ID_KEY = "zoneJSONOfDeptId:";
|
||||
/**
|
||||
* 积分发放部门
|
||||
*/
|
||||
public final static String ZONE_POINTS_DEPT_ID_KEY = "zonePointsDeptId";
|
||||
/**
|
||||
* 内容管理同步缓存前缀
|
||||
*/
|
||||
|
|
@ -213,11 +217,6 @@ public class CacheConstants {
|
|||
*/
|
||||
public final static String SENTINEL_TOKEN = "sentinel_token";
|
||||
|
||||
/**
|
||||
* Rancher Token缓存Key
|
||||
*/
|
||||
public final static String RANCHER_TOKEN = "rancher_token";
|
||||
|
||||
|
||||
/**
|
||||
* Nacos Token缓存Key
|
||||
|
|
@ -250,6 +249,18 @@ public class CacheConstants {
|
|||
return ZONE_PROJECT_SORT_BY_SCORE + "*:" + zoneId + ":*";
|
||||
}
|
||||
|
||||
/**
|
||||
* 专区统计数据缓存前缀
|
||||
*/
|
||||
private final static String ZONE_STATISTICS_KEY = "zone:statistics:";
|
||||
|
||||
/**
|
||||
* 获取专区统计数据缓存key
|
||||
*/
|
||||
public static String getZoneStatisticsKey(Long zoneId) {
|
||||
return ZONE_STATISTICS_KEY + zoneId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件打包是否完成(0:代表未完成;1:代表已完成;-1:代表打包失败,需要重新打包)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ package com.microservices.common.core.constant;
|
|||
*
|
||||
* @author microservices
|
||||
*/
|
||||
public class Constants {
|
||||
public class Constants
|
||||
{
|
||||
/**
|
||||
* UTF-8 字符集
|
||||
*/
|
||||
|
|
@ -124,10 +125,6 @@ public class Constants {
|
|||
* JSON类型
|
||||
*/
|
||||
public static final String JSON_CONTENT_TYPE = "application/json";
|
||||
/**
|
||||
* Yaml类型
|
||||
*/
|
||||
public static final String YAML_CONTENT_TYPE = "application/yaml";
|
||||
/**
|
||||
* 文本类型
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -37,11 +37,6 @@ public class SecurityConstants
|
|||
*/
|
||||
public static final String USER_KEY = "user_key";
|
||||
|
||||
/**
|
||||
* 用户Token
|
||||
*/
|
||||
public static final String TOKEN = "token";
|
||||
|
||||
/**
|
||||
* 组织ID
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -22,16 +22,9 @@ public class TokenConstants {
|
|||
* Sentinel令牌标识
|
||||
*/
|
||||
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";
|
||||
/**
|
||||
* Nacos令牌标识
|
||||
* Sentinel令牌标识
|
||||
*/
|
||||
public static final String Nacos_Token_Key = "Accesstoken";
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ package com.microservices.common.core.constant;
|
|||
*
|
||||
* @author microservices
|
||||
*/
|
||||
public class UserConstants
|
||||
{
|
||||
public class UserConstants {
|
||||
/**
|
||||
* 平台内系统用户的唯一标志
|
||||
*/
|
||||
|
|
@ -28,55 +27,89 @@ public class UserConstants
|
|||
*/
|
||||
public static final String DEL_FLAG_FALSE = "0";
|
||||
|
||||
/** 正常状态 */
|
||||
/**
|
||||
* 正常状态
|
||||
*/
|
||||
public static final String NORMAL = "0";
|
||||
|
||||
/** 异常状态 */
|
||||
/**
|
||||
* 异常状态
|
||||
*/
|
||||
public static final String EXCEPTION = "1";
|
||||
|
||||
/** 用户封禁状态 */
|
||||
/**
|
||||
* 用户封禁状态
|
||||
*/
|
||||
public static final String USER_DISABLE = "1";
|
||||
|
||||
/** 角色封禁状态 */
|
||||
/**
|
||||
* 角色封禁状态
|
||||
*/
|
||||
public static final String ROLE_DISABLE = "1";
|
||||
|
||||
/** 部门正常状态 */
|
||||
/**
|
||||
* 部门正常状态
|
||||
*/
|
||||
public static final String DEPT_NORMAL = "0";
|
||||
|
||||
/** 部门停用状态 */
|
||||
/**
|
||||
* 部门停用状态
|
||||
*/
|
||||
public static final String DEPT_DISABLE = "1";
|
||||
|
||||
/** 字典正常状态 */
|
||||
/**
|
||||
* 字典正常状态
|
||||
*/
|
||||
public static final String DICT_NORMAL = "0";
|
||||
|
||||
/** 是否为系统默认(是) */
|
||||
/**
|
||||
* 是否为系统默认(是)
|
||||
*/
|
||||
public static final String YES = "Y";
|
||||
|
||||
/** 是否菜单外链(是) */
|
||||
/**
|
||||
* 是否菜单外链(是)
|
||||
*/
|
||||
public static final String YES_FRAME = "0";
|
||||
|
||||
/** 是否菜单外链(否) */
|
||||
/**
|
||||
* 是否菜单外链(否)
|
||||
*/
|
||||
public static final String NO_FRAME = "1";
|
||||
|
||||
/** 菜单类型(目录) */
|
||||
/**
|
||||
* 菜单类型(目录)
|
||||
*/
|
||||
public static final String TYPE_DIR = "M";
|
||||
|
||||
/** 菜单类型(菜单) */
|
||||
/**
|
||||
* 菜单类型(菜单)
|
||||
*/
|
||||
public static final String TYPE_MENU = "C";
|
||||
|
||||
/** 菜单类型(按钮) */
|
||||
/**
|
||||
* 菜单类型(按钮)
|
||||
*/
|
||||
public static final String TYPE_BUTTON = "F";
|
||||
|
||||
/** Layout组件标识 */
|
||||
/**
|
||||
* Layout组件标识
|
||||
*/
|
||||
public final static String LAYOUT = "Layout";
|
||||
|
||||
/** ParentView组件标识 */
|
||||
/**
|
||||
* ParentView组件标识
|
||||
*/
|
||||
public final static String PARENT_VIEW = "ParentView";
|
||||
|
||||
/** InnerLink组件标识 */
|
||||
/**
|
||||
* InnerLink组件标识
|
||||
*/
|
||||
public final static String INNER_LINK = "InnerLink";
|
||||
|
||||
/** 校验是否唯一的返回标识 */
|
||||
/**
|
||||
* 校验是否唯一的返回标识
|
||||
*/
|
||||
public final static boolean UNIQUE = true;
|
||||
public final static boolean NOT_UNIQUE = false;
|
||||
|
||||
|
|
@ -122,4 +155,28 @@ public class UserConstants
|
|||
* 项目管理-知识库管理权限
|
||||
*/
|
||||
public static final String PMS_PERMS_DOCS_MANAGE = "pms:docs:manage";
|
||||
/**
|
||||
* 文章管理-文章删除权限
|
||||
*/
|
||||
public static final String CMS_PERMS_DOCS_DELETE = "cms:doc:remove";
|
||||
/**
|
||||
* 文章管理-新增文章权限
|
||||
*/
|
||||
public static final String CMS_PERMS_DOCS_ADD = "cms:doc:add";
|
||||
/**
|
||||
* 文章管理-编辑文章权限
|
||||
*/
|
||||
public static final String CMS_PERMS_DOCS_EDIT = "cms:doc:edit";
|
||||
/**
|
||||
* 文章管理-审核文章权限
|
||||
*/
|
||||
public static final String CMS_PERMS_DOCS_AUDIT = "cms:doc:audit";
|
||||
/**
|
||||
* 专区管理-审核项目权限
|
||||
*/
|
||||
public static final String ZONE_PERMS_PROJECT_AUDIT = "zone:project:audit";
|
||||
/**
|
||||
* 专区管理-审核资源权限
|
||||
*/
|
||||
public static final String ZONE_PERMS_RESOURCE_AUDIT = "zone:resource:audit";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ package com.microservices.common.core.enums;
|
|||
public enum DocAndZoneOperation
|
||||
{
|
||||
OPERATION_CREATE("创建", "create"), OPERATION_UPDATE("更新", "update"),
|
||||
OPERATION_DELETE("删除", "delete");
|
||||
OPERATION_DELETE("删除", "delete"), OPERATION_NON_REPO_UPDATE("非仓库更新", "nonRepoUpdate");
|
||||
|
||||
private final String operationName;
|
||||
private final String operationCode;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.microservices.common.core.threadPool;
|
||||
|
||||
import com.microservices.common.core.constant.TokenConstants;
|
||||
import com.microservices.common.core.context.SecurityContextHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -38,9 +37,6 @@ public class ThreadPoolExecutorWrap extends ThreadPoolExecutor {
|
|||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if(contextValue != null&&contextValue.containsKey("user_key")){
|
||||
contextValue.put(TokenConstants.AUTHENTICATION, contextValue.get("user_key"));
|
||||
}
|
||||
SecurityContextHolder.setLocalMap(contextValue);
|
||||
// 用户任务逻辑
|
||||
task.run();
|
||||
|
|
|
|||
|
|
@ -13,19 +13,17 @@ import com.microservices.common.core.utils.reflect.ReflectUtils;
|
|||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.RegExUtils;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
import org.apache.poi.hssf.usermodel.*;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
||||
import org.apache.poi.xssf.usermodel.*;
|
||||
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
|
||||
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
|
|
@ -1460,288 +1458,4 @@ public class ExcelUtil<T>
|
|||
}
|
||||
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(value = "面包屑数据",hidden = true)
|
||||
@ApiModelProperty("面包屑数据")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL) //为空时隐藏
|
||||
private List<Breadcrumb> breadcrumb;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,8 @@
|
|||
package com.microservices.common.httpClient.config;
|
||||
|
||||
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.HttpClients;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -16,13 +11,7 @@ import org.springframework.beans.factory.annotation.Value;
|
|||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* HttpClient 配置类
|
||||
* 支持 HTTPS 和连接池管理,包含自动连接清理机制
|
||||
*
|
||||
* @author admin
|
||||
* @date 2017/2/6
|
||||
*/
|
||||
|
|
@ -31,131 +20,74 @@ public class HttpClientConfiguration {
|
|||
|
||||
private static final Logger logger = LoggerFactory.getLogger(HttpClientConfiguration.class);
|
||||
|
||||
@Value("${http.maxTotal:100}")
|
||||
@Value("${http.maxTotal}")
|
||||
private Integer maxTotal;
|
||||
|
||||
@Value("${http.defaultMaxPerRoute:20}")
|
||||
@Value("${http.defaultMaxPerRoute}")
|
||||
private Integer defaultMaxPerRoute;
|
||||
|
||||
@Value("${http.connectTimeout:10000}")
|
||||
@Value("${http.connectTimeout}")
|
||||
private Integer connectTimeout;
|
||||
|
||||
@Value("${http.connectionRequestTimeout:5000}")
|
||||
@Value("${http.connectionRequestTimeout}")
|
||||
private Integer connectionRequestTimeout;
|
||||
|
||||
@Value("${http.socketTimeout:30000}")
|
||||
@Value("${http.socketTimeout}")
|
||||
private Integer socketTimeout;
|
||||
|
||||
@Value("${http.staleConnectionCheckEnabled:true}")
|
||||
@Value("${http.staleConnectionCheckEnabled}")
|
||||
private boolean staleConnectionCheckEnabled;
|
||||
|
||||
private PoolingHttpClientConnectionManager connectionManager;
|
||||
|
||||
/**
|
||||
* 创建支持 HTTPS 的连接池管理器
|
||||
* 使用自定义的 SSL 配置来避免 "peer not authenticated" 错误
|
||||
* 首先实例化一个连接池管理器,设置最大连接数、并发连接数
|
||||
*
|
||||
* @return PoolingHttpClientConnectionManager
|
||||
* @return
|
||||
*/
|
||||
@Bean(name = "httpClientConnectionManager")
|
||||
public PoolingHttpClientConnectionManager getHttpClientConnectionManager() {
|
||||
try {
|
||||
// 创建 SSLConnectionSocketFactory
|
||||
SSLConnectionSocketFactory sslSocketFactory = SSLContextFactory.createSSLConnectionSocketFactory();
|
||||
|
||||
// 注册 HTTP 和 HTTPS 的 SocketFactory
|
||||
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);
|
||||
}
|
||||
PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager();
|
||||
//最大连接数
|
||||
httpClientConnectionManager.setMaxTotal(maxTotal);
|
||||
//并发数
|
||||
httpClientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
|
||||
return httpClientConnectionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 HttpClientBuilder
|
||||
* 配置重试机制和连接管理策略
|
||||
* 实例化连接池,设置连接池管理器。
|
||||
* 这里需要以参数形式注入上面实例化的连接池管理器
|
||||
*
|
||||
* @param httpClientConnectionManager 连接池管理器
|
||||
* @return HttpClientBuilder
|
||||
* @param httpClientConnectionManager
|
||||
* @return
|
||||
*/
|
||||
@Bean(name = "httpClientBuilder")
|
||||
public org.apache.http.impl.client.HttpClientBuilder getHttpClientBuilder(
|
||||
@Qualifier("httpClientConnectionManager") PoolingHttpClientConnectionManager httpClientConnectionManager) {
|
||||
public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager") PoolingHttpClientConnectionManager httpClientConnectionManager) {
|
||||
|
||||
org.apache.http.impl.client.HttpClientBuilder builder = HttpClients.custom()
|
||||
.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);
|
||||
//HttpClientBuilder中的构造方法被protected修饰,所以这里不能直接使用new来实例化一个HttpClientBuilder,可以使用HttpClientBuilder提供的静态方法create()来获取HttpClientBuilder对象
|
||||
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
|
||||
httpClientBuilder.setConnectionManager(httpClientConnectionManager);
|
||||
|
||||
logger.info("HttpClientBuilder 配置完成 - 重试机制: 启用(最多2次), 连接存活时间: 60秒");
|
||||
return builder;
|
||||
return httpClientBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 CloseableHttpClient 实例
|
||||
* 注入连接池,用于获取httpClient
|
||||
*
|
||||
* @param httpClientBuilder HttpClientBuilder
|
||||
* @return CloseableHttpClient
|
||||
* @param httpClientBuilder
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public CloseableHttpClient getCloseableHttpClient(
|
||||
@Qualifier("httpClientBuilder") org.apache.http.impl.client.HttpClientBuilder httpClientBuilder) {
|
||||
|
||||
CloseableHttpClient httpClient = httpClientBuilder.build();
|
||||
|
||||
// 启动连接池清理后台线程
|
||||
startConnectionMonitorThread();
|
||||
|
||||
logger.info("CloseableHttpClient 创建成功");
|
||||
return httpClient;
|
||||
public CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder) {
|
||||
return httpClientBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 RequestConfig.Builder
|
||||
* Builder是RequestConfig的一个内部类
|
||||
* 通过RequestConfig的custom方法来获取到一个Builder对象
|
||||
* 设置builder的连接信息
|
||||
* 这里还可以设置proxy,cookieSpec等属性。有需要的话可以在此设置
|
||||
*
|
||||
* @return RequestConfig.Builder
|
||||
* @return
|
||||
*/
|
||||
@Bean(name = "builder")
|
||||
public RequestConfig.Builder getBuilder() {
|
||||
|
|
@ -167,78 +99,14 @@ public class HttpClientConfiguration {
|
|||
}
|
||||
|
||||
/**
|
||||
* 创建 RequestConfig
|
||||
* 使用builder构建一个RequestConfig对象
|
||||
*
|
||||
* @param builder RequestConfig.Builder
|
||||
* @return RequestConfig
|
||||
* @param builder
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder) {
|
||||
RequestConfig config = builder.build();
|
||||
logger.info("RequestConfig 配置完成 - 连接超时: {}ms, 请求超时: {}ms, Socket超时: {}ms, 陈旧连接检查: {}",
|
||||
connectTimeout, connectionRequestTimeout, socketTimeout, staleConnectionCheckEnabled);
|
||||
return config;
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动连接池监控和清理线程
|
||||
* 定期清理过期和空闲连接,防止使用已关闭的连接
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,140 +0,0 @@
|
|||
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];
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -211,6 +211,17 @@ public class HttpAPIService {
|
|||
return doRequest(httpDelete, headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 不带Header的get请求
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public JSONObject doGet(String url) throws Exception {
|
||||
return doGet(url, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 带Header的get请求
|
||||
*
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
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.util.GitLinkRequestHelper.RequestType.GET;
|
||||
|
|
@ -80,75 +79,44 @@ public class GitLinkRequestHelper {
|
|||
HashMap<String, String> headers = prepareAuthenticationHeaders(gitLinkRequestUrl);
|
||||
String requestId = UUID.randomUUID().toString();
|
||||
String path = gitLinkRequestUrl.getPath();
|
||||
logger.debug("[{}]通过HttpClient向平台发起请求,请求方法为:{},请求网站为:{},请求路由为:{},请求载体为:{},请求头为:{}"
|
||||
logger.info("[{}]通过HttpClient向平台发起请求,请求方法为:{},请求网站为:{},请求路由为:{},请求载体为:{},请求头为:{}"
|
||||
, requestId
|
||||
, requestType
|
||||
, gitLinkUrl
|
||||
, path
|
||||
, object
|
||||
, headers);
|
||||
JSONObject result = null;
|
||||
Exception lastException = null;
|
||||
|
||||
// 业务层重试机制:针对 SSL 握手失败等偶发性错误
|
||||
int maxRetries = 2;
|
||||
for (int attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
String requestURL = EscapeUtil.removeExtraSlashOfUrl(gitLinkUrl + path.replace(" ", "%20"));
|
||||
switch (requestType) {
|
||||
case POST:
|
||||
result = httpAPIService.doPost(requestURL, (JSONObject) object, headers);
|
||||
break;
|
||||
case POST_FILE:
|
||||
result = httpAPIService.doPostFile(requestURL, (MultipartFile) object, headers);
|
||||
break;
|
||||
case DELETE:
|
||||
result = httpAPIService.doDelete(requestURL, (JSONObject) object, headers);
|
||||
break;
|
||||
case GET:
|
||||
result = httpAPIService.doGet(requestURL, headers);
|
||||
break;
|
||||
case PUT:
|
||||
result = httpAPIService.doPut(requestURL, (JSONObject) object, headers);
|
||||
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);
|
||||
JSONObject result;
|
||||
try {
|
||||
String requestURL = EscapeUtil.removeExtraSlashOfUrl(gitLinkUrl + path.replace(" ", "%20"));
|
||||
switch (requestType) {
|
||||
case POST:
|
||||
result = httpAPIService.doPost(requestURL, (JSONObject) object, headers);
|
||||
break;
|
||||
case POST_FILE:
|
||||
result = httpAPIService.doPostFile(requestURL, (MultipartFile) object, headers);
|
||||
break;
|
||||
case DELETE:
|
||||
result = httpAPIService.doDelete(requestURL, (JSONObject) object, headers);
|
||||
break;
|
||||
case GET:
|
||||
result = httpAPIService.doGet(requestURL, headers);
|
||||
break;
|
||||
case PUT:
|
||||
result = httpAPIService.doPut(requestURL, (JSONObject) object, headers);
|
||||
break;
|
||||
case PATCH:
|
||||
result = httpAPIService.doPatch(requestURL, (JSONObject) object, headers);
|
||||
break;
|
||||
default:
|
||||
throw new ServiceException("不支持该请求方式:" + requestType.name());
|
||||
}
|
||||
logger.info("[{}]请求响应为:{}"
|
||||
, requestId
|
||||
, result);
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("请求平台出现错误:" + e.getMessage());
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
throw new ServiceException("请求平台时,未返回内容");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,12 +34,6 @@
|
|||
<artifactId>microservices-common-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Sentinel -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -115,8 +115,7 @@ public class AuthLogic {
|
|||
* @param permission 权限字符串
|
||||
* @return 用户是否具备某权限
|
||||
*/
|
||||
public boolean hasPermi(String permission)
|
||||
{
|
||||
public boolean hasPermi(String permission) {
|
||||
return hasPermi(tokenService.getMenuPermissions(), permission);
|
||||
}
|
||||
|
||||
|
|
@ -126,10 +125,8 @@ public class AuthLogic {
|
|||
* @param permission 权限字符串
|
||||
* @return 用户是否具备某权限
|
||||
*/
|
||||
public void checkPermi(String permission)
|
||||
{
|
||||
if (!hasPermi(tokenService.getMenuPermissions(), permission))
|
||||
{
|
||||
public void checkPermi(String permission) {
|
||||
if (!hasPermi(tokenService.getMenuPermissions(), permission)) {
|
||||
throw new NotPermissionException(permission);
|
||||
}
|
||||
}
|
||||
|
|
@ -153,13 +150,10 @@ public class AuthLogic {
|
|||
*
|
||||
* @param permissions 权限列表
|
||||
*/
|
||||
public void checkPermiAnd(String... permissions)
|
||||
{
|
||||
public void checkPermiAnd(String... permissions) {
|
||||
Set<String> permissionList = tokenService.getMenuPermissions();
|
||||
for (String permission : permissions)
|
||||
{
|
||||
if (!hasPermi(permissionList, permission))
|
||||
{
|
||||
for (String permission : permissions) {
|
||||
if (!hasPermi(permissionList, permission)) {
|
||||
throw new NotPermissionException(permission);
|
||||
}
|
||||
}
|
||||
|
|
@ -170,13 +164,10 @@ public class AuthLogic {
|
|||
*
|
||||
* @param permissions 权限码数组
|
||||
*/
|
||||
public void checkPermiOr(String... permissions)
|
||||
{
|
||||
public void checkPermiOr(String... permissions) {
|
||||
Set<String> permissionList = tokenService.getMenuPermissions();
|
||||
for (String permission : permissions)
|
||||
{
|
||||
if (hasPermi(permissionList, permission))
|
||||
{
|
||||
for (String permission : permissions) {
|
||||
if (hasPermi(permissionList, permission)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -191,8 +182,7 @@ public class AuthLogic {
|
|||
* @param role 角色标识
|
||||
* @return 用户是否具备某角色
|
||||
*/
|
||||
public boolean hasRole(String role)
|
||||
{
|
||||
public boolean hasRole(String role) {
|
||||
return hasRole(tokenService.getRolePermissions(), role);
|
||||
}
|
||||
|
||||
|
|
@ -225,13 +215,10 @@ public class AuthLogic {
|
|||
*
|
||||
* @param roles 角色标识数组
|
||||
*/
|
||||
public void checkRoleAnd(String... roles)
|
||||
{
|
||||
public void checkRoleAnd(String... roles) {
|
||||
Set<String> roleList = tokenService.getRolePermissions();
|
||||
for (String role : roles)
|
||||
{
|
||||
if (!hasRole(roleList, role))
|
||||
{
|
||||
for (String role : roles) {
|
||||
if (!hasRole(roleList, role)) {
|
||||
throw new NotRoleException(role);
|
||||
}
|
||||
}
|
||||
|
|
@ -242,18 +229,14 @@ public class AuthLogic {
|
|||
*
|
||||
* @param roles 角色标识数组
|
||||
*/
|
||||
public void checkRoleOr(String... roles)
|
||||
{
|
||||
public void checkRoleOr(String... roles) {
|
||||
Set<String> roleList = tokenService.getRolePermissions();
|
||||
for (String role : roles)
|
||||
{
|
||||
if (hasRole(roleList, role))
|
||||
{
|
||||
for (String role : roles) {
|
||||
if (hasRole(roleList, role)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (roles.length > 0)
|
||||
{
|
||||
if (roles.length > 0) {
|
||||
throw new NotRoleException(roles);
|
||||
}
|
||||
}
|
||||
|
|
@ -323,6 +306,9 @@ public class AuthLogic {
|
|||
public boolean hasUserIdentity(Long deptId, String roleKey) {
|
||||
LoginUser loginUser = getLoginUser();
|
||||
List<SysUserDeptRole> sysUserDeptRoleList = tokenService.getAllUserIdentity(loginUser.getUsername());
|
||||
if (sysUserDeptRoleList == null) {
|
||||
return false;
|
||||
}
|
||||
return sysUserDeptRoleList.stream()
|
||||
.anyMatch(x -> {
|
||||
if (x.getDeptId() != null && x.getSysRole() != null && x.getDeptId().equals(deptId)) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.microservices.common.security.feign;
|
|||
import feign.RequestInterceptor;
|
||||
import feign.codec.Encoder;
|
||||
import feign.form.FormEncoder;
|
||||
import feign.form.spring.SpringFormEncoder;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
|
|
@ -34,6 +33,6 @@ public class FeignAutoConfiguration
|
|||
// 重要的是返回类型要是 Encoder 并且实现类必须是 FormEncoder 或者其子类
|
||||
@Bean
|
||||
public Encoder feignFormEncoder() {
|
||||
return new SpringFormEncoder(new SpringEncoder(messageConverters));
|
||||
return new FormEncoder(new SpringEncoder(messageConverters));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
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));
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import com.microservices.common.core.utils.uuid.IdUtils;
|
|||
import com.microservices.common.redis.service.RedisService;
|
||||
import com.microservices.common.security.interceptor.HeaderInterceptor;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.system.api.RemoteDeptService;
|
||||
import com.microservices.system.api.RemoteUserService;
|
||||
import com.microservices.system.api.domain.SysRole;
|
||||
import com.microservices.system.api.domain.SysUser;
|
||||
|
|
@ -38,6 +39,8 @@ public class TokenService {
|
|||
private RedisService redisService;
|
||||
@Autowired
|
||||
private RemoteUserService remoteUserService;
|
||||
@Autowired
|
||||
private RemoteDeptService remoteDeptService;
|
||||
|
||||
protected static final long MILLIS_SECOND = 1000;
|
||||
|
||||
|
|
@ -329,4 +332,16 @@ public class TokenService {
|
|||
}
|
||||
return loginUser.getSysUser();
|
||||
}
|
||||
|
||||
public Boolean hasDeptPerms(Long deptId, String perms) {
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
Boolean hasPerms = FeignUtils.getReturnData(
|
||||
remoteDeptService.checkUserInDeptOrParentDeptHasPerms(deptId, loginUser.getUserId(), perms, SecurityConstants.INNER)
|
||||
);
|
||||
|
||||
if (hasPerms == null) {
|
||||
hasPerms = false;
|
||||
}
|
||||
return hasPerms;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,4 +4,3 @@ com.microservices.common.security.service.impl.RequestCustomServiceImpl
|
|||
com.microservices.common.security.aspect.PreAuthorizeAspect
|
||||
com.microservices.common.security.aspect.InnerAuthAspect
|
||||
com.microservices.common.security.handler.GlobalExceptionHandler
|
||||
com.microservices.common.security.handler.SentinelBlockExceptionHandler
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ public class AuthFilter implements GlobalFilter, Ordered {
|
|||
try {
|
||||
claims = JwtUtils.parseToken(token);
|
||||
} catch (Exception e) {
|
||||
log.error("[鉴权异常处理]令牌解析失败:{}", e.getMessage());
|
||||
log.error("令牌解析失败:{}", e.getMessage());
|
||||
return unauthorizedResponse(exchange, "令牌格式不正确!");
|
||||
}
|
||||
if (claims == null) {
|
||||
|
|
@ -139,7 +139,7 @@ public class AuthFilter implements GlobalFilter, Ordered {
|
|||
);
|
||||
redisService.setCacheObject(redisKey, feignResult);
|
||||
} 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);
|
||||
} catch (Exception e) {
|
||||
log.error("[鉴权异常处理]检查该token【{}】是否登录时发生异常:{}", token, e.getMessage());
|
||||
log.error("检查该gitlink token【{}】是否登录时发生异常:{}", token, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -215,11 +215,11 @@ public class AuthFilter implements GlobalFilter, Ordered {
|
|||
try {
|
||||
feignResult = future.get();
|
||||
} catch (Exception e) {
|
||||
log.error("[鉴权异常处理]异步请求获取本系统Token出错:{}", e.getMessage());
|
||||
log.error("异步请求获取本系统Token出错:{}", e.getMessage());
|
||||
throw new ServiceException("内部服务错误");
|
||||
}
|
||||
if (StringUtils.isNull(feignResult) || R.FAIL == feignResult.getCode()) {
|
||||
log.error("[鉴权异常处理]Token获取出错:{}", feignResult.getMsg());
|
||||
log.error("Token获取出错:{}", feignResult.getMsg());
|
||||
throw new ServiceException("内部服务错误");
|
||||
}
|
||||
if (R.SUCCESS == feignResult.getCode()) {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
|||
String lowerUrl = request.getURI().getPath().toLowerCase();
|
||||
ServerHttpResponse originalResponse = exchange.getResponse();
|
||||
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
|
||||
|
||||
// 当请求为Nacos时,Nacos返回的所有非JSON响应都会被自动转换为结构化的错误信息,同时将HTTP状态码设置为200,适合用于规范化微服务架构的响应格式。
|
||||
if (lowerUrl.startsWith("/nacos")) {
|
||||
|
||||
|
|
@ -54,7 +53,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
|||
return super.writeWith(body);
|
||||
}
|
||||
if (status == HttpStatus.FORBIDDEN) {
|
||||
log.error("[网关转发异常处理]nacos鉴权异常,已清理redis中nacos token");
|
||||
log.error("nacos鉴权异常,已清理redis中nacos token");
|
||||
// 设置新的状态码为 200
|
||||
setStatusCode(HttpStatus.OK);
|
||||
// 设置响应内容类型为 JSON
|
||||
|
|
@ -126,7 +125,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
|||
}
|
||||
synchronousSink.complete();
|
||||
}).flatMap(resStr -> {
|
||||
log.error("[网关转发异常处理]Portainer响应处理异常,异常信息:{}", resStr);
|
||||
log.error("Portainer响应处理异常,异常信息:{}", resStr);
|
||||
originalResponse.setStatusCode(HttpStatus.OK);
|
||||
byte[] bytes;
|
||||
if (JSON.isValid(resStr)) {
|
||||
|
|
@ -134,7 +133,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
|||
if (resJson.containsKey("message")) {
|
||||
String message = resJson.getString("message");
|
||||
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缓存
|
||||
redisService.deleteObject(CacheConstants.PORTAINER_TOKEN);
|
||||
bytes = JSON.toJSONBytes(AjaxResult.error(ExceptionMsgConstants.RETRY_ERROR));
|
||||
|
|
@ -161,12 +160,12 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
|||
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
|
||||
@Override
|
||||
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
|
||||
HttpStatus status = getStatusCode();
|
||||
HttpStatus status = getStatusCode() != null ? getStatusCode() : HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
if (!status.isError()) {
|
||||
return super.writeWith(body);
|
||||
}
|
||||
if (status == HttpStatus.UNAUTHORIZED) {
|
||||
log.error("[网关转发异常处理]sentinel鉴权异常,已清理redis中sentinel token");
|
||||
log.error("sentinel鉴权异常,已清理redis中sentinel token");
|
||||
// 设置新的状态码为 200
|
||||
setStatusCode(HttpStatus.OK);
|
||||
// 设置响应内容类型为 JSON
|
||||
|
|
@ -193,7 +192,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
|||
}
|
||||
synchronousSink.complete();
|
||||
}).flatMap(resStr -> {
|
||||
log.error("[网关转发异常处理]Sentinel响应处理异常,异常信息:{}", resStr);
|
||||
log.error("Sentinel响应处理异常,异常信息:{}", resStr);
|
||||
byte[] bytes;
|
||||
bytes = JSON.toJSONBytes(AjaxResult.error(ExceptionMsgConstants.SYSTEM_EXEC_ERROR));
|
||||
setStatusCode(HttpStatus.OK);
|
||||
|
|
|
|||
|
|
@ -53,14 +53,8 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
public String portainerUsername;
|
||||
@Value("${thirdPartyTools.portainer.auth.password:}")
|
||||
public String portainerPassword;
|
||||
@Value("${thirdPartyTools.rancher.auth.username:}")
|
||||
public String rancherUsername;
|
||||
@Value("${thirdPartyTools.rancher.auth.password:}")
|
||||
public String rancherPassword;
|
||||
@Value("${thirdPartyTools.portainer.endpoints:}")
|
||||
public Integer portainerEndpoints;
|
||||
@Value("${thirdPartyTools.retryTimes:1}")
|
||||
public Integer retryTimes;
|
||||
ThreadPoolExecutor threadPoolExecutor = CustomExecutorFactory.threadPoolExecutor;
|
||||
@Lazy
|
||||
@Autowired
|
||||
|
|
@ -89,81 +83,27 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
if (redisService.hasKey(CacheConstants.SENTINEL_TOKEN)) {
|
||||
sentinelCookie = redisService.getCacheObject(CacheConstants.SENTINEL_TOKEN);
|
||||
} else {
|
||||
for (int i = 0; i < retryTimes; i++) {
|
||||
// 网关采用异步架构,所以此处需要通过异步请求获取Sentinel Token
|
||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginSentinel(sentinelUsername, sentinelPassword));
|
||||
try {
|
||||
Response response = future.get(3, TimeUnit.SECONDS);
|
||||
Map<String, Collection<String>> header = response.headers();
|
||||
if (header != null && header.containsKey("set-cookie")) {
|
||||
sentinelCookie = header.get("set-cookie").iterator().next();
|
||||
//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());
|
||||
// 网关采用异步架构,所以此处需要通过异步请求获取Sentinel Token
|
||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginSentinel(sentinelUsername, sentinelPassword));
|
||||
try {
|
||||
Response response = future.get(1, TimeUnit.SECONDS);
|
||||
Map<String, Collection<String>> header = response.headers();
|
||||
if (header != null && header.containsKey("set-cookie")) {
|
||||
sentinelCookie = header.get("set-cookie").iterator().next();
|
||||
//Sentinel登录状态默认30分钟失效,将Sentinel Token缓存过期时间调整为28分钟
|
||||
redisService.setCacheObject(CacheConstants.SENTINEL_TOKEN, sentinelCookie, 28L, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(sentinelCookie)) {
|
||||
break;
|
||||
}
|
||||
|
||||
log.warn("[网关转发异常处理]获取Sentinel Token失败,进行第{}次重试中", i + 1);
|
||||
} catch (TimeoutException e) {
|
||||
log.error("获取Sentinel Token超时");
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
log.error("获取Sentinel Token失败:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(sentinelCookie)) {
|
||||
ServletUtils.removeHeader(mutate, TokenConstants.Cookie);
|
||||
mutate.header(TokenConstants.Cookie, String.format("%s;%s;", cookie, sentinelCookie));
|
||||
} else {
|
||||
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失败");
|
||||
throw new ServiceException("Sentinel服务获取Token失败");
|
||||
}
|
||||
}
|
||||
// 处理Nacos请求
|
||||
|
|
@ -172,44 +112,38 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
if (redisService.hasKey(CacheConstants.NACOS_TOKEN)) {
|
||||
nacosToken = redisService.getCacheObject(CacheConstants.NACOS_TOKEN);
|
||||
} else {
|
||||
for (int i = 0; i < retryTimes; i++) {
|
||||
Map<String, String> nacosMap = new HashMap<>();
|
||||
nacosMap.put("username", nacosUsername);
|
||||
nacosMap.put("password", nacosPassword);
|
||||
// 网关采用异步架构,所以此处需要通过异步请求获取Nacos Token
|
||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginNacos(nacosMap));
|
||||
try {
|
||||
Response res = future.get(3, TimeUnit.SECONDS);
|
||||
StringWriter writer = new StringWriter();
|
||||
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
|
||||
String str = writer.toString();
|
||||
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());
|
||||
Map<String, String> nacosMap = new HashMap<>();
|
||||
nacosMap.put("username", nacosUsername);
|
||||
nacosMap.put("password", nacosPassword);
|
||||
// 网关采用异步架构,所以此处需要通过异步请求获取Nacos Token
|
||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginNacos(nacosMap));
|
||||
try {
|
||||
Response res = future.get(1, TimeUnit.SECONDS);
|
||||
StringWriter writer = new StringWriter();
|
||||
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
|
||||
String str = writer.toString();
|
||||
if (!JSON.isValid(str)) {
|
||||
return exceptionResponse(exchange, str, res.status());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(nacosToken)) {
|
||||
break;
|
||||
JSONObject resJsonObject = JSONObject.parseObject(str);
|
||||
if (resJsonObject == null) {
|
||||
return exceptionResponse(exchange, str, res.status());
|
||||
}
|
||||
log.warn("[网关转发异常处理]获取Nacos Token失败,进行第{}次重试中", i + 1);
|
||||
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());
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotEmpty(nacosToken)) {
|
||||
mutate.header(TokenConstants.Nacos_Token_Key, nacosToken);
|
||||
} else {
|
||||
throw new ServiceException("[网关转发异常处理]Nacos服务获取Token失败");
|
||||
throw new ServiceException("Nacos服务获取Token失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -229,7 +163,7 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
try {
|
||||
mutate.uri(new URI(url));
|
||||
} catch (URISyntaxException e) {
|
||||
log.error("[网关转发异常处理]替换Portainer请求中Endpoints时发生异常:{}", e.getMessage());
|
||||
log.error("替换Portainer请求中Endpoints时发生异常:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -244,44 +178,38 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
if (redisService.hasKey(CacheConstants.PORTAINER_TOKEN)) {
|
||||
portainerToken = redisService.getCacheObject(CacheConstants.PORTAINER_TOKEN);
|
||||
} else {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
// 网关采用异步架构,所以此处需要通过异步请求获取Portainer Token
|
||||
JSONObject loginPortainerBody = new JSONObject();
|
||||
loginPortainerBody.put("username", portainerUsername);
|
||||
loginPortainerBody.put("password", portainerPassword);
|
||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginPortainer(loginPortainerBody));
|
||||
try {
|
||||
Response res = future.get(1, TimeUnit.SECONDS);
|
||||
StringWriter writer = new StringWriter();
|
||||
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
|
||||
String str = writer.toString();
|
||||
if (!JSON.isValid(str)) {
|
||||
return exceptionResponse(exchange, str, res.status());
|
||||
}
|
||||
JSONObject resJsonObject = JSONObject.parseObject(str);
|
||||
portainerToken = resJsonObject.getString("jwt");
|
||||
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);
|
||||
JSONObject tokenBody = JSONObject.parseObject(tokenBodyStr);
|
||||
Long expiration = tokenBody.getLong("exp");
|
||||
Long now = new Date().getTime() / 1000;
|
||||
// 网关采用异步架构,所以此处需要通过异步请求获取Portainer Token
|
||||
JSONObject loginPortainerBody = new JSONObject();
|
||||
loginPortainerBody.put("username", portainerUsername);
|
||||
loginPortainerBody.put("password", portainerPassword);
|
||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginPortainer(loginPortainerBody));
|
||||
try {
|
||||
Response res = future.get(1, TimeUnit.SECONDS);
|
||||
StringWriter writer = new StringWriter();
|
||||
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
|
||||
String str = writer.toString();
|
||||
if (!JSON.isValid(str)) {
|
||||
return exceptionResponse(exchange, str, res.status());
|
||||
}
|
||||
JSONObject resJsonObject = JSONObject.parseObject(str);
|
||||
portainerToken = resJsonObject.getString("jwt");
|
||||
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);
|
||||
JSONObject tokenBody = JSONObject.parseObject(tokenBodyStr);
|
||||
Long expiration = tokenBody.getLong("exp");
|
||||
Long now = new Date().getTime() / 1000;
|
||||
|
||||
long portainerTokenTtl = expiration - now;
|
||||
if (portainerTokenTtl > 20) {
|
||||
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());
|
||||
long portainerTokenTtl = expiration - now;
|
||||
if (portainerTokenTtl > 20) {
|
||||
redisService.setCacheObject(CacheConstants.PORTAINER_TOKEN, portainerToken, portainerTokenTtl - 10, TimeUnit.SECONDS);
|
||||
}
|
||||
if (StringUtils.isNotEmpty(portainerToken)) {
|
||||
break;
|
||||
}
|
||||
log.warn("[网关转发异常处理]获取Portainer Token失败,进行第{}次重试中", i + 1);
|
||||
} catch (TimeoutException e) {
|
||||
log.error("获取Portainer Token超时");
|
||||
} catch (InterruptedException | ExecutionException | IOException | NullPointerException e) {
|
||||
log.error("获取Portainer Token失败:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotEmpty(portainerToken)) {
|
||||
|
|
@ -290,7 +218,7 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
mutate.header(TokenConstants.AUTHENTICATION, TokenConstants.PREFIX + portainerToken);
|
||||
mutate.header(TokenConstants.Cookie, String.format("%s;%s;", cookie, portainerToken));
|
||||
} else {
|
||||
throw new ServiceException("[网关转发异常处理]Portainer服务获取Token失败");
|
||||
throw new ServiceException("Portainer服务获取Token失败");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
@ -298,23 +226,7 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过指定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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.microservices.cms.doc.controller;
|
|||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.cms.doc.domain.*;
|
||||
import com.microservices.cms.doc.service.ICmsDocService;
|
||||
import com.microservices.common.core.constant.UserConstants;
|
||||
import com.microservices.common.core.domain.R;
|
||||
import com.microservices.common.core.web.controller.BaseController;
|
||||
import com.microservices.common.core.web.domain.AjaxResult;
|
||||
|
|
@ -17,6 +18,7 @@ import io.swagger.annotations.*;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -106,23 +108,13 @@ public class CmsDocController extends BaseController {
|
|||
@ApiImplicitParam(name = "pageNum", value = "当前记录起始索引", paramType = "query", dataType = "Integer"),
|
||||
@ApiImplicitParam(name = "pageSize", value = "每页显示记录数", paramType = "query", dataType = "Integer"),
|
||||
})
|
||||
public TableDataInfo docListByZone(
|
||||
public GenericsTableDataInfo<CmsDocAllDto> docListByZone(
|
||||
@ApiParam(name = "zoneId", value = "专区Id") @PathVariable("zoneId") Long zoneId
|
||||
, CmsDocSearchVo cmsDocSearchVo) {
|
||||
Long deptId = cmsDocService.getDeptIdByZoneId(zoneId);
|
||||
cmsDocSearchVo.setIsOpen(false);
|
||||
cmsDocSearchVo.setIsOpen(true);
|
||||
startPage();
|
||||
List<CmsDocAllDto> list = cmsDocService.selectCmsDocListByDept(deptId, cmsDocSearchVo);
|
||||
list.forEach(x -> {
|
||||
String docDetailUrl = cmsDocService.getDocDetailUrl(x.getDeptId(), x.getId());
|
||||
x.setDocDetailUrl(docDetailUrl);
|
||||
|
||||
Boolean editable = cmsDocService.isCmsDocEditable(x);
|
||||
x.setEditable(editable);
|
||||
|
||||
});
|
||||
int count = cmsDocService.selectCmsDocCountByDept(deptId, cmsDocSearchVo);
|
||||
return getDataTable(list, count);
|
||||
return cmsDocService.selectAllDocList(deptId, cmsDocSearchVo);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -164,7 +156,7 @@ public class CmsDocController extends BaseController {
|
|||
/**
|
||||
* 新增文章信息
|
||||
*/
|
||||
@RequiresPermissions("cms:doc:add")
|
||||
@RequiresPermissions(UserConstants.CMS_PERMS_DOCS_ADD)
|
||||
@Log(title = "文章信息", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/dir/{dirId}")
|
||||
@ApiOperation("在栏目下创建文章")
|
||||
|
|
@ -201,7 +193,7 @@ public class CmsDocController extends BaseController {
|
|||
/**
|
||||
* 删除文章
|
||||
*/
|
||||
@RequiresPermissions("cms:doc:remove")
|
||||
@RequiresPermissions(UserConstants.CMS_PERMS_DOCS_DELETE)
|
||||
@Log(title = "文章信息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
@ApiOperation("删除文章/栏目")
|
||||
|
|
@ -212,13 +204,13 @@ public class CmsDocController extends BaseController {
|
|||
/**
|
||||
* 修改文章信息
|
||||
*/
|
||||
@RequiresPermissions("cms:doc:edit")
|
||||
@RequiresPermissions(UserConstants.CMS_PERMS_DOCS_EDIT)
|
||||
@Log(title = "文章信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/{id}")
|
||||
@ApiOperation("更新文章")
|
||||
public AjaxResult edit(@ApiParam(name = "id", value = "文章Id") @PathVariable Long id,
|
||||
@ApiParam(name = "cmsDoc", value = "文章实体对象") @RequestBody CmsDocDto cmsDocDto) {
|
||||
return toAjax(cmsDocService.updateCmsDoc(id, cmsDocDto));
|
||||
return success(cmsDocService.updateCmsDoc(id, cmsDocDto));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -237,12 +229,12 @@ public class CmsDocController extends BaseController {
|
|||
/**
|
||||
* 审核文章信息
|
||||
*/
|
||||
@RequiresPermissions("cms:doc:audit")
|
||||
@RequiresPermissions(UserConstants.CMS_PERMS_DOCS_AUDIT)
|
||||
@Log(title = "文章信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/{id}/audit")
|
||||
@ApiOperation("审核文章")
|
||||
public AjaxResult audit(@ApiParam(name = "id", value = "文章Id") @PathVariable Long id,
|
||||
@ApiParam(name = "cmsDocAuditVo", value = "文章审核对象") @RequestBody CmsDocAuditVo cmsDocAuditVo) {
|
||||
@ApiParam(name = "cmsDocAuditVo", value = "文章审核对象") @RequestBody CmsDocAuditVo cmsDocAuditVo) {
|
||||
return toAjax(cmsDocService.auditCmsDoc(id, cmsDocAuditVo));
|
||||
}
|
||||
|
||||
|
|
@ -315,6 +307,24 @@ public class CmsDocController extends BaseController {
|
|||
return R.ok(cmsDocJSONObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部接口:首页文章合并列表(接收置顶文章 docId 有序列表,返回合并去重后的结果)
|
||||
* 供 Zone 服务 Feign 调用,用于 /open/getTopDoc 改造
|
||||
*/
|
||||
@InnerAuth
|
||||
@PostMapping("/homePageDocMergeList/{zoneId}")
|
||||
@ApiOperation(value = "首页文章合并列表", hidden = true)
|
||||
public R<List<JSONObject>> selectHomePageDocMergeList(
|
||||
@PathVariable("zoneId") Long zoneId,
|
||||
@RequestBody List<Long> topDocIds) {
|
||||
List<CmsDocBaseDto> list = cmsDocService.selectHomePageDocMergeList(zoneId, topDocIds);
|
||||
List<JSONObject> result = new ArrayList<>();
|
||||
for (CmsDocBaseDto dto : list) {
|
||||
result.add(JSONObject.from(dto));
|
||||
}
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过组织Id获取专区下文章阅读数量
|
||||
*
|
||||
|
|
|
|||
|
|
@ -5,12 +5,17 @@ import com.microservices.cms.doc.domain.*;
|
|||
import com.microservices.cms.doc.service.ICmsDocCommentService;
|
||||
import com.microservices.cms.doc.service.ICmsDocService;
|
||||
import com.microservices.cms.doc.service.ICmsWechatService;
|
||||
import com.microservices.cms.search.dto.DocSearchResult;
|
||||
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.common.core.web.page.TableDataInfo;
|
||||
import com.microservices.common.log.annotation.Log;
|
||||
import com.microservices.common.log.enums.BusinessType;
|
||||
import com.microservices.cms.search.dto.DocSearchRequest;
|
||||
import com.microservices.cms.search.dto.DocSearchResponse;
|
||||
import com.microservices.cms.search.service.IGlobalSearchService;
|
||||
import io.swagger.annotations.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
|
@ -35,6 +40,22 @@ public class OpenController extends BaseController {
|
|||
@Autowired
|
||||
private ICmsWechatService cmsWechatService;
|
||||
|
||||
@Autowired
|
||||
private IGlobalSearchService globalSearchService;
|
||||
|
||||
/**
|
||||
* 文章搜索接口
|
||||
*
|
||||
* @return 搜索结果
|
||||
*/
|
||||
@ApiOperation("文章搜索")
|
||||
@PostMapping("/search")
|
||||
public GenericsTableDataInfo<DocSearchResult> docSearch(@RequestBody DocSearchRequest docSearchRequest) {
|
||||
logger.info("文章搜索请求: keyword={}", docSearchRequest.getKeyword());
|
||||
DocSearchResponse response = globalSearchService.docSearch(docSearchRequest);
|
||||
return new GenericsTableDataInfo<>(response.getResults(), response.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询栏目列表
|
||||
*/
|
||||
|
|
@ -100,6 +121,19 @@ public class OpenController extends BaseController {
|
|||
return getAllGenericsDataTableToPage(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询文章列表(不区分栏目)
|
||||
*/
|
||||
@GetMapping("/zone/{zoneId}/allDocList")
|
||||
@ApiOperation("查询文章列表(不区分栏目)")
|
||||
public GenericsTableDataInfo<CmsDocAllDto> allDocList(@ApiParam(name = "zoneId", value = "专区Id") @PathVariable("zoneId") Long zoneId,
|
||||
CmsDocSearchVo cmsDocSearchVo) {
|
||||
Long deptId = cmsDocService.getDeptIdByZoneId(zoneId);
|
||||
cmsDocSearchVo.setIsOpen(true);
|
||||
startPage();
|
||||
return cmsDocService.selectAllDocList(deptId, cmsDocSearchVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询首页文章列表
|
||||
*/
|
||||
|
|
@ -175,9 +209,9 @@ public class OpenController extends BaseController {
|
|||
@Log(title = "同步文章数据", businessType = BusinessType.UPDATE)
|
||||
public AjaxResult syncDocData(
|
||||
@ApiParam(name = "deptId", value = "组织Id", required = true) @PathVariable("deptId") Long deptId
|
||||
,@RequestBody() String bodyStr
|
||||
, @RequestBody() String bodyStr
|
||||
, HttpServletRequest request) {
|
||||
cmsDocService.syncDocData(deptId,bodyStr);
|
||||
cmsDocService.syncDocData(deptId, bodyStr);
|
||||
return AjaxResult.success("同步消息发送成功");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.microservices.cms.doc.domain;
|
|||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.microservices.cms.utils.CmsConstants;
|
||||
import com.microservices.common.core.annotation.Excel;
|
||||
import com.microservices.common.core.utils.bean.BeanUtils;
|
||||
import com.microservices.common.core.web.domain.BaseSortEntity;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
|
@ -36,19 +37,27 @@ public class CmsDoc extends BaseSortEntity {
|
|||
@Excel(name = "文件名称")
|
||||
private String fileName;
|
||||
|
||||
/** 文件路径 */
|
||||
/**
|
||||
* 文件路径
|
||||
*/
|
||||
@Excel(name = "文件路径")
|
||||
private String filePath;
|
||||
|
||||
/** 文件SHA */
|
||||
/**
|
||||
* 文件SHA
|
||||
*/
|
||||
@Excel(name = "文件SHA")
|
||||
private String fileSha;
|
||||
|
||||
/** 文件大小 */
|
||||
/**
|
||||
* 文件大小
|
||||
*/
|
||||
@Excel(name = "文件大小")
|
||||
private Long fileSize;
|
||||
|
||||
/** 文件URL */
|
||||
/**
|
||||
* 文件URL
|
||||
*/
|
||||
@Excel(name = "文件URL")
|
||||
private String fileUrl;
|
||||
|
||||
|
|
@ -162,6 +171,11 @@ public class CmsDoc extends BaseSortEntity {
|
|||
*/
|
||||
private String keywords;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
public CmsDir copyToCmsDir() {
|
||||
CmsDir cmsDir = new CmsDir();
|
||||
cmsDir.setId(id);
|
||||
|
|
@ -189,7 +203,6 @@ public class CmsDoc extends BaseSortEntity {
|
|||
hotCmsDocDto.setName(name);
|
||||
hotCmsDocDto.setSummary(summary);
|
||||
hotCmsDocDto.setPublishTime(publishTime);
|
||||
hotCmsDocDto.setHeadImg(headImg);
|
||||
return hotCmsDocDto;
|
||||
}
|
||||
|
||||
|
|
@ -211,30 +224,12 @@ public class CmsDoc extends BaseSortEntity {
|
|||
}
|
||||
|
||||
private CmsDocBaseDto getCmsDocBaseDto(CmsDocBaseDto cmsDocDto) {
|
||||
cmsDocDto.setId(id);
|
||||
cmsDocDto.setName(name);
|
||||
cmsDocDto.setHeadImg(headImg);
|
||||
cmsDocDto.setIsHomepage(isHomepage);
|
||||
cmsDocDto.setSummary(summary);
|
||||
cmsDocDto.setEditorType(editorType);
|
||||
cmsDocDto.setDeptId(deptId);
|
||||
|
||||
BeanUtils.copyProperties(this, cmsDocDto);
|
||||
if (visits == null) {
|
||||
cmsDocDto.setVisits(0L);
|
||||
} else {
|
||||
cmsDocDto.setVisits(visits);
|
||||
}
|
||||
|
||||
cmsDocDto.setPublishTime(publishTime);
|
||||
cmsDocDto.setPublishUser(publishUser);
|
||||
cmsDocDto.setPublishUserUrl(publishUserUrl);
|
||||
cmsDocDto.setPublishUserImage(publishUserImage);
|
||||
cmsDocDto.setPublishUserNickname(publishUserNickname);
|
||||
cmsDocDto.setAuditStatus(auditStatus);
|
||||
cmsDocDto.setAuditType(auditType);
|
||||
cmsDocDto.setCreateBy(createBy);
|
||||
cmsDocDto.setKeywords(keywords);
|
||||
|
||||
return cmsDocDto;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,4 +20,10 @@ public class CmsDocAuditVo {
|
|||
*/
|
||||
@ApiModelProperty(value = "是否重新编辑: 0不允许重新编辑 1允许重新编辑")
|
||||
private Integer reedit;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ApiModelProperty(value = "审核备注")
|
||||
private String remark;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,10 @@ public class CmsDocBaseDto {
|
|||
*/
|
||||
@ApiModelProperty("关键词")
|
||||
private String keywords;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
public void setPublishTime(Date publishTime) {
|
||||
if (publishTime != null) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import lombok.Data;
|
|||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author otto
|
||||
|
|
@ -52,10 +51,6 @@ public class CmsDocInputDto {
|
|||
@ApiModelProperty("关键词")
|
||||
private String keywords;
|
||||
|
||||
@ApiModelProperty(value = "发布时间,隐藏参数,内部调用使用", hidden = true)
|
||||
private Date publishDate;
|
||||
|
||||
|
||||
public String getContent() {
|
||||
String base64decodedString;
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -83,4 +83,10 @@ public class CmsDocSearchVo {
|
|||
*/
|
||||
@ApiModelProperty("关键词")
|
||||
private String keywords;
|
||||
|
||||
/**
|
||||
* 排除文章Id
|
||||
*/
|
||||
@ApiModelProperty(value = "排除文章Id", hidden = true)
|
||||
private Long excludeId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package com.microservices.cms.doc.domain;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* CmsDoc with full-text search score
|
||||
* 用于全局搜索结果,包含全文搜索相关度评分
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class CmsDocWithScore extends CmsDoc implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 全文搜索相关度评分(来自 MySQL MATCH...AGAINST)
|
||||
*/
|
||||
private Double searchScore;
|
||||
}
|
||||
|
|
@ -33,6 +33,4 @@ public class HotCmsDocDto {
|
|||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@ApiModelProperty("发布时间")
|
||||
private Date publishTime;
|
||||
@ApiModelProperty(value = "文章头图")
|
||||
private String headImg;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.microservices.cms.doc.mapper;
|
|||
|
||||
import com.microservices.cms.doc.domain.CmsDoc;
|
||||
import com.microservices.cms.doc.domain.CmsDocSearchVo;
|
||||
import com.microservices.cms.doc.domain.CmsDocWithScore;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
|
|
@ -23,6 +24,14 @@ public interface CmsDocMapper {
|
|||
*/
|
||||
public CmsDoc selectCmsDocById(Long id);
|
||||
|
||||
/**
|
||||
* 批量查询文章信息
|
||||
*
|
||||
* @param ids 文章ID列表
|
||||
* @return 文章信息列表
|
||||
*/
|
||||
List<CmsDoc> selectCmsDocByIds(@Param("ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 查询文章信息列表
|
||||
*
|
||||
|
|
@ -82,6 +91,11 @@ public interface CmsDocMapper {
|
|||
|
||||
CmsDoc selectCmsDocByFilePathAndDeptId(@Param("filePath") String filePath, @Param("deptId") Long deptId);
|
||||
|
||||
/**
|
||||
* 按文章名+deptId查询(忽略dirName),用于Webhook防重判断
|
||||
*/
|
||||
CmsDoc selectCmsDocByNameAndDeptIdIgnoreDirName(@Param("name") String name, @Param("deptId") Long deptId);
|
||||
|
||||
List<CmsDoc> selectHotCmsDocList(CmsDoc cmsDocInput);
|
||||
|
||||
List<CmsDoc> selectCmsDocDirByDeptIdAndInName(@Param("deptId") Long deptId, @Param("cmsDirNameList") List<String> cmsDirNameList);
|
||||
|
|
@ -192,4 +206,41 @@ public interface CmsDocMapper {
|
|||
List<CmsDoc> selectCmsDocAndDirListByDept(Long deptId);
|
||||
|
||||
void updateCmsDocShaByPathAndDeptId(@Param("sha") String sha, @Param("filePath") String filePath, @Param("deptId") Long deptId);
|
||||
|
||||
/**
|
||||
* 全局搜索 - 全文索引查询
|
||||
*
|
||||
* @param keyword 搜索关键词
|
||||
* @param deptId 组织ID(可选)
|
||||
* @param offset 偏移量
|
||||
* @param pageSize 每页数量
|
||||
* @return 搜索结果列表
|
||||
*/
|
||||
List<CmsDoc> globalSearch(@Param("keyword") String keyword, @Param("deptId") Long deptId,
|
||||
@Param("offset") int offset, @Param("pageSize") int pageSize);
|
||||
|
||||
/**
|
||||
* 全局搜索结果计数
|
||||
*
|
||||
* @param keyword 搜索关键词
|
||||
* @param deptId 组织ID(可选)
|
||||
* @return 结果数量
|
||||
*/
|
||||
Long globalSearchCount(@Param("keyword") String keyword, @Param("deptId") Long deptId);
|
||||
|
||||
/**
|
||||
* 全局搜索 - 全文索引查询(含评分)
|
||||
*
|
||||
* @param keyword 搜索关键词
|
||||
* @param deptId 组织ID(可选)
|
||||
* @param offset 偏移量
|
||||
* @param pageSize 每页数量
|
||||
* @return 搜索结果列表(含评分)
|
||||
*/
|
||||
List<CmsDocWithScore> globalSearchWithScore(
|
||||
@Param("keyword") String keyword,
|
||||
@Param("deptId") Long deptId,
|
||||
@Param("offset") int offset,
|
||||
@Param("pageSize") int pageSize
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,4 +99,38 @@ public interface ICmsAsyncService {
|
|||
* @param cmsDoc 文章
|
||||
*/
|
||||
void pushDocDataSearchEngine(CmsDoc cmsDoc);
|
||||
|
||||
void clearTmpDoc(CmsProject cmsProject,List<CmsDoc> tmpDocList);
|
||||
|
||||
/**
|
||||
* 异步增加文章发布积分
|
||||
*
|
||||
* @param deptId 组织ID
|
||||
* @param createBy 创建人用户名
|
||||
* @param docId 文章ID
|
||||
* @param subjectDesc 文章标题
|
||||
*/
|
||||
void addPublishDocPointsAsync(Long deptId, String createBy, Long docId, String subjectDesc);
|
||||
|
||||
/**
|
||||
* 异步增加文章浏览积分(每满100次+2,上限50)
|
||||
*
|
||||
* @param deptId 组织ID
|
||||
* @param createBy 创建人用户名
|
||||
* @param docId 文章ID
|
||||
* @param docName 文章名称
|
||||
* @param totalVisits 累计阅读次数
|
||||
* @param pointsTriggerCount 当前第几次增加积分
|
||||
*/
|
||||
void addVisitsDocPointsAsync(Long deptId, String createBy, Long docId, String docName, Long totalVisits);
|
||||
|
||||
/**
|
||||
* 异步增加文章被设为精选的积分
|
||||
*
|
||||
* @param deptId 组织ID
|
||||
* @param createBy 创建人用户名
|
||||
* @param docId 文章ID
|
||||
* @param subjectDesc 文章标题
|
||||
*/
|
||||
void addFeaturedDocPointsAsync(Long deptId, String createBy, Long docId, String subjectDesc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.microservices.cms.doc.domain.*;
|
|||
import com.microservices.cms.doc.domain.gitlink.EntryDto;
|
||||
import com.microservices.cms.doc.domain.gitlink.FileEntryDto;
|
||||
import com.microservices.cms.project.domain.CmsProject;
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
|
@ -56,9 +57,9 @@ public interface ICmsDocService {
|
|||
*
|
||||
* @param id
|
||||
* @param cmsDocDto 文章信息
|
||||
* @return 结果
|
||||
* @return 结果 文章id
|
||||
*/
|
||||
public boolean updateCmsDoc(Long id, CmsDocDto cmsDocDto);
|
||||
public Long updateCmsDoc(Long id, CmsDocDto cmsDocDto);
|
||||
|
||||
/**
|
||||
* 批量删除文章信息
|
||||
|
|
@ -144,6 +145,15 @@ public interface ICmsDocService {
|
|||
*/
|
||||
List<CmsDocBaseDto> selectHomePageDocList(Long deptId);
|
||||
|
||||
/**
|
||||
* 查询首页文章合并列表(积分置顶文章 + 首页推荐文章,自动去重,置顶在前)
|
||||
*
|
||||
* @param zoneId 专区ID
|
||||
* @param topDocIds 置顶文章 docId 有序列表(前端按此顺序排列)
|
||||
* @return 合并后的首页文章列表(isTop=true 标识置顶文章)
|
||||
*/
|
||||
List<CmsDocBaseDto> selectHomePageDocMergeList(Long zoneId, List<Long> topDocIds);
|
||||
|
||||
/**
|
||||
* 初始化栏目
|
||||
*
|
||||
|
|
@ -198,6 +208,8 @@ public interface ICmsDocService {
|
|||
*/
|
||||
List<CmsDocAllDto> selectCmsDocListByDept(Long deptId, CmsDocSearchVo cmsDocSearchVo);
|
||||
|
||||
GenericsTableDataInfo<CmsDocAllDto> selectAllDocList(Long deptId, CmsDocSearchVo cmsDocSearchVo);
|
||||
|
||||
/**
|
||||
* 查询专区下文章数量
|
||||
*
|
||||
|
|
@ -294,4 +306,6 @@ public interface ICmsDocService {
|
|||
List<CmsDoc> selectCmsDocAndDirListByDept(Long deptId);
|
||||
|
||||
void updateCmsDocShaByPathAndDeptId(String sha, String filePath, Long deptId);
|
||||
|
||||
List<CmsDoc> getTmpDocList(CmsDoc cmsDoc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import com.microservices.cms.utils.CustomExecutorFactory;
|
|||
import com.microservices.common.core.constant.CacheConstants;
|
||||
import com.microservices.common.core.constant.Constants;
|
||||
import com.microservices.common.core.constant.SecurityConstants;
|
||||
import com.microservices.common.core.enums.DocAndZoneOperation;
|
||||
import com.microservices.common.core.enums.DocAuditStatus;
|
||||
import com.microservices.common.core.enums.SystemRole;
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.DateUtils;
|
||||
|
|
@ -33,6 +35,7 @@ import com.microservices.common.httpClient.util.GitLinkRequestHelper;
|
|||
import com.microservices.common.redis.service.RedisService;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.system.api.RemoteDeptService;
|
||||
import com.microservices.system.api.RemoteUserService;
|
||||
import com.microservices.system.api.RemoteZoneService;
|
||||
import com.microservices.system.api.utils.FeignUtils;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
|
|
@ -95,6 +98,8 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
@Autowired
|
||||
private RemoteZoneService remoteZoneService;
|
||||
@Autowired
|
||||
private RemoteUserService remoteUserService;
|
||||
@Autowired
|
||||
private RequestConfig config;
|
||||
|
||||
/**
|
||||
|
|
@ -251,7 +256,16 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
}
|
||||
CmsDoc cmsDoc = cmsDocMapper.selectCmsDocByNameAndDeptId(CmsUtils.getFileNameNoSuffix(entry.getName()), cmsProject.getDeptId(), dirName);
|
||||
if (cmsDoc == null) {
|
||||
syncCreateDoc(entry, dirName, cmsProject.getDeptId(), fileEntry.getLast_commit());
|
||||
// 防重:按文章名+deptId查一次,排除正在移动栏目的已有记录
|
||||
String docName = CmsUtils.getFileNameNoSuffix(entry.getName());
|
||||
CmsDoc existingDoc = cmsDocMapper.selectCmsDocByNameAndDeptIdIgnoreDirName(docName, cmsProject.getDeptId());
|
||||
if (existingDoc != null) {
|
||||
existingDoc.setDirName(dirName);
|
||||
existingDoc.setFilePath(dirName + "/" + existingDoc.getFileName());
|
||||
cmsDocMapper.updateCmsDoc(existingDoc);
|
||||
} else {
|
||||
syncCreateDoc(entry, dirName, cmsProject.getDeptId(), fileEntry.getLast_commit());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
|
@ -618,11 +632,12 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
100, "..."), tmpBranchName);
|
||||
} catch (ServiceException e) {
|
||||
//忽略重复创建PR异常
|
||||
if (!"请求GitLink失败(合并请求已存在)".equals(e.getMessage())) {
|
||||
if (!e.getMessage().contains("合并请求已存在")) {
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cmsDocService.updateCmsCommonDatabase(cmsDoc, tmpBranchName);
|
||||
}
|
||||
|
||||
|
|
@ -723,8 +738,8 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
|
||||
if (isChangeName || isChangeDir) {
|
||||
oldCmsDoc = renameAndChangeDirCmsDoc(oldCmsDoc, cmsProject, newName, newDirName, branchName);
|
||||
//todo 此处是否需要更新数据库待讨论
|
||||
//updateCmsCommonDatabase(oldCmsDoc);
|
||||
// 立即更新数据库中的dirName/filePath,避免GitLink Webhook回调时查不到记录导致重复INSERT
|
||||
cmsDocMapper.updateCmsDoc(oldCmsDoc);
|
||||
}
|
||||
|
||||
boolean isChangeContent = false;
|
||||
|
|
@ -1003,6 +1018,23 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTmpDoc(CmsProject cmsProject, List<CmsDoc> tmpDocList) {
|
||||
CustomExecutorFactory.threadPoolExecutor.execute(() -> {
|
||||
for (CmsDoc tmpDoc : tmpDocList) {
|
||||
//拒绝GitLink合并请求
|
||||
String gitLinkPullRequestNumber = tmpDoc.getAuditPrNumber().split("-")[0];
|
||||
gitLinkRequestHelper.doPost(
|
||||
CmsGitLinkRequestUrl.REFUSE_MERGE_PULL_REQUEST(cmsProject, gitLinkPullRequestNumber), null);
|
||||
gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, tmpDoc.getAuditTmpBranchName()), null);
|
||||
// 所有删除操作调整为将审核状态设置为已拒绝
|
||||
tmpDoc.setAuditStatus(DocAuditStatus.AUDIT_FAIL.getAuditCode());
|
||||
tmpDoc.setRemark("管理员删除");
|
||||
cmsDocMapper.updateCmsDoc(tmpDoc);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void moveCmsDocToNewCmsDir(CmsProject cmsProject, String oldDirName, String newDirName, String message) {
|
||||
CmsDocSearchVo cmsDocSearch = new CmsDocSearchVo();
|
||||
cmsDocSearch.setIsDir(false);
|
||||
|
|
@ -1055,4 +1087,127 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为积分部门
|
||||
*
|
||||
* @param deptId 部门ID
|
||||
* @return 是否为积分部门
|
||||
*/
|
||||
private boolean isPointsDept(Long deptId) {
|
||||
Long cachedPointsDeptId = redisService.getCacheObject(CacheConstants.ZONE_POINTS_DEPT_ID_KEY);
|
||||
return cachedPointsDeptId != null && cachedPointsDeptId > 0 && cachedPointsDeptId.equals(deptId);
|
||||
}
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public void addPublishDocPointsAsync(Long deptId, String createBy, Long docId, String subjectDesc) {
|
||||
try {
|
||||
if (deptId == null || createBy == null) {
|
||||
logger.warn("文章审核通过增加积分失败,deptId或createBy为空,docId={}", docId);
|
||||
return;
|
||||
}
|
||||
// 检查是否为积分部门
|
||||
if (!isPointsDept(deptId)) {
|
||||
logger.info("文章审核通过增加积分跳过,非积分部门,deptId={},docId={}", deptId, docId);
|
||||
return;
|
||||
}
|
||||
// 获取用户ID
|
||||
com.microservices.system.api.domain.SysUser sysUser = FeignUtils.getReturnData(
|
||||
remoteUserService.getSysUserByUserName(createBy, SecurityConstants.INNER));
|
||||
if (sysUser == null || sysUser.getUserId() == null) {
|
||||
logger.warn("文章审核通过增加积分失败,未找到用户信息,createBy={},docId={}", createBy, docId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 直接写入 Redis 积分队列,由 Zone 模块定时任务消费
|
||||
JSONObject task = new JSONObject();
|
||||
task.put("sourceType", CmsConstants.PUBLISH_DOC);
|
||||
task.put("userId", sysUser.getUserId());
|
||||
task.put("deptId", deptId);
|
||||
task.put("sourceId", docId);
|
||||
task.put("subjectDesc", subjectDesc);
|
||||
task.put("operatorId", sysUser.getUserId());
|
||||
redisService.leftPush(CmsConstants.ZONE_POINTS_ASYNC_QUEUE_KEY, task.toJSONString());
|
||||
logger.info("文章审核通过增加积分任务已写入队列,docId={},userId={},deptId={}", docId, sysUser.getUserId(), deptId);
|
||||
} catch (Exception e) {
|
||||
// 捕获异常,确保不影响主事务
|
||||
logger.error("文章审核通过增加积分异常,docId={}", docId, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public void addVisitsDocPointsAsync(Long deptId, String createBy, Long docId, String docName, Long totalVisits) {
|
||||
try {
|
||||
if (deptId == null || createBy == null) {
|
||||
logger.warn("文章浏览增加积分失败,参数不合法,deptId={},createBy={}", deptId, createBy);
|
||||
return;
|
||||
}
|
||||
// 检查是否为积分部门
|
||||
if (!isPointsDept(deptId)) {
|
||||
logger.info("文章浏览增加积分跳过,非积分部门,deptId={},docId={}", deptId, docId);
|
||||
return;
|
||||
}
|
||||
// 获取用户ID
|
||||
com.microservices.system.api.domain.SysUser sysUser = FeignUtils.getReturnData(
|
||||
remoteUserService.getSysUserByUserName(createBy, SecurityConstants.INNER));
|
||||
if (sysUser == null || sysUser.getUserId() == null) {
|
||||
logger.warn("文章浏览增加积分失败,未找到用户信息,createBy={},docId={}", createBy, docId);
|
||||
return;
|
||||
}
|
||||
// 直接写入 Redis 积分队列,由 Zone 模块定时任务消费
|
||||
JSONObject task = new JSONObject();
|
||||
task.put("sourceType", CmsConstants.VISITS_DOC);
|
||||
task.put("userId", sysUser.getUserId());
|
||||
task.put("deptId", deptId);
|
||||
task.put("sourceId", docId);
|
||||
// JSONObject sourceData = new JSONObject();
|
||||
// sourceData.put("totalVisits", totalVisits);
|
||||
// sourceData.put("currentIncrement", pointsTriggerCount);
|
||||
task.put("sourceData", totalVisits);
|
||||
task.put("subjectDesc", docName);
|
||||
task.put("operatorId", SecurityUtils.getUserId());
|
||||
redisService.leftPush(CmsConstants.ZONE_POINTS_ASYNC_QUEUE_KEY, task.toJSONString());
|
||||
logger.info("文章浏览增加积分任务已写入队列,docId={},userId={},deptId={},totalVisits={}", docId, sysUser.getUserId(), deptId, totalVisits);
|
||||
} catch (Exception e) {
|
||||
// 捕获异常,确保不影响主事务
|
||||
logger.error("文章浏览增加积分异常,docId={}", docId, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public void addFeaturedDocPointsAsync(Long deptId, String createBy, Long docId, String subjectDesc) {
|
||||
try {
|
||||
if (deptId == null || createBy == null) {
|
||||
logger.warn("积分-文章精选:参数不合法,deptId={},createBy={}", deptId, createBy);
|
||||
return;
|
||||
}
|
||||
// 检查是否为积分部门
|
||||
if (!isPointsDept(deptId)) {
|
||||
logger.info("积分-文章精选:非积分部门,deptId={},docId={}", deptId, docId);
|
||||
return;
|
||||
}
|
||||
// 获取用户ID
|
||||
com.microservices.system.api.domain.SysUser sysUser = FeignUtils.getReturnData(
|
||||
remoteUserService.getSysUserByUserName(createBy, SecurityConstants.INNER));
|
||||
if (sysUser == null || sysUser.getUserId() == null) {
|
||||
logger.warn("积分-文章精选:未找到用户信息,createBy={},docId={}", createBy, docId);
|
||||
return;
|
||||
}
|
||||
// 直接写入 Redis 积分队列,由 Zone 模块定时任务消费
|
||||
JSONObject task = new JSONObject();
|
||||
task.put("sourceType", CmsConstants.FEATURED_DOC);
|
||||
task.put("userId", sysUser.getUserId());
|
||||
task.put("deptId", deptId);
|
||||
task.put("sourceId", docId);
|
||||
task.put("subjectDesc", "《" + subjectDesc + "》管理员标记");
|
||||
task.put("operatorId", SecurityUtils.getUserId());
|
||||
redisService.leftPush(CmsConstants.ZONE_POINTS_ASYNC_QUEUE_KEY, task.toJSONString());
|
||||
logger.info("文章被设为精选增加积分任务已写入队列,docId={},userId={},deptId={}", docId, sysUser.getUserId(), deptId);
|
||||
} catch (Exception e) {
|
||||
// 捕获异常,确保不影响主事务
|
||||
logger.error("文章被设为精选增加积分异常,docId={}", docId, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.microservices.cms.utils.CmsGitLinkRequestUrl;
|
|||
import com.microservices.common.core.constant.CacheConstants;
|
||||
import com.microservices.common.core.constant.HttpStatus;
|
||||
import com.microservices.common.core.constant.SecurityConstants;
|
||||
import com.microservices.common.core.constant.UserConstants;
|
||||
import com.microservices.common.core.enums.DocAndZoneOperation;
|
||||
import com.microservices.common.core.enums.DocAuditStatus;
|
||||
import com.microservices.common.core.enums.SystemRole;
|
||||
|
|
@ -23,10 +24,12 @@ import com.microservices.common.core.utils.DateUtils;
|
|||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.common.core.utils.bean.BeanUtils;
|
||||
import com.microservices.common.core.utils.html.EscapeUtil;
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
import com.microservices.common.httpClient.constant.GitLinkConstants;
|
||||
import com.microservices.common.httpClient.util.GitLinkRequestHelper;
|
||||
import com.microservices.common.redis.service.RedisService;
|
||||
import com.microservices.common.security.auth.AuthUtil;
|
||||
import com.microservices.common.security.service.TokenService;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.system.api.RemoteDeptService;
|
||||
import com.microservices.system.api.RemoteUserService;
|
||||
|
|
@ -47,8 +50,11 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
@ -80,6 +86,8 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
@Autowired
|
||||
private RemoteDeptService remoteDeptService;
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
@Autowired
|
||||
@Lazy
|
||||
private ICmsDocCommentService cmsDocCommentService;
|
||||
@Value("${cms.detailPath:/newdetail}")
|
||||
|
|
@ -89,7 +97,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
* 查询文章信息
|
||||
*
|
||||
* @param id 文章信息主键
|
||||
* @param isOpen
|
||||
* @param isOpen 是否公开访问
|
||||
* @return 文章信息
|
||||
*/
|
||||
@Override
|
||||
|
|
@ -104,7 +112,14 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(cmsDoc.getDeptId());
|
||||
|
||||
String branchName = DocAuditStatus.AUDIT_PASS.getAuditCode().equals(cmsDoc.getAuditStatus()) ? CmsConstants.BRANCH_MASTER : cmsDoc.getAuditTmpBranchName();
|
||||
// 确定查询文件的分支:已发布文章或非仓库改动使用 master,其他使用临时分支
|
||||
String branchName;
|
||||
if (DocAuditStatus.AUDIT_PASS.getAuditCode().equals(cmsDoc.getAuditStatus())
|
||||
|| (cmsDoc.getAuditType() != null && cmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode()))) {
|
||||
branchName = CmsConstants.BRANCH_MASTER;
|
||||
} else {
|
||||
branchName = cmsDoc.getAuditTmpBranchName();
|
||||
}
|
||||
FileEntryDto fileEntryDto = getFileEntryDto(cmsProject, cmsDoc.getFilePath(), branchName);
|
||||
EntryDto entryDto = fileEntryDto.getEntries();
|
||||
|
||||
|
|
@ -115,7 +130,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
if (cmsDoc.getPublishTime() != null && cmsDoc.getPublishTime().after(cmsDoc.getCreateTime())) {
|
||||
cmsDocDto.setIsFirstPublish(false);
|
||||
}
|
||||
if (isOpen) {
|
||||
if (isOpen && DocAuditStatus.AUDIT_PASS.getAuditCode().equals(cmsDoc.getAuditStatus())) {
|
||||
updateVisits(cmsDocDto.getId());
|
||||
}
|
||||
return cmsDocDto;
|
||||
|
|
@ -171,6 +186,21 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
return cmsDocList.stream().map(CmsDoc::copyToCmsDocAllDto).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericsTableDataInfo<CmsDocAllDto> selectAllDocList(Long deptId, CmsDocSearchVo cmsDocSearchVo) {
|
||||
List<CmsDocAllDto> list = selectCmsDocListByDept(deptId, cmsDocSearchVo);
|
||||
list.forEach(x -> {
|
||||
String docDetailUrl = getDocDetailUrl(x.getDeptId(), x.getId());
|
||||
x.setDocDetailUrl(docDetailUrl);
|
||||
|
||||
Boolean editable = isCmsDocEditable(x);
|
||||
x.setEditable(editable);
|
||||
|
||||
});
|
||||
int count = selectCmsDocCountByDept(deptId, cmsDocSearchVo);
|
||||
return new GenericsTableDataInfo<>(list, Long.valueOf(count));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int selectCmsDocCountByDept(Long deptId, CmsDocSearchVo cmsDocSearchVo) {
|
||||
cmsDocSearchVo.setDeptId(deptId);
|
||||
|
|
@ -233,14 +263,14 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
@Override
|
||||
public List<CmsDocDetailDto> selectCmsDocDetailList(Long dirId) {
|
||||
List<CmsDocDetailDto> cmsDocDetailDtoList = new ArrayList<>();
|
||||
CmsDoc cmsDir = cmsDocMapper.selectCmsDocDirById(dirId);
|
||||
CmsDoc cmsDir = selectCmsDir(dirId);
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(cmsDir.getDeptId());
|
||||
CmsDocSearchVo cmsDocSearchVo = new CmsDocSearchVo();
|
||||
cmsDocSearchVo.setDirName(cmsDir.getName());
|
||||
cmsDocSearchVo.setDeptId(cmsDir.getDeptId());
|
||||
cmsDocSearchVo.setIsDir(false);
|
||||
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocListSetDefaultHeadImg(cmsDocSearchVo);
|
||||
List<CompletableFuture<CmsDocDetailDto>> futures = new ArrayList();
|
||||
List<CompletableFuture<CmsDocDetailDto>> futures = new ArrayList<>();
|
||||
for (CmsDoc cmsDoc : cmsDocList) {
|
||||
CompletableFuture<CmsDocDetailDto> future = CompletableFuture.supplyAsync(() -> {
|
||||
CmsDocDetailDto cmsDocDetailDto = cmsDoc.copyToCmsDocDetailDto();
|
||||
|
|
@ -297,7 +327,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
|
||||
@Override
|
||||
public void updateCmsDocShaByPathAndDeptId(String sha, String filePath, Long deptId) {
|
||||
cmsDocMapper.updateCmsDocShaByPathAndDeptId(sha,filePath,deptId);
|
||||
cmsDocMapper.updateCmsDocShaByPathAndDeptId(sha, filePath, deptId);
|
||||
}
|
||||
|
||||
private List<CmsDocBaseDto> selectCmsDocListByDatabase(Long dirId, CmsDocSearchVo cmsDocSearchVo) {
|
||||
|
|
@ -314,7 +344,8 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
|
||||
/**
|
||||
* 设置文章默认头图为栏目头图
|
||||
* @param dirId 栏目id
|
||||
*
|
||||
* @param dirId 栏目id
|
||||
* @param cmsDocSearchVo 文章查询条件
|
||||
* @return 文章列表
|
||||
*/
|
||||
|
|
@ -359,13 +390,16 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
checkCmsLockStatus(dirDoc.getDeptId());
|
||||
CmsDoc cmsDoc = cmsDocInputDto.toCmsDoc(dirDoc);
|
||||
|
||||
if (isNoAuditRequired(dirDoc.getDeptId()) || isCurrentUserZoneAdmin(dirDoc.getDeptId())) {
|
||||
if (isNoAuditRequired(dirDoc.getDeptId()) || tokenService.hasDeptPerms(dirDoc.getDeptId(), UserConstants.CMS_PERMS_DOCS_AUDIT)) {
|
||||
//文章自动置为审核通过状态值
|
||||
cmsDoc.setAuditStatus(DocAuditStatus.AUDIT_PASS.getAuditCode());
|
||||
boolean success = insertCommonCmsDoc(cmsDoc,
|
||||
"创建文章:" + StringUtils.truncateStringAndConcatenatingSpecifiedString(cmsDoc.getName(), 100, "..."),
|
||||
cmsDocInputDto.getContent());
|
||||
innerInitPublishDate(cmsDoc,cmsDocInputDto.getPublishDate());
|
||||
if (success) {
|
||||
// 自动审核通过时也需要增加积分
|
||||
cmsAsyncService.addPublishDocPointsAsync(cmsDoc.getDeptId(), cmsDoc.getCreateBy(), cmsDoc.getId(), cmsDoc.getName());
|
||||
}
|
||||
return success ? cmsDoc.getId().intValue() : null;
|
||||
} else {
|
||||
//创建临时分支,创建文件,创建PR
|
||||
|
|
@ -375,22 +409,11 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
boolean success = insertCmsDocWithAudit(cmsDoc,
|
||||
"创建文章:" + StringUtils.truncateStringAndConcatenatingSpecifiedString(cmsDoc.getName(), 100, "..."),
|
||||
cmsDocInputDto.getContent());
|
||||
innerInitPublishDate(cmsDoc,cmsDocInputDto.getPublishDate());
|
||||
return success ? cmsDoc.getId().intValue() : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void innerInitPublishDate(CmsDoc cmsDoc, Date publishDate) {
|
||||
if(publishDate!=null){
|
||||
cmsDoc.setCreateTime(publishDate);
|
||||
cmsDoc.setUpdateTime(publishDate);
|
||||
cmsDoc.setPublishTime(publishDate);
|
||||
cmsDocMapper.updateCmsDoc(cmsDoc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean isCurrentUserZoneAdmin(Long deptId) {
|
||||
boolean isZoneAdmin = false;
|
||||
List<SysUserDeptRole> sysUserDeptRoleList = FeignUtils.getReturnData(
|
||||
|
|
@ -414,7 +437,9 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
public String getCmsDocFileContent(CmsProject cmsProject, CmsDoc cmsDoc) {
|
||||
String branchName = CmsConstants.BRANCH_MASTER;
|
||||
if (!DocAuditStatus.AUDIT_PASS.getAuditCode().equals(cmsDoc.getAuditStatus())) {
|
||||
branchName = cmsDoc.getAuditTmpBranchName();
|
||||
if (StringUtils.isNotEmpty(cmsDoc.getAuditTmpBranchName())) {
|
||||
branchName = cmsDoc.getAuditTmpBranchName();
|
||||
}
|
||||
}
|
||||
//当删除文章为文件夹时,判断该文件夹下是否存在文章,若存在需先删除所有文章
|
||||
JSONObject getSubEntriesResult = gitLinkRequestHelper.doGet(
|
||||
|
|
@ -434,9 +459,34 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean auditCmsDoc(Long docId, CmsDocAuditVo cmsDocAuditVo) {
|
||||
CmsDoc cmsDoc = cmsDocMapper.selectCmsDocById(docId);
|
||||
if (cmsDoc == null) {
|
||||
throw new ServiceException("该文章不存在");
|
||||
}
|
||||
checkCmsLockStatus(cmsDoc.getDeptId());
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(cmsDoc.getDeptId());
|
||||
|
||||
// 设置审核备注
|
||||
cmsDoc.setRemark(cmsDocAuditVo.getRemark());
|
||||
|
||||
if (cmsDocAuditVo.getPass() == 1) {
|
||||
// 处理非仓库改动的审核通过
|
||||
if (cmsDoc.getAuditType() != null
|
||||
&& cmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode())) {
|
||||
Long oldCmsDocId = Long.parseLong(cmsDoc.getAuditType().split("-")[1]);
|
||||
CmsDoc oldCmsDoc = cmsDocMapper.selectCmsDocById(oldCmsDocId);
|
||||
|
||||
// 用新文章的非仓库字段更新旧文章
|
||||
oldCmsDoc.setHeadImg(cmsDoc.getHeadImg());
|
||||
oldCmsDoc.setSummary(cmsDoc.getSummary());
|
||||
oldCmsDoc.setKeywords(cmsDoc.getKeywords());
|
||||
oldCmsDoc.setRemark(cmsDoc.getRemark());
|
||||
cmsDocMapper.updateCmsDoc(oldCmsDoc);
|
||||
|
||||
// 删除待审核记录
|
||||
cmsDocMapper.deleteCmsDocById(cmsDoc.getId());
|
||||
return true;
|
||||
}
|
||||
|
||||
//同意合并请求
|
||||
JSONObject result = mergePullRequestByGitLink(cmsProject, cmsDoc);
|
||||
if (result.containsKey(GitLinkConstants.STATUS_KEY)) {
|
||||
|
|
@ -458,8 +508,16 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
}
|
||||
}
|
||||
if (cmsDocAuditVo.getPass() == 0) {
|
||||
// 处理非仓库改动的审核拒绝
|
||||
if (cmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode())) {
|
||||
handleCmsDocWithNoPassByReedit(cmsDocAuditVo, cmsDoc, cmsProject);
|
||||
return true;
|
||||
}
|
||||
|
||||
//拒绝GitLink合并请求
|
||||
JSONObject result = refuseMergePullRequestByGitLink(cmsDoc, cmsProject);
|
||||
String gitLinkPullRequestNumber = cmsDoc.getAuditPrNumber().split("-")[0];
|
||||
JSONObject result = gitLinkRequestHelper.doPost(
|
||||
CmsGitLinkRequestUrl.REFUSE_MERGE_PULL_REQUEST(cmsProject, gitLinkPullRequestNumber), null);
|
||||
if (result.containsKey(GitLinkConstants.STATUS_KEY)) {
|
||||
//2.若拒绝GitLink合并请求操作返回正确的状态值,更新数据库
|
||||
if (result.getInteger(GitLinkConstants.STATUS_KEY).equals(1)) {
|
||||
|
|
@ -506,8 +564,10 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
if (cmsDocAuditVo.getReedit().equals(0)) {
|
||||
//删除待审核文章
|
||||
cmsDocMapper.deleteCmsDocById(cmsDoc.getId());
|
||||
//删除分支
|
||||
gitLinkRequestHelper.doDelete(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()));
|
||||
// 删除分支(如果有)
|
||||
if (StringUtils.isNotEmpty(cmsDoc.getAuditTmpBranchName())) {
|
||||
gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()), null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -519,7 +579,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
int success = deleteCmsDocDatabaseById(ids);
|
||||
if (success == ids.length) {
|
||||
//删除临时分支
|
||||
gitLinkRequestHelper.doDelete(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()));
|
||||
gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -539,7 +599,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
int success = cmsDocMapper.deleteCmsDocById(newDocId);
|
||||
if (success > 0) {
|
||||
//删除临时分支
|
||||
gitLinkRequestHelper.doDelete(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()));
|
||||
gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -553,11 +613,13 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
int success = cmsDocMapper.updateCmsDoc(cmsDoc);
|
||||
if (success > 0) {
|
||||
//删除临时分支
|
||||
gitLinkRequestHelper.doDelete(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()));
|
||||
gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()), null);
|
||||
}
|
||||
|
||||
// 推送文章地址到搜索引擎
|
||||
cmsAsyncService.pushDocDataSearchEngine(cmsDoc);
|
||||
// 文章审核通过后,给作者增加积分(异步执行,不影响主事务)
|
||||
cmsAsyncService.addPublishDocPointsAsync(cmsDoc.getDeptId(), cmsDoc.getCreateBy(), cmsDoc.getId(), cmsDoc.getName());
|
||||
}
|
||||
|
||||
private JSONObject mergePullRequestByGitLink(CmsProject cmsProject, CmsDoc cmsDoc) {
|
||||
|
|
@ -572,12 +634,6 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
CmsGitLinkRequestUrl.MERGE_PULL_REQUEST(cmsProject, gitLinkPullRequestId), requestBody);
|
||||
}
|
||||
|
||||
private JSONObject refuseMergePullRequestByGitLink(CmsDoc cmsDoc, CmsProject cmsProject) {
|
||||
//1.调用gitlink拒绝合并请求接口
|
||||
return gitLinkRequestHelper.doPost(
|
||||
CmsGitLinkRequestUrl.REFUSE_MERGE_PULL_REQUEST(cmsProject, cmsDoc.getAuditPrNumber()), null);
|
||||
}
|
||||
|
||||
public static String sha1(String data) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA1");
|
||||
|
|
@ -719,11 +775,47 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public boolean updateCmsDoc(Long id, CmsDocDto cmsDocDto) {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long updateCmsDoc(Long id, CmsDocDto cmsDocDto) {
|
||||
CmsDoc oldCmsDoc = cmsDocMapper.selectCmsDocById(id);
|
||||
checkCmsLockStatus(oldCmsDoc.getDeptId());
|
||||
if (!hasRepoRelatedChanged(oldCmsDoc, cmsDocDto)) {
|
||||
return cmsDocMapper.updateCmsDoc(oldCmsDoc) > 0;
|
||||
// 更新非仓库字段到原文章对象
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getHeadImg())) {
|
||||
oldCmsDoc.setHeadImg(cmsDocDto.getHeadImg());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getSummary())) {
|
||||
oldCmsDoc.setSummary(cmsDocDto.getSummary());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getKeywords())) {
|
||||
oldCmsDoc.setKeywords(cmsDocDto.getKeywords());
|
||||
}
|
||||
|
||||
// 管理员或免审核:直接更新原记录
|
||||
if (tokenService.hasDeptPerms(oldCmsDoc.getDeptId(), UserConstants.CMS_PERMS_DOCS_AUDIT)
|
||||
|| isNoAuditRequired(oldCmsDoc.getDeptId())) {
|
||||
cmsDocMapper.updateCmsDoc(oldCmsDoc);
|
||||
return oldCmsDoc.getId();
|
||||
}
|
||||
|
||||
// 需要审核:创建新的待审核记录(与仓库改动逻辑一致)
|
||||
if (oldCmsDoc.getAuditStatus().equals(DocAuditStatus.AUDIT_PASS.getAuditCode())) {
|
||||
CmsDoc newDocWithAudit = insertDocWithAudit(oldCmsDoc,
|
||||
DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode() + "-" + oldCmsDoc.getId(),
|
||||
DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
return newDocWithAudit.getId();
|
||||
}
|
||||
oldCmsDoc.setAuditStatus(DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
if (oldCmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_CREATE.getOperationCode())
|
||||
|| oldCmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_UPDATE.getOperationCode())) {
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(oldCmsDoc.getDeptId());
|
||||
// 重新开启PR
|
||||
String gitLinkPullRequestNumber = oldCmsDoc.getAuditPrNumber().split("-")[0];
|
||||
gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.REOPEN_PULL_REQUEST(cmsProject, gitLinkPullRequestNumber), null);
|
||||
}
|
||||
// 待审核/未通过文章重新编辑
|
||||
cmsDocMapper.updateCmsDoc(oldCmsDoc);
|
||||
return oldCmsDoc.getId();
|
||||
}
|
||||
// 当文章名称发生更改时,判断文章名是否在当前栏目下已存在
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getName()) && !cmsDocDto.getName().equals(oldCmsDoc.getName())) {
|
||||
|
|
@ -736,8 +828,16 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
}
|
||||
checkDocName(cmsDocDto.getName(), oldCmsDoc.getDeptId(), dirName);
|
||||
}
|
||||
|
||||
// 当用户更新栏目时,需检查新栏目下是否已存在相同文章名
|
||||
if (cmsDocDto.getDirId() != null) {
|
||||
CmsDir cmsDir = selectCmsDirById(cmsDocDto.getDirId(), false);
|
||||
if (cmsDir != null && !cmsDir.getName().equals(oldCmsDoc.getDirName())) {
|
||||
checkDocName(cmsDocDto.getName(), oldCmsDoc.getDeptId(), cmsDir.getName());
|
||||
}
|
||||
}
|
||||
//用户为专区管理员或专区无审核机制时,直接更新文章及仓库主分支
|
||||
if (isCurrentUserZoneAdmin(oldCmsDoc.getDeptId()) || isNoAuditRequired(oldCmsDoc.getDeptId())) {
|
||||
if (tokenService.hasDeptPerms(oldCmsDoc.getDeptId(), UserConstants.CMS_PERMS_DOCS_AUDIT) || isNoAuditRequired(oldCmsDoc.getDeptId())) {
|
||||
//专区管理员重新编辑并提交审核未通过文章 或 重新编辑并提交待审核文章时专区不需审核机制
|
||||
if (!oldCmsDoc.getAuditStatus().equals(DocAuditStatus.AUDIT_PASS.getAuditCode())) {
|
||||
//文章审核类型:update-原文章id 取出原文章id直接更新,删除待审核更新类型文章
|
||||
|
|
@ -752,7 +852,8 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
if (oldCmsDoc.getAuditType() != null && oldCmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_CREATE.getOperationCode())) {
|
||||
deleteTmpBranchIfBranchExist(oldCmsDoc);
|
||||
cmsDocMapper.deleteCmsDocById(id);
|
||||
return directlyInsertAuditedCmsDocWhenZoneHasNoAuditRequired(cmsDocDto, oldCmsDoc);
|
||||
directlyInsertAuditedCmsDocWhenZoneHasNoAuditRequired(cmsDocDto, oldCmsDoc);
|
||||
return oldCmsDoc.getId();
|
||||
}
|
||||
}
|
||||
String branchName = CmsConstants.BRANCH_MASTER;
|
||||
|
|
@ -760,16 +861,52 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
oldCmsDoc.setAuditStatus(DocAuditStatus.AUDIT_PASS.getAuditCode());
|
||||
oldCmsDoc.setAuditTmpBranchName(null);
|
||||
oldCmsDoc.setKeywords(cmsDocDto.getKeywords());
|
||||
return updateCmsCommonDatabase(oldCmsDoc, CmsConstants.BRANCH_MASTER) > 0;
|
||||
updateCmsCommonDatabase(oldCmsDoc, CmsConstants.BRANCH_MASTER);
|
||||
return oldCmsDoc.getId();
|
||||
} else {
|
||||
|
||||
CmsDoc newDocWithAudit = new CmsDoc();
|
||||
//待审核、未通过文章重新编辑并提交
|
||||
if (DocAuditStatus.AUDIT_FAIL.getAuditCode().equals(oldCmsDoc.getAuditStatus())
|
||||
|| DocAuditStatus.TO_BE_AUDIT.getAuditCode().equals(oldCmsDoc.getAuditStatus())) {
|
||||
|
||||
// 非仓库改动待审核记录:检查是否有仓库改动
|
||||
if (oldCmsDoc.getAuditType() != null
|
||||
&& oldCmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode())) {
|
||||
|
||||
if (!hasRepoRelatedChanged(oldCmsDoc, cmsDocDto)) {
|
||||
// 纯非仓库改动:继续在当前记录上更新
|
||||
oldCmsDoc.setAuditStatus(DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getHeadImg())) {
|
||||
oldCmsDoc.setHeadImg(cmsDocDto.getHeadImg());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getSummary())) {
|
||||
oldCmsDoc.setSummary(cmsDocDto.getSummary());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(cmsDocDto.getKeywords())) {
|
||||
oldCmsDoc.setKeywords(cmsDocDto.getKeywords());
|
||||
}
|
||||
cmsDocMapper.updateCmsDoc(oldCmsDoc);
|
||||
return oldCmsDoc.getId();
|
||||
} else {
|
||||
// 有仓库改动:转为仓库改动类型,删除当前记录,重新创建
|
||||
Long oldCmsDocId = Long.parseLong(oldCmsDoc.getAuditType().split("-")[1]);
|
||||
CmsDoc originCmsDoc = cmsDocMapper.selectCmsDocById(oldCmsDocId);
|
||||
cmsDocMapper.deleteCmsDocById(oldCmsDoc.getId());
|
||||
|
||||
// 按照仓库改动逻辑重新创建
|
||||
newDocWithAudit = insertDocWithAudit(originCmsDoc,
|
||||
DocAndZoneOperation.OPERATION_UPDATE.getOperationCode() + "-" + oldCmsDocId,
|
||||
DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
cmsAsyncService.asyncUpdateBranchAndFileAndCreatePR(newDocWithAudit, cmsDocDto);
|
||||
return newDocWithAudit.getId();
|
||||
}
|
||||
}
|
||||
|
||||
// 仓库改动待审核记录:继续在当前记录上更新
|
||||
oldCmsDoc.setAuditStatus(DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
newDocWithAudit = oldCmsDoc;
|
||||
} else
|
||||
} else {
|
||||
//更新已发布文章
|
||||
if (oldCmsDoc.getAuditStatus().equals(DocAuditStatus.AUDIT_PASS.getAuditCode())) {
|
||||
//1.创建一条auditType="update-原文章id",audit_status为2,其余字段与待更新文章一致的新文章数据
|
||||
|
|
@ -777,8 +914,9 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
DocAndZoneOperation.OPERATION_UPDATE.getOperationCode() + "-" + id,
|
||||
DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
}
|
||||
}
|
||||
cmsAsyncService.asyncUpdateBranchAndFileAndCreatePR(newDocWithAudit, cmsDocDto);
|
||||
return true;
|
||||
return newDocWithAudit.getId();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -830,7 +968,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
private void deleteTmpBranchIfBranchExist(CmsDoc cmsDoc) {
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(cmsDoc.getDeptId());
|
||||
try {
|
||||
gitLinkRequestHelper.doDelete(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()));
|
||||
gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()), null);
|
||||
} catch (ServiceException e) {
|
||||
//忽略分支不存在异常
|
||||
if (!"分支不存在!".equals(e.getMessage())) {
|
||||
|
|
@ -861,15 +999,29 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
}
|
||||
|
||||
private CmsDoc insertDocWithAudit(CmsDoc oldCmsDoc, String auditType, String auditStatus) {
|
||||
List<CmsDoc> tmpDocList = getTmpDocList(oldCmsDoc);
|
||||
if (!tmpDocList.isEmpty()) {
|
||||
throw new ServiceException("已存在待审核操作,请等待审核完成后再进行操作");
|
||||
}
|
||||
oldCmsDoc.setId(null);
|
||||
oldCmsDoc.setAuditType(auditType);
|
||||
oldCmsDoc.setAuditStatus(auditStatus);
|
||||
oldCmsDoc.setCreateBy(SecurityUtils.getUsername());
|
||||
|
||||
// 非 repo 改动:显式设置 auditTmpBranchName 为 null(没有对应的分支)
|
||||
if (auditType != null && auditType.contains(DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode())) {
|
||||
oldCmsDoc.setAuditTmpBranchName(null);
|
||||
}
|
||||
|
||||
cmsDocMapper.insertCmsDoc(oldCmsDoc);
|
||||
return oldCmsDoc;
|
||||
}
|
||||
|
||||
private CmsDoc insertDeletedDocWithAudit(CmsDoc oldCmsDoc, Long oldCmsDocId) {
|
||||
List<CmsDoc> tmpDocList = getTmpDocList(oldCmsDoc);
|
||||
if (!tmpDocList.isEmpty()) {
|
||||
throw new ServiceException("已存在待审核操作,请等待审核完成后再进行操作");
|
||||
}
|
||||
oldCmsDoc.setId(null);
|
||||
oldCmsDoc.setAuditType(DocAndZoneOperation.OPERATION_DELETE.getOperationCode() + "-" + oldCmsDocId);
|
||||
oldCmsDoc.setAuditStatus(DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
|
|
@ -1015,7 +1167,13 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
visits = visits + cmsDoc.getVisits();
|
||||
}
|
||||
cmsDoc.setVisits(visits);
|
||||
return cmsDocMapper.updateCmsDoc(cmsDoc) > 0;
|
||||
int rows = cmsDocMapper.updateCmsDoc(cmsDoc);
|
||||
if (rows > 0) {
|
||||
cmsAsyncService.addVisitsDocPointsAsync(cmsDoc.getDeptId(), cmsDoc.getCreateBy(),
|
||||
cmsDoc.getId(), cmsDoc.getName(), cmsDoc.getVisits());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1139,6 +1297,9 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
//首页推荐时,需将顺序设置为1
|
||||
setCmsSort(1, cmsDoc, false, null);
|
||||
cmsDoc.setIsHomepage(CmsConstants.TRUE);
|
||||
// 文章被设为精选,异步增加作者积分
|
||||
cmsAsyncService.addFeaturedDocPointsAsync(cmsDoc.getDeptId(), cmsDoc.getCreateBy(),
|
||||
cmsDoc.getId(), cmsDoc.getName());
|
||||
}
|
||||
return cmsDocMapper.updateCmsDoc(cmsDoc);
|
||||
}
|
||||
|
|
@ -1162,6 +1323,41 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
return cmsDocBaseDtoList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CmsDocBaseDto> selectHomePageDocMergeList(Long zoneId, List<Long> topDocIds) {
|
||||
Long deptId = getDeptIdByZoneId(zoneId);
|
||||
Set<Long> addedDocIds = new HashSet<>();
|
||||
|
||||
// 1. 获取首页推荐文章列表
|
||||
List<CmsDocBaseDto> homePageDocs = selectHomePageDocList(deptId);
|
||||
List<CmsDocBaseDto> result = new ArrayList<>();
|
||||
|
||||
// 2. 批量查询置顶文章完整数据,按传入顺序放入结果头部
|
||||
if (topDocIds != null && !topDocIds.isEmpty()) {
|
||||
List<CmsDoc> topCmsDocs = cmsDocMapper.selectCmsDocByIds(topDocIds);
|
||||
Map<Long, CmsDoc> topDocMap = new HashMap<>();
|
||||
for (CmsDoc doc : topCmsDocs) {
|
||||
topDocMap.put(doc.getId(), doc);
|
||||
}
|
||||
for (Long docId : topDocIds) {
|
||||
CmsDoc doc = topDocMap.get(docId);
|
||||
if (doc != null) {
|
||||
result.add(doc.copyToCmsDocBaseDto());
|
||||
addedDocIds.add(docId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 追加首页推荐文章(跳过已在置顶列表中的)
|
||||
for (CmsDocBaseDto doc : homePageDocs) {
|
||||
if (!addedDocIds.contains(doc.getId())) {
|
||||
result.add(doc);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public CmsDir initCmsDir(Long deptId, CmsDir cmsDirInput) {
|
||||
|
|
@ -1308,6 +1504,17 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
cmsAsyncService.updateCmsPublishDataByGitLink(cmsProject, cmsDoc, branchName);
|
||||
}
|
||||
|
||||
private int deleteCmsDir(CmsProject cmsProject, CmsDoc cmsDir) {
|
||||
if (!isNoAuditRequired(cmsDir.getDeptId()) || tokenService.hasDeptPerms(cmsDir.getDeptId(), UserConstants.CMS_PERMS_DOCS_AUDIT)) {
|
||||
boolean deleteResult = cmsAsyncService.deleteCmsDocForGitLink(cmsDir, cmsProject, CmsConstants.BRANCH_MASTER);
|
||||
if (deleteResult) {
|
||||
return cmsDocMapper.deleteCmsDocById(cmsDir.getId());
|
||||
}
|
||||
throw new ServiceException("栏目删除失败");
|
||||
}
|
||||
throw new ServiceException("无权限删除栏目");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteCmsDocById(Long id) {
|
||||
CmsDoc cmsDoc = cmsDocMapper.selectCmsDocById(id);
|
||||
|
|
@ -1317,22 +1524,42 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
checkCmsLockStatus(cmsDoc.getDeptId());
|
||||
//2、获取专区项目
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(cmsDoc.getDeptId());
|
||||
if (cmsDoc.getIsDir()) {
|
||||
return deleteCmsDir(cmsProject, cmsDoc);
|
||||
}
|
||||
|
||||
//删除待审核、审核未通过文章——删除临时分支,拒绝合并请求
|
||||
if (DocAuditStatus.TO_BE_AUDIT.getAuditCode().equals(cmsDoc.getAuditStatus())
|
||||
|| DocAuditStatus.AUDIT_FAIL.getAuditCode().equals(cmsDoc.getAuditStatus())) {
|
||||
gitLinkRequestHelper.doDelete(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()));
|
||||
cmsDocMapper.deleteCmsDocById(id);
|
||||
return 1;
|
||||
if (DocAuditStatus.TO_BE_AUDIT.getAuditCode().equals(cmsDoc.getAuditStatus())) {
|
||||
// 非仓库改动类型直接删除
|
||||
if (cmsDoc.getAuditType().contains(DocAndZoneOperation.OPERATION_NON_REPO_UPDATE.getOperationCode())) {
|
||||
return cmsDocMapper.deleteCmsDocById(cmsDoc.getId());
|
||||
}
|
||||
|
||||
//拒绝GitLink合并请求
|
||||
String gitLinkPullRequestNumber = cmsDoc.getAuditPrNumber().split("-")[0];
|
||||
gitLinkRequestHelper.doPost(
|
||||
CmsGitLinkRequestUrl.REFUSE_MERGE_PULL_REQUEST(cmsProject, gitLinkPullRequestNumber), null);
|
||||
gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()), null);
|
||||
return cmsDocMapper.deleteCmsDocById(cmsDoc.getId());
|
||||
}
|
||||
if (isCurrentUserZoneAdmin(cmsDoc.getDeptId()) //当前用户为专区管理员
|
||||
if (DocAuditStatus.AUDIT_FAIL.getAuditCode().equals(cmsDoc.getAuditStatus())) {
|
||||
return cmsDocMapper.deleteCmsDocById(cmsDoc.getId());
|
||||
}
|
||||
// 判读当前用户是否拥有文章直接删除权限
|
||||
if (tokenService.hasDeptPerms(cmsDoc.getDeptId(), UserConstants.CMS_PERMS_DOCS_AUDIT) //当前用户为专区管理员
|
||||
|| isNoAuditRequired(cmsDoc.getDeptId()) //当前专区文章发布无需审核机制
|
||||
) {
|
||||
String branchName = CmsConstants.BRANCH_MASTER;
|
||||
boolean deleteResult = cmsAsyncService.deleteCmsDocForGitLink(cmsDoc, cmsProject, branchName);
|
||||
if (deleteResult) {
|
||||
return deleteCmsDocDatabaseById(cmsDoc.getId());
|
||||
// 拒绝相关合并请求并清理所有临时分支,同时删除所有临时申请
|
||||
List<CmsDoc> tmpDocList = getTmpDocList(cmsDoc);
|
||||
cmsAsyncService.clearTmpDoc(cmsProject, tmpDocList);
|
||||
cmsDoc.setAuditStatus(DocAuditStatus.AUDIT_FAIL.getAuditCode());
|
||||
cmsDoc.setRemark("管理员删除");
|
||||
return cmsDocMapper.updateCmsDoc(cmsDoc);
|
||||
}
|
||||
|
||||
} else {
|
||||
//1.创建一条auditType="delete-原文章id",audit_status=2,其余字段与待删除文章一致的新文章数据
|
||||
CmsDoc newDocWithAudit = insertDeletedDocWithAudit(cmsDoc, id);
|
||||
|
|
@ -1342,6 +1569,18 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
throw new ServiceException("文件删除失败");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CmsDoc> getTmpDocList(CmsDoc cmsDoc) {
|
||||
CmsDocSearchVo cmsDocSearchVo = new CmsDocSearchVo();
|
||||
cmsDocSearchVo.setName(cmsDoc.getName());
|
||||
cmsDocSearchVo.setDeptId(cmsDoc.getDeptId());
|
||||
cmsDocSearchVo.setIsDir(false);
|
||||
cmsDocSearchVo.setDirName(cmsDoc.getDirName());
|
||||
cmsDocSearchVo.setAuditStatus(DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
// 拒绝相关合并请求并清理所有临时分支,同时删除所有临时申请
|
||||
return cmsDocMapper.selectCmsDocList(cmsDocSearchVo);
|
||||
}
|
||||
|
||||
public int deleteCmsDocDatabaseById(Long id) {
|
||||
CmsDoc cmsDoc = cmsDocMapper.selectCmsDocById(id);
|
||||
if (cmsDoc != null && !cmsDoc.getIsDir()) {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,16 @@ public class CmsProjectController extends BaseController {
|
|||
return R.ok(changeRoleResult);
|
||||
}
|
||||
|
||||
@InnerAuth
|
||||
@PutMapping("/changeOrgRole/user/{userId}/operate/{operate}")
|
||||
@ApiOperation(value = "修改用户所在GItLink组织中的权限", hidden = true)
|
||||
public R<Boolean> changeUserOrgRole(@PathVariable("userId") Long userId, @PathVariable("operate") Long operate
|
||||
) {
|
||||
Boolean changeRoleResult = cmsProjectService.changeUserOrgRole(userId, operate);
|
||||
return R.ok(changeRoleResult);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询专区对应项目列表
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package com.microservices.cms.project.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author otto
|
||||
*/
|
||||
@Data
|
||||
public class GitlinkOrganizationTeamVo implements Serializable {
|
||||
@ApiModelProperty(value = "团队权限")
|
||||
private String authorize;
|
||||
@ApiModelProperty(value = "团队Id")
|
||||
private Long id;
|
||||
@ApiModelProperty(value = "团队名称")
|
||||
private String name;
|
||||
@ApiModelProperty(value = "团队昵称")
|
||||
private String nickname;
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.microservices.cms.project.mapper;
|
|||
|
||||
import com.microservices.cms.project.domain.CmsProject;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -64,4 +65,25 @@ public interface CmsProjectMapper {
|
|||
CmsProject selectCmsProjectByDeptId(Long deptId);
|
||||
|
||||
CmsProject selectCmsProjectByIdentifier(String identifier);
|
||||
|
||||
/**
|
||||
* 全局搜索 - 全文索引查询
|
||||
*
|
||||
* @param keyword 搜索关键词
|
||||
* @param deptId 组织ID(可选)
|
||||
* @param offset 偏移量
|
||||
* @param pageSize 每页数量
|
||||
* @return 搜索结果列表
|
||||
*/
|
||||
List<CmsProject> globalSearch(@Param("keyword") String keyword, @Param("deptId") Long deptId,
|
||||
@Param("offset") int offset, @Param("pageSize") int pageSize);
|
||||
|
||||
/**
|
||||
* 全局搜索结果计数
|
||||
*
|
||||
* @param keyword 搜索关键词
|
||||
* @param deptId 组织ID(可选)
|
||||
* @return 结果数量
|
||||
*/
|
||||
Long globalSearchCount(@Param("keyword") String keyword, @Param("deptId") Long deptId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,4 +82,6 @@ public interface ICmsProjectService {
|
|||
boolean initZoneCmsProjectByDept(Long deptId);
|
||||
|
||||
CmsProject selectCmsProjectByDeptIdAndNoException(Long deptId);
|
||||
|
||||
Boolean changeUserOrgRole(Long userId, Long operate);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.microservices.cms.doc.domain.*;
|
|||
import com.microservices.cms.doc.service.ICmsAsyncService;
|
||||
import com.microservices.cms.doc.service.ICmsDocService;
|
||||
import com.microservices.cms.project.domain.CmsProject;
|
||||
import com.microservices.cms.project.domain.GitlinkOrganizationTeamVo;
|
||||
import com.microservices.cms.project.mapper.CmsProjectMapper;
|
||||
import com.microservices.cms.project.service.ICmsProjectService;
|
||||
import com.microservices.cms.utils.CmsConstants;
|
||||
|
|
@ -320,6 +321,40 @@ public class CmsProjectServiceImpl implements ICmsProjectService {
|
|||
return cmsProjectMapper.selectCmsProjectByDeptId(deptId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean changeUserOrgRole(Long userId, Long operate) {
|
||||
Long gitlinkOrgId = getOrganizationId();
|
||||
SysUser sysUser = FeignUtils.getReturnData(remoteUserService.getSysUserByUserId(userId, SecurityConstants.INNER));
|
||||
if (sysUser == null) {
|
||||
return false;
|
||||
}
|
||||
List<GitlinkOrganizationTeamVo> gitlinkOrganizationTeamVoList = gitLinkRequestHelper.getAllDataByPage(
|
||||
CmsGitLinkRequestUrl.TEAMS_BY_ORGANIZATION_URL(gitlinkOrgId), "teams", GitlinkOrganizationTeamVo.class
|
||||
);
|
||||
GitlinkOrganizationTeamVo ownerTeam = gitlinkOrganizationTeamVoList.stream().filter(x -> "owner".equals(x.getAuthorize())).findFirst().orElse(null);
|
||||
if (ownerTeam == null) {
|
||||
return false;
|
||||
}
|
||||
if (operate == 1) {
|
||||
JSONObject addUserToTeam = new JSONObject();
|
||||
addUserToTeam.put("username", sysUser.getUserName());
|
||||
gitLinkRequestHelper.doPost(
|
||||
CmsGitLinkRequestUrl.ADD_USER_TO_ORGANIZATION_TEAM(gitLinkOrganization, ownerTeam.getId()), addUserToTeam);
|
||||
}
|
||||
if (operate == 3) {
|
||||
try {
|
||||
gitLinkRequestHelper.doDelete(CmsGitLinkRequestUrl.DELETE_USER_FROM_ORGANIZATION_TEAM(
|
||||
gitLinkOrganization,
|
||||
ownerTeam.getId(),
|
||||
sysUser.getUserName()
|
||||
));
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean changeUserRole(Long userId, Long oldDeptId, Long newDeptId, Long oldRoleId, Long newRoleId) {
|
||||
SysUser sysUser = FeignUtils.getReturnData(remoteUserService.getSysUserByUserId(userId, SecurityConstants.INNER));
|
||||
|
|
@ -338,9 +373,10 @@ public class CmsProjectServiceImpl implements ICmsProjectService {
|
|||
try {
|
||||
gitLinkRequestHelper.doDelete(CmsGitLinkRequestUrl.REMOVE_USER_FROM_PROJECT(oldCmsProject), requestBody);
|
||||
} catch (ServiceException e) {
|
||||
if (!e.getMessage().contains("用户为组织成员,请到组织下操作")) {
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
log.error("将用户从原项目中移除发生异常:{}", e.getMessage());
|
||||
// if (!e.getMessage().contains("用户为组织成员,请到组织下操作")||!e.getMessage().contains("还不是项目成员")) {
|
||||
// throw new ServiceException(e.getMessage());
|
||||
// }
|
||||
}
|
||||
}
|
||||
//将用户加入新的项目
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
package com.microservices.cms.search.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 文章搜索请求对象
|
||||
*
|
||||
* @author microservices
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("文章搜索请求对象")
|
||||
public class DocSearchRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 搜索关键词
|
||||
*/
|
||||
@ApiModelProperty(value = "搜索关键词", required = true)
|
||||
private String keyword;
|
||||
|
||||
/**
|
||||
* 专区ID
|
||||
*/
|
||||
@ApiModelProperty(value = "专区ID")
|
||||
private Long zoneId;
|
||||
|
||||
/**
|
||||
* 页码
|
||||
*/
|
||||
@ApiModelProperty(value = "页码")
|
||||
private Integer pageNum = 1;
|
||||
|
||||
/**
|
||||
* 每页数量
|
||||
*/
|
||||
@ApiModelProperty(value = "每页数量")
|
||||
private Integer pageSize = 20;
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package com.microservices.cms.search.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 全局搜索响应对象
|
||||
*
|
||||
* @author microservices
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("文章搜索响应对象")
|
||||
public class DocSearchResponse implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 总结果数
|
||||
*/
|
||||
@ApiModelProperty(value = "总结果数")
|
||||
private Long total;
|
||||
|
||||
/**
|
||||
* 搜索结果列表
|
||||
*/
|
||||
@ApiModelProperty(value = "搜索结果列表")
|
||||
private List<DocSearchResult> results;
|
||||
|
||||
/**
|
||||
* 各类型结果数量统计
|
||||
*/
|
||||
@ApiModelProperty(value = "各类型结果数量统计")
|
||||
private Map<String, Long> typeCounts;
|
||||
|
||||
/**
|
||||
* 搜索耗时(毫秒)
|
||||
*/
|
||||
@ApiModelProperty(value = "搜索耗时(毫秒)")
|
||||
private Long searchTime;
|
||||
|
||||
/**
|
||||
* 搜索关键词
|
||||
*/
|
||||
@ApiModelProperty(value = "搜索关键词")
|
||||
private String keyword;
|
||||
|
||||
/**
|
||||
* 当前页码
|
||||
*/
|
||||
@ApiModelProperty(value = "当前页码")
|
||||
private Integer pageNum;
|
||||
|
||||
/**
|
||||
* 每页数量
|
||||
*/
|
||||
@ApiModelProperty(value = "每页数量")
|
||||
private Integer pageSize;
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package com.microservices.cms.search.dto;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 文章搜索结果对象
|
||||
*
|
||||
* @author microservices
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("文章搜索结果对象")
|
||||
public class DocSearchResult implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@ApiModelProperty(value = "ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@ApiModelProperty(value = "标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 内容摘要
|
||||
*/
|
||||
@ApiModelProperty(value = "内容摘要")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 组织ID
|
||||
*/
|
||||
@ApiModelProperty(value = "组织ID")
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 相关度评分
|
||||
*/
|
||||
@ApiModelProperty(value = "相关度评分")
|
||||
private Double score;
|
||||
|
||||
/**
|
||||
* 扩展数据(JSON格式)
|
||||
*/
|
||||
@ApiModelProperty(value = "扩展数据")
|
||||
private JSONObject extendData;
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.microservices.cms.search.service;
|
||||
|
||||
import com.microservices.cms.search.dto.DocSearchRequest;
|
||||
import com.microservices.cms.search.dto.DocSearchResponse;
|
||||
|
||||
/**
|
||||
* 全局搜索服务接口
|
||||
*
|
||||
* @author microservices
|
||||
*/
|
||||
public interface IGlobalSearchService {
|
||||
|
||||
/**
|
||||
* 全局搜索
|
||||
*
|
||||
* @param request 搜索请求
|
||||
* @return 搜索响应
|
||||
*/
|
||||
DocSearchResponse docSearch(DocSearchRequest request);
|
||||
}
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
package com.microservices.cms.search.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.cms.doc.domain.CmsDoc;
|
||||
import com.microservices.cms.doc.domain.CmsDocWithScore;
|
||||
import com.microservices.cms.doc.mapper.CmsDocMapper;
|
||||
import com.microservices.cms.doc.service.ICmsDocService;
|
||||
import com.microservices.cms.search.service.IGlobalSearchService;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.common.redis.service.RedisService;
|
||||
import com.microservices.cms.search.dto.DocSearchRequest;
|
||||
import com.microservices.cms.search.dto.DocSearchResponse;
|
||||
import com.microservices.cms.search.dto.DocSearchResult;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.system.api.model.LoginUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 全局搜索服务实现
|
||||
*
|
||||
* @author microservices
|
||||
*/
|
||||
@Service
|
||||
public class GlobalSearchServiceImpl implements IGlobalSearchService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(GlobalSearchServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private CmsDocMapper cmsDocMapper;
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
@Autowired
|
||||
private ICmsDocService cmsDocService;
|
||||
|
||||
private static final String SEARCH_CACHE_PREFIX = "search:cache:";
|
||||
private static final Long CACHE_EXPIRE_SECONDS = 300L; // 5分钟
|
||||
|
||||
@Override
|
||||
public DocSearchResponse docSearch(DocSearchRequest request) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
// 参数校验
|
||||
if (StringUtils.isEmpty(request.getKeyword())) {
|
||||
return buildEmptyResponse(request);
|
||||
}
|
||||
|
||||
// 1. 尝试从缓存获取(仅第一页)
|
||||
if (request.getPageNum() == 1) {
|
||||
String cacheKey = buildCacheKey(request);
|
||||
|
||||
DocSearchResponse cached = redisService.getCacheObject(SEARCH_CACHE_PREFIX + cacheKey);
|
||||
if (cached != null) {
|
||||
cached.setSearchTime(System.currentTimeMillis() - startTime);
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 并行搜索各类型
|
||||
List<DocSearchResult> allResults = new ArrayList<>();
|
||||
Map<String, Long> typeCounts = new HashMap<>();
|
||||
|
||||
// 获取当前用户信息
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
|
||||
// 搜索CMS文章
|
||||
List<DocSearchResult> docResults = searchDocs(request);
|
||||
allResults.addAll(docResults);
|
||||
typeCounts.put("doc", (long) docResults.size());
|
||||
|
||||
// 3. 按相关度评分排序
|
||||
allResults.sort((a, b) -> {
|
||||
if (b.getScore() != null && a.getScore() != null) {
|
||||
return b.getScore().compareTo(a.getScore());
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
// 4. 分页
|
||||
int total = allResults.size();
|
||||
int start = (request.getPageNum() - 1) * request.getPageSize();
|
||||
int end = Math.min(start + request.getPageSize(), total);
|
||||
List<DocSearchResult> pagedResults = start < total ?
|
||||
allResults.subList(start, end) : new ArrayList<>();
|
||||
|
||||
// 5. 构建响应
|
||||
DocSearchResponse response = new DocSearchResponse();
|
||||
response.setTotal((long) total);
|
||||
response.setResults(pagedResults);
|
||||
response.setTypeCounts(typeCounts);
|
||||
response.setKeyword(request.getKeyword());
|
||||
response.setPageNum(request.getPageNum());
|
||||
response.setPageSize(request.getPageSize());
|
||||
response.setSearchTime(System.currentTimeMillis() - startTime);
|
||||
|
||||
// 6. 缓存结果(仅第一页)
|
||||
if (request.getPageNum() == 1) {
|
||||
String cacheKey = buildCacheKey(request);
|
||||
redisService.setCacheObject(SEARCH_CACHE_PREFIX + cacheKey, response, CACHE_EXPIRE_SECONDS, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
// 7. 记录搜索日志
|
||||
recordSearchLog(request, response, loginUser);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录搜索日志
|
||||
*/
|
||||
private void recordSearchLog(DocSearchRequest request, DocSearchResponse response, LoginUser loginUser) {
|
||||
Long userId = loginUser != null ? loginUser.getUserId() : null;
|
||||
String searchTypes = "文章";
|
||||
Long deptId = cmsDocService.getDeptIdByZoneId(request.getZoneId());
|
||||
logger.info("全局搜索 - 关键词: {}, 用户ID: {}, 耗时: {}ms, 结果数: {}, 类型: {}, 专区Id: {}, 组织ID: {}",
|
||||
request.getKeyword(),
|
||||
userId,
|
||||
response.getSearchTime(),
|
||||
response.getTotal(),
|
||||
searchTypes,
|
||||
request.getZoneId(),
|
||||
deptId
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索CMS文章
|
||||
*/
|
||||
private List<DocSearchResult> searchDocs(DocSearchRequest request) {
|
||||
List<DocSearchResult> results = new ArrayList<>();
|
||||
try {
|
||||
// 使用部门ID参数
|
||||
Long deptId = cmsDocService.getDeptIdByZoneId(request.getZoneId());
|
||||
|
||||
// 使用新的带评分的查询方法
|
||||
List<CmsDocWithScore> docs = cmsDocMapper.globalSearchWithScore(
|
||||
request.getKeyword(),
|
||||
deptId,
|
||||
(request.getPageNum() - 1) * request.getPageSize(),
|
||||
request.getPageSize()
|
||||
);
|
||||
|
||||
for (CmsDocWithScore doc : docs) {
|
||||
DocSearchResult result = new DocSearchResult();
|
||||
result.setId(doc.getId());
|
||||
result.setTitle(highlightKeyword(doc.getName(), request.getKeyword()));
|
||||
result.setContent(highlightKeyword(doc.getSummary(), request.getKeyword()));
|
||||
result.setDeptId(doc.getDeptId());
|
||||
result.setCreateTime(doc.getCreateTime());
|
||||
|
||||
// 使用数据库返回的实际搜索评分
|
||||
Double score = doc.getSearchScore();
|
||||
if (score == null || score == 0.0) {
|
||||
// 对于 LIKE 匹配(无全文评分),赋予最小评分
|
||||
score = 0.1;
|
||||
}
|
||||
result.setScore(score);
|
||||
|
||||
JSONObject extendData = new JSONObject();
|
||||
extendData.put("visits", doc.getVisits());
|
||||
extendData.put("publishTime", doc.getPublishTime());
|
||||
result.setExtendData(extendData);
|
||||
results.add(result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 记录错误但继续处理其他类型
|
||||
System.err.println("搜索CMS文章失败: " + e.getMessage());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建缓存键
|
||||
*/
|
||||
private String buildCacheKey(DocSearchRequest request) {
|
||||
Long deptId = cmsDocService.getDeptIdByZoneId(request.getZoneId());
|
||||
StringBuilder key = new StringBuilder(request.getKeyword());
|
||||
key.append(":").append(String.join(",", "Doc"));
|
||||
if (deptId != null) {
|
||||
key.append(":dept=").append(deptId);
|
||||
}
|
||||
return key.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建空响应
|
||||
*/
|
||||
private DocSearchResponse buildEmptyResponse(DocSearchRequest request) {
|
||||
DocSearchResponse response = new DocSearchResponse();
|
||||
response.setTotal(0L);
|
||||
response.setResults(new ArrayList<>());
|
||||
response.setTypeCounts(new HashMap<>());
|
||||
response.setKeyword(request.getKeyword());
|
||||
response.setPageNum(request.getPageNum());
|
||||
response.setPageSize(request.getPageSize());
|
||||
response.setSearchTime(0L);
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将文本中的关键词用 <em> 标签包裹(不区分大小写)
|
||||
*/
|
||||
private String highlightKeyword(String text, String keyword) {
|
||||
if (StringUtils.isEmpty(text) || StringUtils.isEmpty(keyword)) {
|
||||
return text;
|
||||
}
|
||||
return text.replaceAll("(?i)(" + Pattern.quote(keyword) + ")", "<em>$1</em>");
|
||||
}
|
||||
}
|
||||
|
|
@ -25,4 +25,24 @@ public class CmsConstants {
|
|||
* 是
|
||||
*/
|
||||
public final static String TRUE = "1";
|
||||
|
||||
/**
|
||||
* 专区积分异步队列 Redis Key(与 Zone 模块保持一致)
|
||||
*/
|
||||
public final static String ZONE_POINTS_ASYNC_QUEUE_KEY = "zone:points:async:queue";
|
||||
|
||||
/**
|
||||
* 发布文章积分类型
|
||||
*/
|
||||
public final static String PUBLISH_DOC = "publishDoc";
|
||||
|
||||
/**
|
||||
* 浏览文章积分类型
|
||||
*/
|
||||
public final static String VISITS_DOC = "visitsDoc";
|
||||
|
||||
/**
|
||||
* 精选文章积分类型
|
||||
*/
|
||||
public final static String FEATURED_DOC = "featuredDoc";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,18 @@ import java.util.Map;
|
|||
|
||||
public class CmsGitLinkRequestUrl extends GitLinkRequestUrl {
|
||||
|
||||
public static GitLinkRequestUrl ADD_USER_TO_ORGANIZATION_TEAM(String orgIdentifier, Long teamId) {
|
||||
return getAdminGitLinkRequestUrl(String.format("/api/organizations/%s/teams/%d/team_users.json", orgIdentifier, teamId));
|
||||
}
|
||||
|
||||
public static String TEAMS_BY_ORGANIZATION_URL(Long orgId) {
|
||||
return String.format("/api/organizations/%s/teams.json", orgId);
|
||||
}
|
||||
|
||||
public static GitLinkRequestUrl DELETE_USER_FROM_ORGANIZATION_TEAM(String orgIdentifier, Long teamId, String username) {
|
||||
return getAdminGitLinkRequestUrl(String.format("/api/organizations/%s/teams/%d/team_users/%s.json", orgIdentifier, teamId, username));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建项目
|
||||
*/
|
||||
|
|
@ -66,7 +78,7 @@ public class CmsGitLinkRequestUrl extends GitLinkRequestUrl {
|
|||
|
||||
public static GitLinkRequestUrl DELETE_BRANCH(CmsProject cmsProject, String branchName) {
|
||||
return getGitLinkRequestUrl(
|
||||
String.format("/api/v1/%s/%s/branches/%s.json", cmsProject.getUsername(), cmsProject.getIdentifier(), branchName)
|
||||
String.format("/api/v1/%s/%s/branches/delete.json?branch_name=%s", cmsProject.getUsername(), cmsProject.getIdentifier(), branchName)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -76,6 +88,12 @@ public class CmsGitLinkRequestUrl extends GitLinkRequestUrl {
|
|||
);
|
||||
}
|
||||
|
||||
public static GitLinkRequestUrl REOPEN_PULL_REQUEST(CmsProject cmsProject, String giteaPrNumber) {
|
||||
return getGitLinkRequestUrl(
|
||||
String.format("/api/v1/%s/%s/pulls/%s/reopen", cmsProject.getUsername(), cmsProject.getIdentifier(), giteaPrNumber)
|
||||
);
|
||||
}
|
||||
|
||||
public static GitLinkRequestUrl GET_PULL_REQUEST_DETAILS(CmsProject cmsProject, String giteaPrNumber) {
|
||||
return getGitLinkRequestUrl(
|
||||
String.format("/api/%s/%s/pulls/%s.json", cmsProject.getUsername(), cmsProject.getIdentifier(), giteaPrNumber)
|
||||
|
|
@ -101,7 +119,7 @@ public class CmsGitLinkRequestUrl extends GitLinkRequestUrl {
|
|||
}
|
||||
|
||||
public static GitLinkRequestUrl ADD_USER_FROM_PROJECT(CmsProject cmsProject) {
|
||||
return getGitLinkRequestUrl(
|
||||
return getAdminGitLinkRequestUrl(
|
||||
String.format("/api/%s/%s/collaborators.json", cmsProject.getUsername(), cmsProject.getIdentifier())
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 8080
|
||||
port: 9116
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
<result property="auditTmpBranchName" column="audit_tmp_branch_name"/>
|
||||
<result property="auditPrNumber" column="audit_pr_number"/>
|
||||
<result property="keywords" column="keywords"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectCmsDocVo">
|
||||
|
|
@ -71,7 +72,8 @@
|
|||
audit_type,
|
||||
audit_tmp_branch_name,
|
||||
keywords,
|
||||
audit_pr_number
|
||||
audit_pr_number,
|
||||
remark
|
||||
from cms_doc
|
||||
</sql>
|
||||
|
||||
|
|
@ -103,7 +105,51 @@
|
|||
cd.is_homepage,
|
||||
cd.editor_type,
|
||||
cd.keywords,
|
||||
cd.is_dir
|
||||
cd.is_dir,
|
||||
cd.audit_status,
|
||||
cd.audit_type,
|
||||
cd.audit_tmp_branch_name,
|
||||
cd.audit_pr_number,
|
||||
cd.remark
|
||||
from cms_doc cd
|
||||
</sql>
|
||||
|
||||
<sql id="selectCmsDocWithScoreVo">
|
||||
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,
|
||||
cd.head_img,
|
||||
cd.dir_name,
|
||||
cd.dept_id,
|
||||
cd.issue_id,
|
||||
cd.is_homepage,
|
||||
cd.editor_type,
|
||||
cd.keywords,
|
||||
cd.is_dir,
|
||||
cd.audit_status,
|
||||
cd.audit_type,
|
||||
cd.audit_tmp_branch_name,
|
||||
cd.audit_pr_number,
|
||||
-- 计算全文搜索相关度评分
|
||||
MATCH(cd.name, cd.summary) AGAINST(#{keyword} IN NATURAL LANGUAGE MODE) AS search_score,
|
||||
cd.remark
|
||||
from cms_doc cd
|
||||
</sql>
|
||||
|
||||
|
|
@ -141,9 +187,14 @@
|
|||
cd.is_homepage,
|
||||
cd.editor_type,
|
||||
cd.keywords,
|
||||
cd.is_dir
|
||||
cd.is_dir,
|
||||
cd.audit_status,
|
||||
cd.audit_type,
|
||||
cd.audit_tmp_branch_name,
|
||||
cd.audit_pr_number,
|
||||
cd.remark
|
||||
from cms_doc cd
|
||||
left join cms_doc dir on cd.dir_name = dir.name and cd.dept_id = dir.dept_id
|
||||
left join cms_doc dir on cd.dir_name = dir.name and cd.dept_id = dir.dept_id and dir.is_dir=1
|
||||
</sql>
|
||||
|
||||
<select id="selectCmsDocAndDirListByDept" resultMap="CmsDocResult">
|
||||
|
|
@ -166,10 +217,19 @@
|
|||
where id = #{id}
|
||||
</select>
|
||||
|
||||
<select id="selectCmsDocByIds" resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocVo"/>
|
||||
where id in
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<select id="selectCmsDocByNameAndDeptId" resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocVo"/>
|
||||
<where>
|
||||
and name = #{name}
|
||||
and audit_status != 0
|
||||
and dept_id = #{deptId}
|
||||
<choose>
|
||||
<when test="dirName != null">
|
||||
|
|
@ -181,6 +241,10 @@
|
|||
</choose>
|
||||
</where>
|
||||
</select>
|
||||
<select id="selectCmsDocByNameAndDeptIdIgnoreDirName" resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocVo"/>
|
||||
where name = #{name} and dept_id = #{deptId} and is_dir = 0
|
||||
</select>
|
||||
<select id="selectCmsDocDirByNameAndDeptId" resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocVo"/>
|
||||
where name = #{name} and dept_id = #{deptId} and is_dir = 1
|
||||
|
|
@ -221,6 +285,7 @@
|
|||
<if test="auditStatus != null and auditStatus != '-1' ">and audit_status = #{auditStatus}</if>
|
||||
<if test="auditStatus == null ">and audit_status = '1'</if>
|
||||
<if test="createBy != null and createBy != '' ">and create_by = #{createBy}</if>
|
||||
<if test="excludeId != null ">and id != #{excludeId}</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
|
|
@ -458,6 +523,7 @@
|
|||
<if test="auditTmpBranchName != null">audit_tmp_branch_name = #{auditTmpBranchName},</if>
|
||||
<if test="auditPrNumber != null">audit_pr_number = #{auditPrNumber},</if>
|
||||
<if test="keywords != null">keywords = #{keywords},</if>
|
||||
<if test="remark != null">remark = #{remark},</if>
|
||||
</trim>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
|
@ -494,4 +560,70 @@
|
|||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<!-- 全局搜索 - 全文索引查询(含 LIKE 后备搜索) -->
|
||||
<select id="globalSearch" resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocAliasVo"/>
|
||||
WHERE
|
||||
cd.is_dir = 0
|
||||
AND cd.audit_status = '1'
|
||||
AND (
|
||||
MATCH(cd.name, cd.summary) AGAINST(#{keyword} IN BOOLEAN MODE)
|
||||
OR cd.name LIKE CONCAT('%', #{keyword}, '%')
|
||||
OR cd.summary LIKE CONCAT('%', #{keyword}, '%')
|
||||
)
|
||||
<if test="deptId != null">
|
||||
AND cd.dept_id = #{deptId}
|
||||
</if>
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN MATCH(cd.name, cd.summary) AGAINST(#{keyword} IN BOOLEAN MODE) > 0 THEN 1
|
||||
ELSE 2
|
||||
END,
|
||||
cd.update_time DESC
|
||||
LIMIT #{offset}, #{pageSize}
|
||||
</select>
|
||||
|
||||
<select id="globalSearchCount" resultType="java.lang.Long">
|
||||
SELECT COUNT(*)
|
||||
FROM cms_doc cd
|
||||
WHERE
|
||||
cd.is_dir = 0
|
||||
AND cd.audit_status = '1'
|
||||
AND (
|
||||
MATCH(cd.name, cd.summary) AGAINST(#{keyword} IN BOOLEAN MODE)
|
||||
OR cd.name LIKE CONCAT('%', #{keyword}, '%')
|
||||
OR cd.summary LIKE CONCAT('%', #{keyword}, '%')
|
||||
)
|
||||
<if test="deptId != null">
|
||||
AND cd.dept_id = #{deptId}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<!-- ResultMap for CmsDocWithScore -->
|
||||
<resultMap type="com.microservices.cms.doc.domain.CmsDocWithScore" id="CmsDocWithScoreResult" extends="CmsDocResult">
|
||||
<result property="searchScore" column="search_score"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 全局搜索 - 带评分的全文索引查询 -->
|
||||
<select id="globalSearchWithScore" resultMap="CmsDocWithScoreResult">
|
||||
<include refid="selectCmsDocWithScoreVo"/>
|
||||
WHERE
|
||||
cd.is_dir = 0
|
||||
AND cd.audit_status = '1'
|
||||
AND (
|
||||
MATCH(cd.name, cd.summary) AGAINST(#{keyword} IN BOOLEAN MODE)
|
||||
OR cd.name LIKE CONCAT('%', #{keyword}, '%')
|
||||
OR cd.summary LIKE CONCAT('%', #{keyword}, '%')
|
||||
)
|
||||
<if test="deptId != null">
|
||||
AND cd.dept_id = #{deptId}
|
||||
</if>
|
||||
ORDER BY
|
||||
-- 主要排序:按相关度评分降序
|
||||
search_score DESC,
|
||||
-- 次要排序:更新时间降序
|
||||
cd.update_time DESC
|
||||
LIMIT #{offset}, #{pageSize}
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
@ -159,4 +159,38 @@
|
|||
item="id" collection="array" open="(" separator="," close=")">#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<!-- 全局搜索 - 全文索引查询 -->
|
||||
<select id="globalSearch" resultMap="CmsProjectResult">
|
||||
SELECT id,
|
||||
name,
|
||||
description,
|
||||
user_id,
|
||||
dept_id,
|
||||
identifier,
|
||||
username,
|
||||
create_by,
|
||||
create_time,
|
||||
update_time
|
||||
FROM cms_project cp
|
||||
WHERE
|
||||
MATCH(cp.name) AGAINST(#{keyword} IN NATURAL LANGUAGE MODE)
|
||||
<if test="deptId != null">
|
||||
AND cp.dept_id = #{deptId}
|
||||
</if>
|
||||
ORDER BY
|
||||
MATCH(cp.name) AGAINST(#{keyword} IN NATURAL LANGUAGE MODE) DESC,
|
||||
cp.update_time DESC
|
||||
LIMIT #{offset}, #{pageSize}
|
||||
</select>
|
||||
|
||||
<select id="globalSearchCount" resultType="java.lang.Long">
|
||||
SELECT COUNT(*)
|
||||
FROM cms_project cp
|
||||
WHERE
|
||||
MATCH(cp.name) AGAINST(#{keyword} IN NATURAL LANGUAGE MODE)
|
||||
<if test="deptId != null">
|
||||
AND cp.dept_id = #{deptId}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
@ -87,18 +87,10 @@
|
|||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-swagger</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-log</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-core</artifactId>
|
||||
|
|
@ -133,7 +125,7 @@
|
|||
<dependency>
|
||||
<groupId>com.hankcs</groupId>
|
||||
<artifactId>hanlp</artifactId>
|
||||
<version>portable-1.3.4</version>
|
||||
<version>portable-1.8.4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,17 +9,14 @@ import com.microservices.common.log.enums.BusinessType;
|
|||
import com.microservices.dms.achievementLibrary.domain.AchQueryVo;
|
||||
import com.microservices.dms.achievementLibrary.domain.Achievements;
|
||||
import com.microservices.dms.achievementLibrary.service.IAchievementsService;
|
||||
import com.microservices.system.api.RemoteFileService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 成果Controller
|
||||
*
|
||||
|
|
@ -33,17 +30,13 @@ public class AchievementsController extends BaseController {
|
|||
@Autowired
|
||||
private IAchievementsService achievementsService;
|
||||
|
||||
@Autowired
|
||||
private RemoteFileService remoteFileService;
|
||||
|
||||
/**
|
||||
* 查询成果列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(AchQueryVo achQueryVo) {
|
||||
public TableDataInfo list(Achievements achievements) {
|
||||
startPage();
|
||||
achQueryVo.setAllStatus(true);
|
||||
List<Achievements> list = achievementsService.getAllResult(achQueryVo);
|
||||
List<Achievements> list = achievementsService.selectAchievementsList(achievements);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
|
|
@ -52,8 +45,8 @@ public class AchievementsController extends BaseController {
|
|||
*/
|
||||
@Log(title = "成果", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, AchQueryVo achQueryVo) {
|
||||
List<Achievements> list = achievementsService.selectAchievementsList(achQueryVo);
|
||||
public void export(HttpServletResponse response, Achievements achievements) {
|
||||
List<Achievements> list = achievementsService.selectAchievementsList(achievements);
|
||||
ExcelUtil<Achievements> util = new ExcelUtil<Achievements>(Achievements.class);
|
||||
util.exportExcel(response, list, "成果数据");
|
||||
}
|
||||
|
|
@ -63,7 +56,7 @@ public class AchievementsController extends BaseController {
|
|||
*/
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
||||
return success(achievementsService.selectAchievementsById(id, false));
|
||||
return success(achievementsService.selectAchievementsById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -222,20 +215,19 @@ public class AchievementsController extends BaseController {
|
|||
public AjaxResult getWatchFavoriteStatusById(Long id, Long userId) {
|
||||
return success(achievementsService.getWatchFavoriteStatusById(id, userId));
|
||||
}
|
||||
|
||||
@ApiOperation("根据成果ID,获取近7日成果点击数量(折线图)")
|
||||
@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) {
|
||||
return success(achievementsService.get7AddClickById(id, clickType));
|
||||
return success(achievementsService.get7AddClickById(id,clickType));
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation("根据专家id,获取近7日成果点击数量(折线图)")
|
||||
@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) {
|
||||
return success(achievementsService.get7AddClickById(id, clickType));
|
||||
return success(achievementsService.get7AddClickById(id,clickType));
|
||||
}
|
||||
|
||||
@ApiOperation("根据成果ID,获取成果的相关行为数据统计(点击量、搜索量、附件下载量、收藏、关注)")
|
||||
|
|
@ -251,24 +243,21 @@ public class AchievementsController extends BaseController {
|
|||
return success(achievementsService.getAllAreas(areaName));
|
||||
}
|
||||
|
||||
@ApiOperation("根据已有数据,获取融办名称数据")
|
||||
@GetMapping("/getAllField2")
|
||||
public AjaxResult getAllField2() {
|
||||
return success(achievementsService.getAllField2());
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation("根据领域,将成果数据进行分类")
|
||||
@GetMapping("/getAreaStatistic")
|
||||
public AjaxResult getAreaStatistic(String areaKey) {
|
||||
public AjaxResult getAreaStatistic(String areaKey)
|
||||
{
|
||||
return success(achievementsService.getAreaStatistic(areaKey));
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation("根据领域获取领域详情")
|
||||
@GetMapping("/getAreaDetail")
|
||||
public AjaxResult getAreaDetail(String areaKey, String kyxmSum, String source) {
|
||||
return success(achievementsService.getAreaDetail(areaKey, kyxmSum, source));
|
||||
public AjaxResult getAreaDetail(String areaKey,String kyxmSum,String source)
|
||||
{
|
||||
return success(achievementsService.getAreaDetail(areaKey,kyxmSum,source));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -276,59 +265,46 @@ public class AchievementsController extends BaseController {
|
|||
*/
|
||||
@ApiOperation(value = "获取开源项目的相关成果")
|
||||
@GetMapping("/getRelatedAch")
|
||||
public AjaxResult getRelatedAch(Long id, Long sourceId) {
|
||||
return success(achievementsService.getRelatedAch(id, sourceId));
|
||||
public AjaxResult getRelatedAch(Long id,Long sourceId)
|
||||
{
|
||||
return success(achievementsService.getRelatedAch(id,sourceId));
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation(value = "获取开源竞赛的相关成果")
|
||||
@GetMapping("/getRelatedAchCompetition")
|
||||
public AjaxResult getRelatedAchCompetition(Long id, Long sourceId) {
|
||||
return success(achievementsService.getRelatedAchCompetition(id, sourceId));
|
||||
public AjaxResult getRelatedAchCompetition(Long id,Long sourceId)
|
||||
{
|
||||
return success(achievementsService.getRelatedAchCompetition(id,sourceId));
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation(value = "获取创客任务的相关成果")
|
||||
@GetMapping("/getRelatedAchTask")
|
||||
public AjaxResult getRelatedAchTask(Long id, Long sourceId) {
|
||||
return success(achievementsService.getRelatedAchTask(id, sourceId));
|
||||
public AjaxResult getRelatedAchTask(Long id,Long sourceId)
|
||||
{
|
||||
return success(achievementsService.getRelatedAchTask(id,sourceId));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取专家-创客任务的相关成果")
|
||||
@GetMapping("/getRelatedAchTaskOfExpert")
|
||||
public AjaxResult getRelatedAchTaskOfExpert(Long expertId) {
|
||||
public AjaxResult getRelatedAchTaskOfExpert(Long expertId)
|
||||
{
|
||||
return success(achievementsService.getRelatedAchTaskOfExpert(expertId));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取专家-开源竞赛的相关成果")
|
||||
@GetMapping("/getRelatedAchCompetitionOfExpert")
|
||||
public AjaxResult getRelatedAchCompetitionOfExpert(Long expertId) {
|
||||
public AjaxResult getRelatedAchCompetitionOfExpert(Long expertId)
|
||||
{
|
||||
return success(achievementsService.getRelatedAchCompetitionOfExpert(expertId));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "搜索行为数据记录")
|
||||
@GetMapping("/getSearchResult")
|
||||
public AjaxResult getSearchResult(String achName, Long 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));
|
||||
public AjaxResult getSearchResult(String achName,Long userId)
|
||||
{
|
||||
return success(achievementsService.getSearchResult(achName,userId));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import com.microservices.common.core.web.domain.AjaxResult;
|
|||
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.achievementLibrary.domain.SchoolEnterpriseAchievements;
|
||||
import com.microservices.dms.achievementLibrary.service.ISchoolEnterpriseAchievementsService;
|
||||
import io.swagger.annotations.Api;
|
||||
|
|
@ -16,11 +15,9 @@ import io.swagger.annotations.ApiImplicitParams;
|
|||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 校企成果Controller
|
||||
|
|
@ -93,21 +90,6 @@ public class SchoolEnterpriseAchievementsController extends BaseController
|
|||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改校企成果
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,25 +1,12 @@
|
|||
package com.microservices.dms.achievementLibrary.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AchQueryVo {
|
||||
|
||||
private String areaQuery;//领域
|
||||
private String source;//来源
|
||||
private String achievementType;//成果类型
|
||||
private String achievementName;//名称
|
||||
private String userId;
|
||||
private Long userId;
|
||||
private String showAchievementName;
|
||||
private String rongbanName;
|
||||
private String maturityLevel; //成果成熟度
|
||||
private String sortBy; //排序字段
|
||||
private String sortOrder; //升降序
|
||||
private Boolean userSelf = false; //用户自己
|
||||
private Boolean allStatus = false; //所有状态
|
||||
|
||||
private List<String> achievementTypeList;//成果类型
|
||||
private List<String> sourceList;//成果类型
|
||||
|
||||
public String getAreaQuery() {
|
||||
return areaQuery;
|
||||
}
|
||||
|
|
@ -44,11 +31,11 @@ public class AchQueryVo {
|
|||
this.achievementName = achievementName;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
public void setUserId(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
|
|
@ -59,77 +46,4 @@ public class AchQueryVo {
|
|||
public void setShowAchievementName(String showAchievementName) {
|
||||
this.showAchievementName = showAchievementName;
|
||||
}
|
||||
|
||||
public String getRongbanName() {
|
||||
return rongbanName;
|
||||
}
|
||||
|
||||
public void setRongbanName(String rongbanName) {
|
||||
this.rongbanName = rongbanName;
|
||||
}
|
||||
|
||||
|
||||
public List<String> getAchievementTypeList() {
|
||||
return achievementTypeList;
|
||||
}
|
||||
|
||||
public void setAchievementTypeList(List<String> achievementTypeList) {
|
||||
this.achievementTypeList = achievementTypeList;
|
||||
}
|
||||
|
||||
public List<String> getSourceList() {
|
||||
return sourceList;
|
||||
}
|
||||
|
||||
public void setSourceList(List<String> sourceList) {
|
||||
this.sourceList = sourceList;
|
||||
}
|
||||
|
||||
public String getMaturityLevel() {
|
||||
return maturityLevel;
|
||||
}
|
||||
|
||||
public void setMaturityLevel(String maturityLevel) {
|
||||
this.maturityLevel = maturityLevel;
|
||||
}
|
||||
|
||||
public String getAchievementType() {
|
||||
return achievementType;
|
||||
}
|
||||
|
||||
public void setAchievementType(String achievementType) {
|
||||
this.achievementType = achievementType;
|
||||
}
|
||||
|
||||
public String getSortBy() {
|
||||
return sortBy;
|
||||
}
|
||||
|
||||
public void setSortBy(String sortBy) {
|
||||
this.sortBy = sortBy;
|
||||
}
|
||||
|
||||
public String getSortOrder() {
|
||||
return sortOrder;
|
||||
}
|
||||
|
||||
public void setSortOrder(String sortOrder) {
|
||||
this.sortOrder = sortOrder;
|
||||
}
|
||||
|
||||
public Boolean getUserSelf() {
|
||||
return userSelf;
|
||||
}
|
||||
|
||||
public void setUserSelf(Boolean userSelf) {
|
||||
this.userSelf = userSelf;
|
||||
}
|
||||
|
||||
public Boolean getAllStatus() {
|
||||
return allStatus;
|
||||
}
|
||||
|
||||
public void setAllStatus(Boolean allStatus) {
|
||||
this.allStatus = allStatus;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
package com.microservices.dms.achievementLibrary.domain;
|
||||
|
||||
import com.microservices.system.api.domain.SysDictData;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AchievementSourceDictVo extends SysDictData {
|
||||
private Long cnt;
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
package com.microservices.dms.achievementLibrary.domain;
|
||||
|
||||
import com.microservices.system.api.domain.SysDictData;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AchievementTypeDictVo extends SysDictData {
|
||||
private Long cnt;
|
||||
}
|
||||
|
|
@ -38,37 +38,33 @@ public class Achievements extends BaseEntity {
|
|||
/**
|
||||
* 成果领域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=计算机网络"
|
||||
// )
|
||||
@Excel(name = "成果领域一级")
|
||||
@Excel(name = "成果领域1")
|
||||
private String field1;
|
||||
//成果领域名称
|
||||
private String field1Name;
|
||||
|
||||
/**
|
||||
* 成果领域二级
|
||||
* 成果领域2
|
||||
*/
|
||||
@Excel(name = "成果领域二级")
|
||||
@Excel(name = "成果领域2")
|
||||
private String field2;
|
||||
|
||||
/**
|
||||
* 融办描述
|
||||
* 成果领域3
|
||||
*/
|
||||
@Excel(name = "融办描述")
|
||||
@Excel(name = "成果领域3")
|
||||
private String field3;
|
||||
|
||||
/**
|
||||
* 成果类型
|
||||
*/
|
||||
@Excel(name = "成果类型", readConverterExp = "1=基础研究成果,2=技术开发成果,3=应用研究成果,4=软科学成果")
|
||||
@Excel(name = "成果类型")
|
||||
private String achievementType;
|
||||
|
||||
/**
|
||||
* 成果来源
|
||||
*/
|
||||
@Excel(name = "成果来源渠道", readConverterExp = "1=开源项目,2=创客任务,3=开放竞赛,4=校企成果,5=省市融办", defaultValue = "5")
|
||||
@Excel(name = "成果来源")
|
||||
private String source;
|
||||
|
||||
/**
|
||||
|
|
@ -78,15 +74,15 @@ public class Achievements extends BaseEntity {
|
|||
private Long sourceId;
|
||||
|
||||
/**
|
||||
* 成果来源URL
|
||||
* 成果来源跳转链接
|
||||
*/
|
||||
@Excel(name = "成果来源URL")
|
||||
@Excel(name = "成果来源跳转链接")
|
||||
private String sourceLink;
|
||||
|
||||
/**
|
||||
* 成果标签
|
||||
*/
|
||||
@Excel(name = "成果标签", readConverterExp = "1=高校,2=企业,3=其他")
|
||||
@Excel(name = "成果标签")
|
||||
private String tags;
|
||||
|
||||
/**
|
||||
|
|
@ -96,15 +92,15 @@ public class Achievements extends BaseEntity {
|
|||
private String summary;
|
||||
|
||||
/**
|
||||
* 成果提供方
|
||||
* 发布单位
|
||||
*/
|
||||
@Excel(name = "成果提供方")
|
||||
@Excel(name = "发布单位")
|
||||
private String publishingUnit;
|
||||
|
||||
/**
|
||||
* 单位概况
|
||||
* 成果地址
|
||||
*/
|
||||
@Excel(name = "单位概况")
|
||||
@Excel(name = "成果地址")
|
||||
private String address;
|
||||
|
||||
/**
|
||||
|
|
@ -120,9 +116,9 @@ public class Achievements extends BaseEntity {
|
|||
private String contactPerson;
|
||||
|
||||
/**
|
||||
* 联系方式
|
||||
* 联系电话
|
||||
*/
|
||||
@Excel(name = "联系方式")
|
||||
@Excel(name = "联系电话")
|
||||
private String contactNumber;
|
||||
|
||||
/**
|
||||
|
|
@ -144,9 +140,9 @@ public class Achievements extends BaseEntity {
|
|||
private String status;
|
||||
|
||||
/**
|
||||
* 成果简介
|
||||
* 成果详情
|
||||
*/
|
||||
@Excel(name = "成果简介")
|
||||
@Excel(name = "成果详情")
|
||||
private String details;
|
||||
|
||||
/**
|
||||
|
|
@ -171,7 +167,7 @@ public class Achievements extends BaseEntity {
|
|||
/**
|
||||
* 成果图片
|
||||
*/
|
||||
@Excel(name = "图片")
|
||||
@Excel(name = "成果图片")
|
||||
private String images;
|
||||
|
||||
/**
|
||||
|
|
@ -180,32 +176,20 @@ public class Achievements extends BaseEntity {
|
|||
@Excel(name = "成果附件")
|
||||
private String attachments;
|
||||
|
||||
@Excel(name = "成果图片视频")
|
||||
//成果小类
|
||||
private String ext1;
|
||||
|
||||
@Excel(name = "应用图片视频")
|
||||
//成果状态
|
||||
private String ext2;
|
||||
|
||||
@Excel(name = "应用场景")
|
||||
//成果团队名称
|
||||
private String ext3;
|
||||
|
||||
private String ext4;
|
||||
private String ext5;
|
||||
|
||||
@Excel(name = "成果载体")
|
||||
private String storageType;
|
||||
@Excel(name = "成果成熟度")
|
||||
private String maturityLevel;
|
||||
@Excel(name = "推介范围")
|
||||
private String recommendScope;
|
||||
|
||||
private Long clickSum;
|
||||
private Long watcherSum;
|
||||
private Long favoriteSum;
|
||||
private Long dockSum;
|
||||
private String filedDesc;
|
||||
private Float hotRank;
|
||||
private int attachmentCount;
|
||||
private Long attachmentCount;
|
||||
private Integer isExpertAudit;
|
||||
private String userImg;
|
||||
private String userNickName;
|
||||
|
|
@ -237,22 +221,6 @@ public class Achievements extends BaseEntity {
|
|||
this.ext3 = ext3;
|
||||
}
|
||||
|
||||
public String getExt4() {
|
||||
return ext4;
|
||||
}
|
||||
|
||||
public void setExt4(String ext4) {
|
||||
this.ext4 = ext4;
|
||||
}
|
||||
|
||||
public String getExt5() {
|
||||
return ext5;
|
||||
}
|
||||
|
||||
public void setExt5(String ext5) {
|
||||
this.ext5 = ext5;
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getDockingUserInfo() {
|
||||
return dockingUserInfo;
|
||||
}
|
||||
|
|
@ -357,11 +325,11 @@ public class Achievements extends BaseEntity {
|
|||
this.isExpertAudit = isExpertAudit;
|
||||
}
|
||||
|
||||
public int getAttachmentCount() {
|
||||
public Long getAttachmentCount() {
|
||||
return attachmentCount;
|
||||
}
|
||||
|
||||
public void setAttachmentCount(int attachmentCount) {
|
||||
public void setAttachmentCount(Long attachmentCount) {
|
||||
this.attachmentCount = attachmentCount;
|
||||
}
|
||||
|
||||
|
|
@ -583,27 +551,4 @@ public class Achievements extends BaseEntity {
|
|||
return attachments;
|
||||
}
|
||||
|
||||
public String getStorageType() {
|
||||
return storageType;
|
||||
}
|
||||
|
||||
public void setStorageType(String storageType) {
|
||||
this.storageType = storageType;
|
||||
}
|
||||
|
||||
public String getMaturityLevel() {
|
||||
return maturityLevel;
|
||||
}
|
||||
|
||||
public void setMaturityLevel(String maturityLevel) {
|
||||
this.maturityLevel = maturityLevel;
|
||||
}
|
||||
|
||||
public String getRecommendScope() {
|
||||
return recommendScope;
|
||||
}
|
||||
|
||||
public void setRecommendScope(String recommendScope) {
|
||||
this.recommendScope = recommendScope;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,10 +32,7 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
|||
/**
|
||||
* 成果领域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=计算机网络"
|
||||
)
|
||||
@Excel(name = "成果领域1")
|
||||
private String field1;
|
||||
|
||||
/**
|
||||
|
|
@ -53,7 +50,7 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
|||
/**
|
||||
* 成果类型
|
||||
*/
|
||||
@Excel(name = "成果类型", readConverterExp = "1=理论成果,2=技术成果,3=应用成果,4=软科学成果,5=文化艺术成果,6=社会服务成果,7=交叉领域成果")
|
||||
@Excel(name = "成果类型")
|
||||
private String achievementType;
|
||||
|
||||
/**
|
||||
|
|
@ -77,10 +74,7 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
|||
/**
|
||||
* 成果标签
|
||||
*/
|
||||
@Excel(
|
||||
name = "成果标签",
|
||||
readConverterExp = "1=高校,2=企业,3=其他"
|
||||
)
|
||||
@Excel(name = "成果标签")
|
||||
private String tags;
|
||||
|
||||
/**
|
||||
|
|
@ -165,7 +159,7 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
|||
/**
|
||||
* 成果图片
|
||||
*/
|
||||
@Excel(name = "图片")
|
||||
@Excel(name = "成果图片")
|
||||
private String images;
|
||||
|
||||
/**
|
||||
|
|
@ -175,18 +169,10 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
|||
private String attachments;
|
||||
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;
|
||||
@Excel(
|
||||
name = "成果状态",
|
||||
readConverterExp = "1=已有阶段性成果,2=已有成熟成果,3=已公开发表,4=已对外发布,5=已开展应用,6=已形成商业化产品"
|
||||
)
|
||||
//成果状态
|
||||
private String achievementCurStatus;
|
||||
//团队名称
|
||||
@Excel(name = "成果团队名称")
|
||||
private String teamName;
|
||||
|
||||
private List<AchievementTeam> teamList;
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@ import com.microservices.common.datasource.annotation.Master;
|
|||
import com.microservices.common.datasource.annotation.Slave;
|
||||
import com.microservices.dms.achievementLibrary.domain.*;
|
||||
import com.microservices.dms.behaviorImage.domain.AchievementBehaviorSumVo;
|
||||
import com.microservices.dms.achievementLibrary.domain.AchievementSourceStatisticVo;
|
||||
import com.microservices.dms.common.vo.NameCountVo;
|
||||
import com.microservices.dms.resourceLibrary.domain.CompetitionResourceLibrary;
|
||||
import com.microservices.dms.resourceLibrary.domain.TaskResourceLibrary;
|
||||
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
||||
import org.apache.ibatis.annotations.MapKey;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
|
||||
/**
|
||||
* 成果Mapper接口
|
||||
|
|
@ -31,7 +30,6 @@ public interface AchievementsMapper {
|
|||
* @return 成果
|
||||
*/
|
||||
public Achievements selectAchievementsById(Long id);
|
||||
public Achievements selectAchievementsByAchievementName(String achievementName);
|
||||
|
||||
/**
|
||||
* 查询成果列表
|
||||
|
|
@ -84,7 +82,6 @@ public interface AchievementsMapper {
|
|||
List<KeyValueVo> getTjByAreas();
|
||||
|
||||
List<Achievements> selectAchievementsByParam(AchQueryVo achQueryVo);
|
||||
List<Achievements> selectAchievementsByParamNew(AchQueryVo achQueryVo);
|
||||
|
||||
Long getAchievementClickSum(@Param("id") Long id);
|
||||
|
||||
|
|
@ -168,18 +165,10 @@ public interface AchievementsMapper {
|
|||
List<KeyValVo<String, Long>> getExperts(@Param("s") Date s, @Param("e") Date e);
|
||||
|
||||
List<KeyValueVo> getAllAreas(@Param("areaName") String areaName);
|
||||
List<KeyValueVo> getAllField2();
|
||||
|
||||
void updateRelationAchievements(@Param("source") String source,@Param("sourceId") Long sourceId);
|
||||
|
||||
List<Map<String, Object>> getDockingUserInfoList(@Param("id") Long id);
|
||||
|
||||
String getField1RemarkByParam(@Param("source")String source,@Param("areaKey") String areaKey);
|
||||
|
||||
AchievementSourceStatisticVo getSource5Statistic(@Param("name") String name);
|
||||
AchievementSourceStatisticVo getSource5Field2(@Param("name") String name);
|
||||
|
||||
List<NameCountVo> groupByAchievementsType();
|
||||
List<NameCountVo> groupByAchievementsSource();
|
||||
int isGitlinkAdminUser(@Param("gitlinkUserId") Long gitlinkUserId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,9 @@ import java.util.Map;
|
|||
|
||||
import com.microservices.dms.achievementLibrary.domain.*;
|
||||
import com.microservices.dms.behaviorImage.domain.AchievementBehaviorSumVo;
|
||||
import com.microservices.dms.achievementLibrary.domain.AchievementSourceStatisticVo;
|
||||
import com.microservices.dms.common.vo.NameCountVo;
|
||||
import com.microservices.dms.resourceLibrary.domain.CompetitionResourceLibrary;
|
||||
import com.microservices.dms.resourceLibrary.domain.TaskResourceLibrary;
|
||||
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 成果Service接口
|
||||
|
|
@ -25,15 +22,15 @@ public interface IAchievementsService {
|
|||
* @param id 成果主键
|
||||
* @return 成果
|
||||
*/
|
||||
public Achievements selectAchievementsById(Long id, Boolean isOpenView);
|
||||
public Achievements selectAchievementsById(Long id);
|
||||
|
||||
/**
|
||||
* 查询成果列表
|
||||
*
|
||||
* @param achQueryVo 成果
|
||||
* @param achievements 成果
|
||||
* @return 成果集合
|
||||
*/
|
||||
public List<Achievements> selectAchievementsList(AchQueryVo achQueryVo);
|
||||
public List<Achievements> selectAchievementsList(Achievements achievements);
|
||||
|
||||
/**
|
||||
* 新增成果
|
||||
|
|
@ -109,8 +106,6 @@ public interface IAchievementsService {
|
|||
|
||||
int getSearchResult(String achName, Long userId);
|
||||
|
||||
AchievementSourceStatisticVo getSource5Statistic(String name);
|
||||
|
||||
List<KeyValueVo> getProjectAreasByName(String areaName);
|
||||
|
||||
List<String> getExpertAreasByName(String areaName);
|
||||
|
|
@ -128,13 +123,5 @@ public interface IAchievementsService {
|
|||
List<KeyValVo<String, Long>> get7DayAddExport(AchQueryVo achQueryVo);
|
||||
|
||||
List<KeyValueVo> getAllAreas(String areaName);
|
||||
List<KeyValueVo> getAllField2();
|
||||
|
||||
Map<String, Object> batchInsertAchievements(List<Achievements> list, boolean updateSupport, String operName);
|
||||
|
||||
String batchImportAchievementsZip(MultipartFile file, boolean updateSupport);
|
||||
|
||||
List<AchievementTypeDictVo> achievementsTypeStatistic();
|
||||
|
||||
List<AchievementSourceDictVo> achievementsSourceStatistic();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
package com.microservices.dms.achievementLibrary.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.microservices.dms.achievementLibrary.domain.SchoolEnterpriseAchievements;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 校企成果Service接口
|
||||
|
|
@ -67,6 +64,4 @@ public interface ISchoolEnterpriseAchievementsService
|
|||
List<SchoolEnterpriseAchievements> listFront(SchoolEnterpriseAchievements schoolEnterpriseAchievements);
|
||||
|
||||
boolean getCheckSchoolAchName(SchoolEnterpriseAchievements schoolEnterpriseAchievements);
|
||||
|
||||
String batchInsertSchoolEnterpriseAchievements(List<SchoolEnterpriseAchievements> list, Map<String, MultipartFile> imageMap, boolean updateSupport, String operName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,57 +1,40 @@
|
|||
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.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
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.StringUtils;
|
||||
import com.microservices.common.core.utils.poi.ExcelUtil;
|
||||
import com.microservices.common.httpClient.service.HttpAPIService;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
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.AchievementImageVo;
|
||||
import com.microservices.dms.achievementLibrary.domain.AchievementSourceStatisticVo;
|
||||
import com.microservices.dms.behaviorImage.service.IBehaviorImageService;
|
||||
import com.microservices.dms.common.vo.AchievementSysFileVo;
|
||||
import com.microservices.dms.common.vo.NameCountVo;
|
||||
import com.microservices.dms.resourceLibrary.domain.*;
|
||||
import com.microservices.dms.resourceLibrary.domain.Clicker;
|
||||
import com.microservices.dms.resourceLibrary.domain.CompetitionResourceLibrary;
|
||||
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.mapper.CompetitionResourceLibraryMapper;
|
||||
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.utils.CustomMultipartFile;
|
||||
import com.microservices.dms.utils.DateUtil;
|
||||
import com.microservices.dms.utils.FileMultipartFile;
|
||||
import com.microservices.system.api.RemoteDictDataService;
|
||||
import com.microservices.system.api.RemoteFileService;
|
||||
import com.microservices.system.api.domain.SysDictData;
|
||||
import com.microservices.system.api.domain.SysFile;
|
||||
import com.microservices.system.api.domain.SysFileInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.checkerframework.checker.units.qual.K;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.microservices.dms.achievementLibrary.mapper.AchievementsMapper;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
|
@ -63,9 +46,6 @@ import static com.microservices.dms.utils.UrlUtil.getUrlPath;
|
|||
@Service
|
||||
@Slf4j
|
||||
public class AchievementsServiceImpl implements IAchievementsService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AchievementsServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private AchievementsMapper achievementsMapper;
|
||||
|
||||
|
|
@ -79,12 +59,6 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
|||
@Autowired
|
||||
private IBehaviorImageService behaviorImageService;
|
||||
|
||||
@Autowired
|
||||
private RemoteFileService remoteFileService;
|
||||
|
||||
@Autowired
|
||||
private RemoteDictDataService remoteDictDataService;
|
||||
|
||||
@Value("${makerSpaceUrl}")
|
||||
public String makerSpaceUrl;
|
||||
|
||||
|
|
@ -101,7 +75,7 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
|||
* @return 成果
|
||||
*/
|
||||
@Override
|
||||
public Achievements selectAchievementsById(Long id, Boolean isOpenView) {
|
||||
public Achievements selectAchievementsById(Long id) {
|
||||
Achievements a = achievementsMapper.selectAchievementsById(id);
|
||||
if (StringUtils.isNotNull(a)) {
|
||||
String gender = a.getGender();
|
||||
|
|
@ -112,20 +86,16 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
|||
img = "images/avatars/User/boy.jpg";
|
||||
}
|
||||
a.setUserImg(img);
|
||||
if (StringUtils.isNotEmpty(a.getField1()) && !a.getSource().equals("5")) {
|
||||
if (StringUtils.isNotEmpty(a.getField1())) {
|
||||
String field1Name = achievementsMapper.getField1NameByParam(a.getSource(), a.getId());
|
||||
if (StringUtils.isNotNull(field1Name)) {
|
||||
a.setField1Name(field1Name);
|
||||
}
|
||||
}
|
||||
a.setUserImg(img);
|
||||
a.setImages( a.getImages() == null ? null : a.getImages().replace("/api/file/common/downloadByIdentifier/", "/api/file/open/downloadByIdentifier/"));
|
||||
if (isOpenView){
|
||||
a.setAttachments(buildFileInfoByIdents(a.getAttachments(), a.getSource()));
|
||||
}
|
||||
//拼接对接的用户信息
|
||||
List<Map<String,Object>> dockingUserInfo = achievementsMapper.getDockingUserInfoList(a.getId());
|
||||
a.setDockingUserInfo(dockingUserInfo);
|
||||
|
||||
a.setImages(buildFileInfoByIdents(a.getImages(), a.getSource()));
|
||||
a.setAttachments(buildFileInfoByIdents(a.getAttachments(), a.getSource()));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
|
@ -133,12 +103,36 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
|||
/**
|
||||
* 查询成果列表
|
||||
*
|
||||
* @param achQueryVo 成果
|
||||
* @param achievements 成果
|
||||
* @return 成果
|
||||
*/
|
||||
@Override
|
||||
public List<Achievements> selectAchievementsList(AchQueryVo achQueryVo) {
|
||||
return getAllResult(achQueryVo);
|
||||
public List<Achievements> selectAchievementsList(Achievements achievements) {
|
||||
List<Achievements> list = achievementsMapper.selectAchievementsList(achievements);
|
||||
for (Achievements a : list) {
|
||||
String gender = a.getGender();
|
||||
String img = "";
|
||||
if (StringUtils.isNotEmpty(gender) && gender.equals("1")) {
|
||||
img = "images/avatars/User/girl.jpg";
|
||||
} else if (StringUtils.isNotEmpty(gender) && gender.equals("0")) {
|
||||
img = "images/avatars/User/boy.jpg";
|
||||
}
|
||||
a.setUserImg(img);
|
||||
//根据id获取领域名称
|
||||
if (StringUtils.isNotEmpty(a.getField1())) {
|
||||
String field1Name = achievementsMapper.getField1NameByParam(a.getSource(), a.getId());
|
||||
if (StringUtils.isNotNull(field1Name)) {
|
||||
a.setField1Name(field1Name);
|
||||
}
|
||||
}
|
||||
a.setImages(buildFileInfoByIdents(a.getImages(), a.getSource()));
|
||||
a.setAttachments(buildFileInfoByIdents(a.getAttachments(), a.getSource()));
|
||||
|
||||
//拼接对接的用户信息
|
||||
List<Map<String,Object>> dockingUserInfo = achievementsMapper.getDockingUserInfoList(a.getId());
|
||||
a.setDockingUserInfo(dockingUserInfo);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -202,7 +196,7 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
|||
Achievements achievements = achievementsMapper.selectAchievementsById(id);
|
||||
if(achievements != null){
|
||||
String source = achievements.getSource();
|
||||
if(StringUtils.isNotEmpty(source) && !source.equals("5")) {
|
||||
if(StringUtils.isNotEmpty(source)) {
|
||||
achievementsMapper.updateRelationAchievements(source,achievements.getSourceId());
|
||||
}
|
||||
}
|
||||
|
|
@ -217,10 +211,20 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
|||
|
||||
List<Map<String, String>> list = JSON.parseObject(aStr, new TypeReference<List<Map<String, String>>>() {
|
||||
});
|
||||
List<Map<String, String>> filterList = list.stream()
|
||||
.filter(item -> !item.getOrDefault("name","").contains("入驻承诺书"))
|
||||
.collect(Collectors.toList());
|
||||
return JSON.toJSONString(filterList);
|
||||
|
||||
if (Objects.equals(source, "1") || Objects.equals(source, "3")) {
|
||||
concatUrl(list, gitLinkUrl);
|
||||
}
|
||||
|
||||
if (Objects.equals(source, "2")) {
|
||||
concatUrl(list, makerSpaceUrl);
|
||||
}
|
||||
|
||||
if (Objects.equals(source, "4")) {
|
||||
concatUrl(list, gatewayUrl);
|
||||
}
|
||||
|
||||
return JSON.toJSONString(list);
|
||||
}
|
||||
|
||||
private void concatUrl(List<Map<String, String>> list, String url) {
|
||||
|
|
@ -250,28 +254,26 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
|||
@Override
|
||||
public List<Achievements> getAllResult(AchQueryVo achQueryVo) {
|
||||
//根据查询条件获取所有的成果数据
|
||||
logger.info("getAllResult USERID======={},user={}", SecurityUtils.getGitlinkUserId(),SecurityUtils.getUsername());
|
||||
if (achQueryVo.getUserSelf() && SecurityUtils.getGitlinkUserId() != null) {
|
||||
achQueryVo.setUserId(SecurityUtils.getGitlinkUserId().toString());
|
||||
achQueryVo.setAllStatus(true);
|
||||
}
|
||||
List<Achievements> list = achievementsMapper.selectAchievementsByParamNew(achQueryVo);
|
||||
List<Achievements> list = achievementsMapper.selectAchievementsByParam(achQueryVo);
|
||||
//遍历成果数据,获取对应成果的点击数
|
||||
for (Achievements a : list) {
|
||||
String gender = a.getGender();
|
||||
String img = "images/avatars/User/boy.jpg";
|
||||
String img = "";
|
||||
if (StringUtils.isNotEmpty(gender) && gender.equals("1")) {
|
||||
img = "images/avatars/User/girl.jpg";
|
||||
} else if (StringUtils.isNotEmpty(gender) && gender.equals("0")) {
|
||||
img = "images/avatars/User/boy.jpg";
|
||||
}
|
||||
a.setUserImg(img);
|
||||
//根据id获取领域名称
|
||||
if (StringUtils.isEmpty(achQueryVo.getSource()) && StringUtils.isNotEmpty(a.getField1())) {
|
||||
String field1Name = achievementsMapper.getField1NameByParam(a.getSource(), a.getId());
|
||||
if (StringUtils.isNotNull(field1Name)) {
|
||||
a.setField1Name(field1Name);
|
||||
}
|
||||
}
|
||||
Long clickSum = achievementsMapper.getAchievementClickSum(a.getId());
|
||||
a.setClickSum(clickSum);
|
||||
a.setImages( a.getImages() == null ? null : a.getImages().replace("/api/file/common/downloadByIdentifier/", "/api/file/open/downloadByIdentifier/"));
|
||||
//拼接对接的用户信息
|
||||
List<Map<String,Object>> dockingUserInfo = achievementsMapper.getDockingUserInfoList(a.getId());
|
||||
a.setDockingUserInfo(dockingUserInfo);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
|
@ -511,19 +513,17 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
|||
@Override
|
||||
public List<AchRelatedResult> getRelatedAchCompetition(Long id, Long sourceId) {
|
||||
List<AchRelatedResult> relatedResultList = new ArrayList<>();
|
||||
if (sourceId !=null){
|
||||
//想根据开源项目id,获取对应的年度信息
|
||||
List<Long> allSourceId = achievementsMapper.getAllSourceIdCompetition(id, sourceId);
|
||||
List<String> allYear = achievementsMapper.getDistinctYear(id, allSourceId);
|
||||
if (StringUtils.isNotNull(allYear)) {
|
||||
//遍历年度信息,获取年度成果数据
|
||||
for (String paramYear : allYear) {
|
||||
AchRelatedResult relatedResult = new AchRelatedResult();
|
||||
relatedResult.setYear(paramYear);
|
||||
List<AchRelatedVo> tmpList = achievementsMapper.getRelatedAch(id, allSourceId, paramYear);
|
||||
relatedResult.setAchRelatedVoList(tmpList);
|
||||
relatedResultList.add(relatedResult);
|
||||
}
|
||||
//想根据开源项目id,获取对应的年度信息
|
||||
List<Long> allSourceId = achievementsMapper.getAllSourceIdCompetition(id, sourceId);
|
||||
List<String> allYear = achievementsMapper.getDistinctYear(id, allSourceId);
|
||||
if (StringUtils.isNotNull(allYear)) {
|
||||
//遍历年度信息,获取年度成果数据
|
||||
for (String paramYear : allYear) {
|
||||
AchRelatedResult relatedResult = new AchRelatedResult();
|
||||
relatedResult.setYear(paramYear);
|
||||
List<AchRelatedVo> tmpList = achievementsMapper.getRelatedAch(id, allSourceId, paramYear);
|
||||
relatedResult.setAchRelatedVoList(tmpList);
|
||||
relatedResultList.add(relatedResult);
|
||||
}
|
||||
}
|
||||
return relatedResultList;
|
||||
|
|
@ -532,19 +532,17 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
|||
@Override
|
||||
public List<AchRelatedResult> getRelatedAchTask(Long id, Long sourceId) {
|
||||
List<AchRelatedResult> relatedResultList = new ArrayList<>();
|
||||
if (sourceId !=null){
|
||||
//想根据开源项目id,获取对应的年度信息
|
||||
List<Long> allSourceId = achievementsMapper.getAllSourceIdTask(id, sourceId);
|
||||
List<String> allYear = achievementsMapper.getDistinctYear(id, allSourceId);
|
||||
if (StringUtils.isNotNull(allYear)) {
|
||||
//遍历年度信息,获取年度成果数据
|
||||
for (String paramYear : allYear) {
|
||||
AchRelatedResult relatedResult = new AchRelatedResult();
|
||||
relatedResult.setYear(paramYear);
|
||||
List<AchRelatedVo> tmpList = achievementsMapper.getRelatedAch(id, allSourceId, paramYear);
|
||||
relatedResult.setAchRelatedVoList(tmpList);
|
||||
relatedResultList.add(relatedResult);
|
||||
}
|
||||
//想根据开源项目id,获取对应的年度信息
|
||||
List<Long> allSourceId = achievementsMapper.getAllSourceIdTask(id, sourceId);
|
||||
List<String> allYear = achievementsMapper.getDistinctYear(id, allSourceId);
|
||||
if (StringUtils.isNotNull(allYear)) {
|
||||
//遍历年度信息,获取年度成果数据
|
||||
for (String paramYear : allYear) {
|
||||
AchRelatedResult relatedResult = new AchRelatedResult();
|
||||
relatedResult.setYear(paramYear);
|
||||
List<AchRelatedVo> tmpList = achievementsMapper.getRelatedAch(id, allSourceId, paramYear);
|
||||
relatedResult.setAchRelatedVoList(tmpList);
|
||||
relatedResultList.add(relatedResult);
|
||||
}
|
||||
}
|
||||
return relatedResultList;
|
||||
|
|
@ -589,15 +587,6 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
|||
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
|
||||
public List<KeyValueVo> getProjectAreasByName(String areaName) {
|
||||
return achievementsMapper.getProjectAreasByName(areaName);
|
||||
|
|
@ -640,409 +629,4 @@ public class AchievementsServiceImpl implements IAchievementsService {
|
|||
return resultVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyValueVo> getAllField2() {
|
||||
List<KeyValueVo> resultVal = achievementsMapper.getAllField2();
|
||||
return resultVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AchievementTypeDictVo> achievementsTypeStatistic() {
|
||||
List<NameCountVo> nameCountVos = achievementsMapper.groupByAchievementsType();
|
||||
R<List<SysDictData>> feignResult = remoteDictDataService.dictType("dms_achievement_type");
|
||||
return Optional.ofNullable(feignResult.getData()).orElse(Collections.emptyList())
|
||||
.stream().map(sysDictData -> {
|
||||
AchievementTypeDictVo dictVo = new AchievementTypeDictVo();
|
||||
BeanUtils.copyProperties(sysDictData, dictVo);
|
||||
dictVo.setCnt(nameCountVos.isEmpty() ? 0 : nameCountVos.stream().filter(dict -> sysDictData.getDictValue().equals(dict.getName()))
|
||||
.mapToLong(NameCountVo::getCnt).sum());
|
||||
return dictVo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AchievementSourceDictVo> achievementsSourceStatistic() {
|
||||
List<NameCountVo> nameCountVos = achievementsMapper.groupByAchievementsSource();
|
||||
R<List<SysDictData>> feignResult = remoteDictDataService.dictType("dms_achievement_source");
|
||||
return Optional.ofNullable(feignResult.getData()).orElse(Collections.emptyList())
|
||||
.stream().map(sysDictData -> {
|
||||
AchievementSourceDictVo dictVo = new AchievementSourceDictVo();
|
||||
BeanUtils.copyProperties(sysDictData, dictVo);
|
||||
dictVo.setCnt(nameCountVos.isEmpty() ? 0 : nameCountVos.stream().filter(dict -> dict.getName().equals(sysDictData.getDictValue()))
|
||||
.mapToLong(NameCountVo::getCnt).sum());
|
||||
return dictVo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<String, Object> 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();
|
||||
List<Achievements> successList = new ArrayList<>();
|
||||
|
||||
for (Achievements achievements : list) {
|
||||
try {
|
||||
// 查重:根据项目名称查询
|
||||
Achievements exist = achievementsMapper.selectAchievementsByAchievementName(achievements.getAchievementName());
|
||||
Long gitlinkUserId=SecurityUtils.getGitlinkUserId();
|
||||
Boolean gitlinkUserAdmin=achievementsMapper.isGitlinkAdminUser(gitlinkUserId) == 1;
|
||||
achievements.setStatus(gitlinkUserAdmin ? "1" : "0");
|
||||
achievements.setOwnerId(gitlinkUserId.toString());
|
||||
if (null == exist) {
|
||||
achievements.setCreateBy(operName);
|
||||
achievements.setCreateTime(new Date());
|
||||
achievements.setUpdateBy(operName);
|
||||
achievements.setUpdateTime(new Date());
|
||||
achievementsMapper.insertAchievements(achievements);
|
||||
successNum++;
|
||||
successList.add(achievements);
|
||||
successMsg.append("<br/>").append(successNum).append("、成果 ").append(achievements.getAchievementName()).append(" 导入成功");
|
||||
} else {
|
||||
if (updateSupport && exist.getOwnerId() != null && exist.getOwnerId().equals(gitlinkUserId.toString())) {
|
||||
achievements.setId(exist.getId());
|
||||
achievements.setCreateBy(exist.getCreateBy());
|
||||
achievements.setCreateTime(exist.getCreateTime());
|
||||
achievements.setUpdateBy(operName);
|
||||
achievements.setUpdateTime(new Date());
|
||||
achievementsMapper.updateAchievements(achievements);
|
||||
successNum++;
|
||||
successList.add(achievements);
|
||||
successMsg.append("<br/>").append(successNum).append("、成果 ").append(achievements.getAchievementName()).append(" 更新成功");
|
||||
} else if (!updateSupport && exist.getOwnerId() != null && exist.getOwnerId().equals(gitlinkUserId.toString())) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).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);
|
||||
finalMsg.append("<br/>***压缩包共读取到 ").append(successList.stream().mapToInt(Achievements::getAttachmentCount).sum()).append(" 个文件");
|
||||
}
|
||||
if (failureNum > 0) {
|
||||
finalMsg.append("<br/>共 ").append(failureNum).append(" 条数据导入失败:").append(failureMsg);
|
||||
}
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("successNum", successNum);
|
||||
result.put("failureNum", failureNum);
|
||||
result.put("message", finalMsg);
|
||||
return result;
|
||||
}
|
||||
|
||||
@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<>();
|
||||
Map<String, AchievementSysFileVo> coveImages = 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.endsWith("附件") && (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.endsWith("成果图片视频") && 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.endsWith("应用图片视频") && 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.setName(videoFile.getOriginalFilename());
|
||||
transferVo.setK(videoFile.getOriginalFilename());
|
||||
transferVo.setV(sysFile.getUrl());
|
||||
mp4ImagesExt2.put(fileName, transferVo);
|
||||
}
|
||||
// 清理临时文件
|
||||
tempFile.delete();
|
||||
}
|
||||
|
||||
// 3. 处理图片文件
|
||||
else if (parentPath.endsWith("成果图片视频") && 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-open", "import", SecurityConstants.INNER);
|
||||
if (R.SUCCESS == fileResult.getCode()) {
|
||||
SysFile sysFile = fileResult.getData();
|
||||
AchievementSysFileVo transferVo = new AchievementSysFileVo();
|
||||
BeanUtils.copyProperties(sysFile, transferVo);
|
||||
transferVo.setName(imageFile.getOriginalFilename());
|
||||
transferVo.setK(imageFile.getOriginalFilename());
|
||||
transferVo.setV(sysFile.getUrl());
|
||||
mp4ImagesExt1.put(fileName, transferVo);
|
||||
}
|
||||
}
|
||||
// 3. 处理图片文件
|
||||
else if (parentPath.endsWith("应用图片视频") && 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-open", "import", SecurityConstants.INNER);
|
||||
if (R.SUCCESS == fileResult.getCode()) {
|
||||
SysFile sysFile = fileResult.getData();
|
||||
AchievementSysFileVo transferVo = new AchievementSysFileVo();
|
||||
BeanUtils.copyProperties(sysFile, transferVo);
|
||||
transferVo.setName(imageFile.getOriginalFilename());
|
||||
transferVo.setK(imageFile.getOriginalFilename());
|
||||
transferVo.setV(sysFile.getUrl());
|
||||
mp4ImagesExt2.put(fileName, transferVo);
|
||||
}
|
||||
}
|
||||
else if (parentPath.endsWith("附件")) {
|
||||
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-open", "import", SecurityConstants.INNER);
|
||||
if (R.SUCCESS == fileResult.getCode()) {
|
||||
SysFile sysFile = fileResult.getData();
|
||||
AchievementSysFileVo transferVo = new AchievementSysFileVo();
|
||||
BeanUtils.copyProperties(sysFile, transferVo);
|
||||
transferVo.setName(attachmentFile.getOriginalFilename());
|
||||
transferVo.setK(attachmentFile.getOriginalFilename());
|
||||
transferVo.setV(sysFile.getUrl());
|
||||
attachmentMap.put(fileName, transferVo);
|
||||
}
|
||||
// 清理临时文件
|
||||
tempFile.delete();
|
||||
}// 3. 处理图片文件
|
||||
else if (parentPath.endsWith("封面图") && 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-open", "import", SecurityConstants.INNER);
|
||||
if (R.SUCCESS == fileResult.getCode()) {
|
||||
SysFile sysFile = fileResult.getData();
|
||||
AchievementSysFileVo transferVo = new AchievementSysFileVo();
|
||||
BeanUtils.copyProperties(sysFile, transferVo);
|
||||
transferVo.setName(imageFile.getOriginalFilename());
|
||||
transferVo.setK(imageFile.getOriginalFilename());
|
||||
transferVo.setV(sysFile.getUrl());
|
||||
coveImages.put(fileName, transferVo);
|
||||
}
|
||||
}
|
||||
|
||||
zipInputStream.closeEntry();
|
||||
}
|
||||
logger.info("✅ 使用 " + charset.displayName() + " 编码成功读取 ZIP");
|
||||
List<Achievements> saveDataList = excelDataList.stream()
|
||||
.filter(item -> StringUtils.isNotEmpty(item.getSource()) && StringUtils.isNotEmpty(item.getAchievementName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
saveDataList.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("入驻承诺书") || item.getKey().contains(achievements.getAchievementName()))
|
||||
.map(Map.Entry::getValue)
|
||||
.collect(Collectors.toList());
|
||||
List<Object> coveImagesList = coveImages.entrySet().stream()
|
||||
.filter(item -> item.getKey().contains(achievements.getAchievementName()))
|
||||
.map(Map.Entry::getValue)
|
||||
.collect(Collectors.toList());
|
||||
if (!mp4ImagesExt1List.isEmpty()){
|
||||
achievements.setExt1(JSONObject.toJSONString(mp4ImagesExt1List));
|
||||
achievements.setAttachmentCount(achievements.getAttachmentCount() + mp4ImagesExt1List.size());
|
||||
}
|
||||
if (!mp4ImagesExt2List.isEmpty()){
|
||||
achievements.setExt2(JSONObject.toJSONString(mp4ImagesExt2List));
|
||||
achievements.setAttachmentCount(achievements.getAttachmentCount() + mp4ImagesExt2List.size());
|
||||
}
|
||||
if (!filterAttachmentList.isEmpty()){
|
||||
achievements.setAttachments(JSONObject.toJSONString(filterAttachmentList));
|
||||
achievements.setAttachmentCount(achievements.getAttachmentCount() + filterAttachmentList.size());
|
||||
}
|
||||
if (!coveImagesList.isEmpty()){
|
||||
achievements.setImages(JSONObject.toJSONString(coveImagesList));
|
||||
achievements.setAttachmentCount(achievements.getAttachmentCount() + coveImagesList.size());
|
||||
}
|
||||
});
|
||||
|
||||
// 保存 Excel 数据到数据库
|
||||
String operName = SecurityUtils.getUsername();
|
||||
Map<String, Object> resultMap = saveDataList.isEmpty() ? new HashMap<>() : batchInsertAchievements(saveDataList, updateSupport, operName);
|
||||
//
|
||||
return resultMap.get("message") ==null ? "未去读取到数据,请确认文件压缩目录是否正确" : resultMap.get("message").toString();
|
||||
} 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,34 +1,25 @@
|
|||
package com.microservices.dms.achievementLibrary.service.impl;
|
||||
|
||||
import java.io.*;
|
||||
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.domain.R;
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.DateUtils;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.common.datasource.annotation.Slave;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.dms.achievementLibrary.domain.AchievementTeam;
|
||||
import com.microservices.dms.achievementLibrary.domain.Achievements;
|
||||
import com.microservices.dms.achievementLibrary.mapper.AchievementTeamMapper;
|
||||
import com.microservices.dms.achievementLibrary.mapper.AchievementsMapper;
|
||||
import com.microservices.dms.achievementLibrary.service.IAchievementsService;
|
||||
import com.microservices.system.api.RemoteFileService;
|
||||
import com.microservices.system.api.domain.SysUser;
|
||||
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.stereotype.Service;
|
||||
import com.microservices.dms.achievementLibrary.mapper.SchoolEnterpriseAchievementsMapper;
|
||||
import com.microservices.dms.achievementLibrary.domain.SchoolEnterpriseAchievements;
|
||||
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业务层处理
|
||||
|
|
@ -50,9 +41,6 @@ public class SchoolEnterpriseAchievementsServiceImpl implements ISchoolEnterpris
|
|||
@Autowired
|
||||
private AchievementsMapper achievementsMapper;
|
||||
|
||||
@Autowired
|
||||
private RemoteFileService remoteFileService;
|
||||
|
||||
/**
|
||||
* 查询校企成果
|
||||
*
|
||||
|
|
@ -136,144 +124,6 @@ public class SchoolEnterpriseAchievementsServiceImpl implements ISchoolEnterpris
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修改校企成果
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ package com.microservices.dms.common.controller;
|
|||
import com.microservices.common.core.web.controller.BaseController;
|
||||
import com.microservices.common.core.web.domain.AjaxResult;
|
||||
import com.microservices.common.core.web.page.TableDataInfo;
|
||||
import com.microservices.common.security.annotation.RequiresLogin;
|
||||
import com.microservices.common.security.utils.SecurityUtils;
|
||||
import com.microservices.dms.achievementLibrary.domain.AchQueryVo;
|
||||
import com.microservices.dms.achievementLibrary.service.BlockChainService;
|
||||
import com.microservices.dms.achievementLibrary.service.IAchievementsService;
|
||||
|
|
@ -109,44 +107,6 @@ public class OpenController extends BaseController {
|
|||
return getDataTable(achievementsService.getAllResult(achQueryVo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取成果详细信息
|
||||
*/
|
||||
@GetMapping(value = "/achievements/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
||||
return success(achievementsService.selectAchievementsById(id, true));
|
||||
}
|
||||
|
||||
@ApiOperation("首页成果分类统计")
|
||||
@GetMapping("/achievements/typeStatistic")
|
||||
public AjaxResult achievementsTypeStatistic() {
|
||||
return success(achievementsService.achievementsTypeStatistic());
|
||||
}
|
||||
|
||||
@ApiOperation("首页成果来源统计")
|
||||
@GetMapping("/achievements/sourceStatistic")
|
||||
public AjaxResult achievementsSourceStatistic() {
|
||||
return success(achievementsService.achievementsSourceStatistic());
|
||||
}
|
||||
|
||||
@ApiOperation("根据成果ID,获取成果的相关行为数据统计(点击量、搜索量、附件下载量、收藏、关注)")
|
||||
@GetMapping("/achievements/getActDataStatisticById")
|
||||
public AjaxResult getActDataStatisticById(Long id) {
|
||||
return success(achievementsService.getActDataStatisticById(id));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取开源竞赛的相关成果")
|
||||
@GetMapping("/achievements/getRelatedAchCompetition")
|
||||
public AjaxResult getRelatedAchCompetition(Long id, Long sourceId) {
|
||||
return success(achievementsService.getRelatedAchCompetition(id, sourceId));
|
||||
}
|
||||
|
||||
@ApiOperation("根据当前用户以及成果ID,获取当前成果的 是否收藏与关注状态")
|
||||
@GetMapping("/achievements/getWatchFavoriteStatusById")
|
||||
public AjaxResult getWatchFavoriteStatusById(Long id, Long userId) {
|
||||
return success(achievementsService.getWatchFavoriteStatusById(id, userId));
|
||||
}
|
||||
|
||||
@ApiOperation("近七日用户行为数据")
|
||||
@GetMapping("/achievements/getUerActionData")
|
||||
public AjaxResult getUerActionData() {
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
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,9 +0,0 @@
|
|||
package com.microservices.dms.common.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class NameCountVo {
|
||||
private String name;
|
||||
private long cnt;
|
||||
}
|
||||
|
|
@ -1,15 +1,11 @@
|
|||
package com.microservices.dms.resourceLibrary.controller;
|
||||
|
||||
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.web.controller.BaseController;
|
||||
import com.microservices.common.core.web.domain.AjaxResult;
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
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.vo.CompetitionListVo;
|
||||
import com.microservices.dms.resourceLibrary.service.CompetitionResourceLibraryService;
|
||||
|
|
@ -21,7 +17,6 @@ import io.swagger.annotations.ApiImplicitParams;
|
|||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
|
@ -83,17 +78,6 @@ public class CompetitionResourceLibraryController extends BaseController {
|
|||
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}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
||||
return success(competitionResourceLibraryService.selectCompetitionResourceLibraryById(id));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.microservices.dms.resourceLibrary.controller;
|
||||
|
||||
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.web.controller.BaseController;
|
||||
import com.microservices.common.core.web.domain.AjaxResult;
|
||||
|
|
@ -9,18 +8,16 @@ import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
|||
import com.microservices.common.core.web.page.TableDataInfo;
|
||||
import com.microservices.dms.resourceLibrary.domain.ProjectResourceLibrary;
|
||||
import com.microservices.dms.resourceLibrary.domain.vo.ProjectListVo;
|
||||
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.TaskListVo;
|
||||
import com.microservices.dms.resourceLibrary.domain.vo.UserActionDataVo;
|
||||
import com.microservices.dms.resourceLibrary.service.ProjectResourceLibraryService;
|
||||
import com.microservices.dms.resourceLibrary.service.TaskResourceLibraryService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
|
@ -125,23 +122,6 @@ public class ProjectResourceLibraryController extends BaseController {
|
|||
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}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
||||
return success(projectResourceLibraryService.selectProjectResourceLibraryById(id));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.microservices.dms.resourceLibrary.controller;
|
||||
|
||||
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.web.controller.BaseController;
|
||||
import com.microservices.common.core.web.domain.AjaxResult;
|
||||
|
|
@ -9,7 +8,6 @@ import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
|||
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.TaskResourceLibrary;
|
||||
import com.microservices.dms.resourceLibrary.domain.vo.TaskListVo;
|
||||
import com.microservices.dms.resourceLibrary.domain.vo.UserActionDataVo;
|
||||
|
|
@ -20,7 +18,6 @@ import io.swagger.annotations.ApiImplicitParams;
|
|||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
|
@ -137,17 +134,6 @@ public class TaskResourceLibraryController extends BaseController {
|
|||
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}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
||||
return success(taskResourceLibraryService.selectTaskResourceLibraryById(id));
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.microservices.common.core.annotation.Excel;
|
||||
import com.microservices.common.core.web.domain.BaseEntity;
|
||||
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
||||
|
||||
|
|
@ -20,12 +19,10 @@ public class CompetitionResourceLibrary extends BaseEntity {
|
|||
/**
|
||||
* 开放竞赛ID
|
||||
*/
|
||||
@Excel(name = "竞赛ID")
|
||||
private Long openCompetitionId;
|
||||
/**
|
||||
* 开放竞赛名称
|
||||
*/
|
||||
@Excel(name = "竞赛名称")
|
||||
private String openCompetitionName;
|
||||
/**
|
||||
* 开放竞赛创建者
|
||||
|
|
@ -34,28 +31,23 @@ public class CompetitionResourceLibrary extends BaseEntity {
|
|||
/**
|
||||
* 竞赛领域
|
||||
*/
|
||||
@Excel(name = "成果领域")
|
||||
private String competitionField;
|
||||
/**
|
||||
* 竞赛状态 status: 0 未上架 1上架
|
||||
*/
|
||||
@Excel(name = "竞赛状态", readConverterExp = "0=未上架,1=上架")
|
||||
private String competitionStatus;
|
||||
/**
|
||||
* 竞赛提交名称
|
||||
*/
|
||||
@Excel(name = "作品名称")
|
||||
private String competitionSubmissionName;
|
||||
/**
|
||||
* 作品提交时间
|
||||
*/
|
||||
@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;
|
||||
/**
|
||||
* 提交者
|
||||
*/
|
||||
@Excel(name = "提交人")
|
||||
private String submitter;
|
||||
/**
|
||||
* 提交类型
|
||||
|
|
@ -84,13 +76,11 @@ public class CompetitionResourceLibrary extends BaseEntity {
|
|||
/**
|
||||
* 是否已转入成果库 0否 1是
|
||||
*/
|
||||
@Excel(name = "转入状态", readConverterExp = "0=未转入,1=已转入")
|
||||
private Integer isTransferredToResultLibrary;
|
||||
/**
|
||||
* 转入成果库时间
|
||||
*/
|
||||
@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;
|
||||
/**
|
||||
* 是否精选成果
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.microservices.common.core.annotation.Excel;
|
||||
import com.microservices.common.core.web.domain.BaseEntity;
|
||||
import com.microservices.dms.resourceLibrary.domain.vo.KeyValVo;
|
||||
|
||||
|
|
@ -19,10 +18,8 @@ public class ProjectResourceLibrary extends BaseEntity {
|
|||
private static final long serialVersionUID = 1L;
|
||||
private Long id;
|
||||
//项目资源名称
|
||||
@Excel(name = "项目名称")
|
||||
private String projectName;
|
||||
//项目领域
|
||||
@Excel(name = "成果领域")
|
||||
private String projectDomain;
|
||||
//项目领域名称
|
||||
private String projectDomainName;
|
||||
|
|
@ -30,24 +27,19 @@ public class ProjectResourceLibrary extends BaseEntity {
|
|||
private String identifier;
|
||||
private String userIdentifier;
|
||||
//开源项目ID
|
||||
@Excel(name = "项目ID")
|
||||
private Long projectId;
|
||||
//仓库ID
|
||||
private Long repositoryId;
|
||||
//版本Id
|
||||
private Long versionReleasesId;
|
||||
//项目是否已公开
|
||||
@Excel(name = "是否公开", readConverterExp = "0=否,1=是")
|
||||
private Long isPublic;
|
||||
//发版名称
|
||||
@Excel(name = "发行版名称")
|
||||
private String releaseName;
|
||||
//发版时间
|
||||
@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;
|
||||
//发版人
|
||||
@Excel(name = "发版人")
|
||||
private String releasePerson;
|
||||
//发版类型
|
||||
private String releaseType;
|
||||
|
|
@ -62,11 +54,9 @@ public class ProjectResourceLibrary extends BaseEntity {
|
|||
//联系时间
|
||||
private String contactPhone;
|
||||
//是否已转入成果库
|
||||
@Excel(name = "转入状态", readConverterExp = "0=未转入,1=已转入")
|
||||
private Long isTransferredToAchievement;
|
||||
//转入成果库时间
|
||||
@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 Long isSelectedAchievement;
|
||||
|
|
|
|||
|
|
@ -21,28 +21,21 @@ public class TaskResourceLibrary extends BaseEntity {
|
|||
//
|
||||
private Long id;
|
||||
//创客任务ID
|
||||
@Excel(name = "任务ID")
|
||||
private Long taskId;
|
||||
//
|
||||
private Long paperId;
|
||||
//创客任务名称
|
||||
@Excel(name = "任务名称")
|
||||
private String taskName;
|
||||
//任务领域
|
||||
@Excel(name = "成果领域")
|
||||
private String taskDomain;
|
||||
//创客任务金额
|
||||
@Excel(name = "任务金额(元)")
|
||||
private BigDecimal taskAmount;
|
||||
//胜出交稿名称
|
||||
@Excel(name = "成果编号")
|
||||
private String submissionName;
|
||||
//交稿时间
|
||||
@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;
|
||||
//交稿人
|
||||
@Excel(name = "交稿人")
|
||||
private String submitterName;
|
||||
//交稿类型
|
||||
private String submissionType;
|
||||
|
|
@ -57,11 +50,9 @@ public class TaskResourceLibrary extends BaseEntity {
|
|||
//联系电话
|
||||
private String contactPhone;
|
||||
//是否已转入成果库
|
||||
@Excel(name = "转入状态", readConverterExp = "0=未转入,1=已转入")
|
||||
private Long isTransferredToResultsLibrary;
|
||||
//转入成果库时间
|
||||
@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;
|
||||
//是否精选成果 0否 1是
|
||||
private Long isSelectedResult;
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@ public interface CompetitionResourceLibraryMapper {
|
|||
|
||||
CompetitionResourceLibrary selectCompetitionResourceLibraryById(Long id);
|
||||
|
||||
CompetitionResourceLibrary selectCompetitionResourceLibraryByCompetitionName(@Param("competitionName") String competitionName);
|
||||
|
||||
List<CompetitionResourceLibrary> selectCompetitionResourceLibraryList(CompetitionResourceLibrary competitionResourceLibrary);
|
||||
|
||||
int insertCompetitionResourceLibrary(CompetitionResourceLibrary competitionResourceLibrary);
|
||||
|
|
|
|||
|
|
@ -73,6 +73,4 @@ public interface ProjectResourceLibraryMapper {
|
|||
String getUserIdBYLogin(@Param("userId")String userId);
|
||||
|
||||
UserProjectTransferRecords selectIssueEndInfo(@Param("issueId") String issueId);
|
||||
|
||||
ProjectResourceLibrary selectProjectResourceLibraryByProjectName(@Param("projectName") String projectName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,4 @@ public interface TaskResourceLibraryMapper {
|
|||
int delWatcher(Watcher watcher);
|
||||
|
||||
double getConvertedTaskAmount2();
|
||||
|
||||
TaskResourceLibrary selectTaskResourceLibraryByTaskName(@Param("taskName") String taskName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,61 +149,4 @@ public class CompetitionResourceLibraryService {
|
|||
// 这里替换成你的实际逻辑
|
||||
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,62 +140,4 @@ public class ProjectResourceLibraryService {
|
|||
public long 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,8 +14,6 @@ import org.springframework.stereotype.Service;
|
|||
|
||||
import java.util.Arrays;
|
||||
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;
|
||||
|
||||
|
|
@ -211,61 +209,4 @@ public class TaskResourceLibraryService {
|
|||
public int delWatcher(Watcher 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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue