Merge branch 'feature/REQ-3540' into 'master'

Feature/req 3540

See merge request universal/infrastructure/backend/nanopart!158
This commit is contained in:
徐大伟 2025-04-28 09:00:20 +00:00
commit 65d879acb4
9 changed files with 328 additions and 58 deletions

View File

@ -0,0 +1,81 @@
package cn.axzo.nanopart.doc.api.enums;
import cn.axzo.nanopart.doc.api.wps.response.WpsPermissionResponse;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Accessors;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author xudawei
*/
@Getter
@Accessors(fluent = true)
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public enum WpsPermissionStatusEnum {
EDIT("edit", "编辑"),
PREVIEW("preview", "预览"),
;
private final String code;
private final String desc;
private static final Map<String, WpsPermissionStatusEnum> map = Stream.of(WpsPermissionStatusEnum.values()).collect(Collectors.toMap(key -> key.code, key -> key));
public static WpsPermissionStatusEnum getByCode(String code) {
return map.get(code);
}
public static void main(String[] args) {
WpsPermissionStatusEnum preview = WpsPermissionStatusEnum.getByCode("preview");
System.out.println("preview = " + preview);
}
/**
* 预览
* @param personId
* @return
*/
public static WpsPermissionResponse preview(String personId) {
return WpsPermissionResponse.builder()
.personId(personId)
.read(1)
.update(0)
.download(0)
.rename(0)
.history(0)
.copy(1)
.print(0)
.saveas(0)
.comment(0)
.build();
}
/**
* 编辑
*/
public static WpsPermissionResponse edit(String personId) {
return WpsPermissionResponse.builder()
.personId(personId)
.read(1)
.update(1)
.download(0)
.rename(0)
.history(0)
.copy(1)
.print(0)
.saveas(0)
.comment(0)
.build();
}
}

View File

@ -33,4 +33,19 @@ public class Constants {
*/
public static final String WPS_UPLOAD_PREPARE_SHA1 = "sha1";
/**
* http开头
*/
public static final String WPS_HTTP_START = "http://";
/**
* https开头
*/
public static final String WPS_HTTPS_START = "https://";
/**
* wps默认用户Id
*/
public static final String WPS_DEFAULT_USER_ID = "0";
}

View File

@ -22,4 +22,9 @@ public class WpsFetchFileRequest {
*/
private String docCode;
/**
* 用户Id
*/
private String personId;
}

View File

@ -1,6 +1,7 @@
package cn.axzo.nanopart.doc.api.wps.request;
import cn.axzo.nanopart.doc.api.enums.WpsPermissionStatusEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -27,4 +28,9 @@ public class WpsPermissionRequest {
*/
private String personId;
/**
* 权限状态
*/
private WpsPermissionStatusEnum wpsPermissionStatus;
}

View File

@ -67,22 +67,4 @@ public class WpsPermissionResponse {
*/
private Integer comment;
/**
* 预览文档权限
*/
public static WpsPermissionResponse preview(String personId) {
return WpsPermissionResponse.builder()
.personId(personId)
.read(1)
.update(0)
.download(0)
.rename(0)
.history(0)
.copy(0)
.print(0)
.saveas(0)
.comment(0)
.build();
}
}

View File

@ -8,6 +8,8 @@ import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest;
import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse;
import cn.axzo.oss.http.model.ApiSignUrlUploadRequest;
import cn.axzo.oss.http.model.ApiSignUrlUploadResponse;
import cn.axzo.oss.http.model.file.FetchFileInfoRequest;
import cn.axzo.oss.http.model.file.FetchFileInfoResponse;
import cn.axzo.oss.http.model.file.UpdateFileInfoRequest;
import cn.axzo.oss.http.model.file.UpdateFileInfoResponse;
import cn.azxo.framework.common.model.CommonResponse;
@ -82,4 +84,20 @@ public class DocOssGateway {
}
/**
* 获取文件基础信息
*/
public FetchFileInfoResponse fetchFileInfo(FetchFileInfoRequest request) {
try {
log.info("DocOssGateway-fetchFileInfo request:{}", JSON.toJSONString(request));
CommonResponse<FetchFileInfoResponse> response = serverFileServiceApi.fetchFileInfo(request);
log.info("DocOssGateway-fetchFileInfo result:{}", JSON.toJSONString(response));
return response.getData();
} catch (Exception e) {
log.warn("DocOssGateway-fetchFileInfo exception", e);
throw new WpsException(WpsErrorCodeEnum.UPLOAD_ERROR);
}
}
}

View File

@ -0,0 +1,115 @@
package cn.axzo.nanopart.doc.wps.support;
import cn.axzo.nanopart.doc.api.enums.WpsErrorCodeEnum;
import cn.axzo.nanopart.doc.api.util.Constants;
import cn.axzo.nanopart.doc.api.wps.response.WpsFetchDownloadResponse;
import cn.axzo.nanopart.doc.api.wps.response.WpsFetchFileResponse;
import cn.axzo.nanopart.doc.integration.DocOssGateway;
import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest;
import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse;
import cn.axzo.oss.http.model.file.FetchFileInfoRequest;
import cn.axzo.oss.http.model.file.FetchFileInfoResponse;
import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Objects;
/**
* @author xudawei@axzo.cn
* @date 2025/3/21
* @description wps支持
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class OssSupport {
private final DocOssGateway docOssGateway;
public WpsFetchFileResponse fetchFileInfo(String fileKey, String personId) {
fileKey = url2FileKey(fileKey);
FetchFileInfoResponse response = docOssGateway.fetchFileInfo(FetchFileInfoRequest.builder().fileKey(fileKey).build());
if (Objects.isNull(response) || Objects.isNull(response.getId())) {
return null;
}
return WpsFetchFileResponse.builder()
.docCode(response.getFileUuid())
.name(response.getFileName())
.version(1)
.size(response.getStorageSize())
.createAt(response.getCreateAt())
.updateAt(response.getUpdateAt())
.creatorId(StringUtils.isNotBlank(response.getCreateBy()) ? response.getCreateBy() : personId)
.modifierId(StringUtils.isNotBlank(response.getUpdateBy()) ? response.getUpdateBy() : personId)
.build();
}
public WpsFetchDownloadResponse fetchDownload(String fileKey) {
fileKey = url2FileKey(fileKey);
FetchFileInfoResponse response = docOssGateway.fetchFileInfo(FetchFileInfoRequest.builder().fileKey(fileKey).build());
if (Objects.isNull(response) || Objects.isNull(response.getId())) {
return null;
}
return WpsFetchDownloadResponse.builder()
.url(this.downloadUrl(response.getFileUuid()))
.digest("")
.digestType("")
.headers(null)
.build();
}
/**
* 获取文件下载地址
*/
public String downloadUrl(String fileKey) {
if (StringUtils.isEmpty(fileKey)) {
return StringUtils.EMPTY;
}
fileKey = url2FileKey(fileKey);
ApiSignUrlDownloadRequest request = new ApiSignUrlDownloadRequest();
request.setFileKeys(Lists.newArrayList(fileKey));
List<ApiSignUrlDownloadResponse> responseList = docOssGateway.signUrlFetchDownload(request);
WpsAssertUtil.isFalse(CollectionUtil.isEmpty(responseList) || StringUtils.isBlank(responseList.get(0).getSignUrl()), WpsErrorCodeEnum.UPLOAD_ERROR);
return responseList.get(0).getSignUrl();
}
/**
* 从链接中提取fileKey比如如下链接获取fileKey:b4148fbee6954c2fa3139471f18a2dcd
* https://xx/identity/b4148fbee6954c2fa3139471f18a2dcd.docx?AccessKeyId=xx&Expires=xx&response-content-disposition=xx&Signature=xx
* https://xx/identity/b4148fbee6954c2fa3139471f18a2dcd.doc?AccessKeyId=xx&Expires=xx&response-content-disposition=xx&Signature=xx
* https://xxx/app/app/b4148fbee6954c2fa3139471f18a2dcd.docx
* https://xxx/app/app/b4148fbee6954c2fa3139471f18a2dcd.doc
*/
public String url2FileKey(String url) {
if (!url.startsWith(Constants.WPS_HTTP_START) && !url.startsWith(Constants.WPS_HTTPS_START)) {
return url;
}
if (url.contains("/") && url.contains("?")) {
url = url.split("\\?")[0];
String fileName = url.substring(url.lastIndexOf("/") + 1);
if (fileName.contains(".")) {
return fileName.substring(0, fileName.indexOf("."));
}
return fileName;
}
if (url.contains("/") ) {
String fileName = url.substring(url.lastIndexOf("/") + 1);
if (fileName.contains(".")) {
return fileName.substring(0, fileName.indexOf("."));
}
return fileName;
}
return url;
}
}

View File

@ -12,6 +12,7 @@ import cn.axzo.nanopart.doc.api.wps.response.WpsFetchFileResponse;
import cn.axzo.nanopart.doc.api.wps.response.WpsPermissionResponse;
import cn.axzo.nanopart.doc.api.wps.response.WpsRenameResponse;
import cn.axzo.nanopart.doc.api.wps.response.WpsUsersResponse;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
@ -37,7 +38,10 @@ public class WpsBaseController implements WpsBaseApi {
*/
@Override
public ApiResult<WpsFetchFileResponse> fetchFile(@Validated @RequestBody WpsFetchFileRequest request) {
return ApiResult.ok(wpsBaseManager.fetchFileBase(request.getDocCode()));
log.info("WpsBaseController-fetchFile-params: {}", JSON.toJSONString(request));
WpsFetchFileResponse wpsFetchFileResponse = wpsBaseManager.fetchFileBase(request.getDocCode(), request.getPersonId());
log.info("WpsBaseController-fetchFile-result: {}", JSON.toJSONString(wpsFetchFileResponse));
return ApiResult.ok(wpsFetchFileResponse);
}
/**
@ -58,7 +62,10 @@ public class WpsBaseController implements WpsBaseApi {
*/
@Override
public ApiResult<WpsPermissionResponse> permission(@Validated @RequestBody WpsPermissionRequest request) {
return ApiResult.ok(wpsBaseManager.permission(request));
log.info("WpsBaseController-permission-params: {}", JSON.toJSONString(request));
WpsPermissionResponse permission = wpsBaseManager.permission(request);
log.info("WpsBaseController-permission-params:{},result: {}", JSON.toJSONString(request),JSON.toJSONString(permission));
return ApiResult.ok(permission);
}
/**
@ -68,7 +75,10 @@ public class WpsBaseController implements WpsBaseApi {
*/
@Override
public ApiResult<WpsUsersResponse> users(@Validated @RequestBody WpsUsersRequest request) {
return ApiResult.ok(wpsBaseManager.users(request));
log.info("WpsBaseController-users-params: {}", JSON.toJSONString(request));
WpsUsersResponse users = wpsBaseManager.users(request);
log.info("WpsBaseController-users-params:{},result: {}", JSON.toJSONString(request), JSON.toJSONString(users));
return ApiResult.ok(users);
}
/**

View File

@ -1,17 +1,10 @@
package cn.axzo.nanopart.doc.wps.wpsbase;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import com.google.common.collect.Lists;
import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
import cn.axzo.nanopart.doc.api.enums.WpsErrorCodeEnum;
import cn.axzo.nanopart.doc.api.enums.WpsPermissionStatusEnum;
import cn.axzo.nanopart.doc.api.util.Constants;
import cn.axzo.nanopart.doc.api.wps.exception.WpsException;
import cn.axzo.nanopart.doc.api.wps.request.WpsPermissionRequest;
import cn.axzo.nanopart.doc.api.wps.request.WpsRenameRequest;
@ -27,14 +20,20 @@ import cn.axzo.nanopart.doc.file.index.IndexManager;
import cn.axzo.nanopart.doc.file.index.domain.NameUsedException;
import cn.axzo.nanopart.doc.integration.DocOssGateway;
import cn.axzo.nanopart.doc.integration.DocUserProfileGateway;
import cn.axzo.nanopart.doc.wps.support.OssSupport;
import cn.axzo.nanopart.doc.wps.support.WpsAssertUtil;
import cn.axzo.nanopart.doc.wps.support.WpsSupport;
import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest;
import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse;
import cn.axzo.oss.http.model.file.UpdateFileInfoRequest;
import cn.axzo.oss.http.model.file.UpdateFileInfoResponse;
import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* wps对接基础信息
@ -52,11 +51,19 @@ public class WpsBaseManager {
private final DocPermissionProps docPermissionProps;
private final WpsSupport wpsSupport;
private final OssSupport ossSupport;
/**
* 获取文件基础信息
* @param docCode 文件编码
*/
public WpsFetchFileResponse fetchFileBase(String docCode) {
public WpsFetchFileResponse fetchFileBase(String docCode, String personId) {
WpsFetchFileResponse wpsFetchFileResponse = ossSupport.fetchFileInfo(docCode, personId);
if (Objects.nonNull(wpsFetchFileResponse) && Objects.nonNull(wpsFetchFileResponse.getDocCode())) {
return wpsFetchFileResponse;
}
IndexNode node = wpsSupport.findAndCheckByCode(docCode);
return WpsFetchFileResponse.builder()
.docCode(docCode)
@ -75,30 +82,21 @@ public class WpsBaseManager {
* @param docCode 文件编码
*/
public WpsFetchDownloadResponse fetchDownload(String docCode) {
WpsFetchDownloadResponse wpsFetchDownloadResponse = ossSupport.fetchDownload(docCode);
if (Objects.nonNull(wpsFetchDownloadResponse) && StringUtils.isNotBlank(wpsFetchDownloadResponse.getUrl())) {
return wpsFetchDownloadResponse;
}
IndexNode node = wpsSupport.findAndCheckByCode(docCode);
return WpsFetchDownloadResponse.builder()
.url(this.downloadUrl(node.getAttributes().getFileAttributes().getOssFileKey()))
.url(ossSupport.downloadUrl(node.getAttributes().getFileAttributes().getOssFileKey()))
.digest("")
.digestType("")
.headers(null)
.build();
}
/**
* 获取文件下载地址
*/
private String downloadUrl(String fileKey) {
if (StringUtils.isEmpty(fileKey)) {
return StringUtils.EMPTY;
}
ApiSignUrlDownloadRequest request = new ApiSignUrlDownloadRequest();
request.setFileKeys(Lists.newArrayList(fileKey));
List<ApiSignUrlDownloadResponse> responseList = docOssGateway.signUrlFetchDownload(request);
WpsAssertUtil.isFalse(CollectionUtil.isEmpty(responseList) || StringUtils.isBlank(responseList.get(0).getSignUrl()), WpsErrorCodeEnum.UPLOAD_ERROR);
return responseList.get(0).getSignUrl();
}
/**
* 文档权限
@ -107,9 +105,14 @@ public class WpsBaseManager {
public WpsPermissionResponse permission(WpsPermissionRequest request) {
IndexNode indexNode = indexManager.findOrNull(request.getDocCode());
if (StringUtils.isNotBlank(indexNode.getOrCreateFileAttributes().getFileExtension())
if (Objects.nonNull(indexNode) && StringUtils.isNotBlank(indexNode.getOrCreateFileAttributes().getFileExtension())
&& indexNode.getOrCreateFileAttributes().getFileExtension().equalsIgnoreCase("pdf")) {
return WpsPermissionResponse.preview(request.getPersonId());
return WpsPermissionStatusEnum.preview(request.getPersonId());
}
if (Objects.nonNull(request.getWpsPermissionStatus())) {
if (request.getWpsPermissionStatus() == WpsPermissionStatusEnum.PREVIEW) {
return WpsPermissionStatusEnum.preview(request.getPersonId());
}
}
return WpsPermissionResponse.builder()
@ -131,19 +134,54 @@ public class WpsBaseManager {
*/
public WpsUsersResponse users(WpsUsersRequest request) {
WpsAssertUtil.isFalse(Objects.isNull(request) || CollectionUtil.isEmpty(request.getPersonIds()), WpsErrorCodeEnum.REQUEST_PARAMETER_ERROR);
//查询人员档案
List<PersonProfileDto> personProfiles = this.docUserProfileGateway.personProfileByPersonIds(request.getPersonIds().stream().map(Long::parseLong).collect(Collectors.toList()));
WpsAssertUtil.isFalse(CollectionUtil.isEmpty(personProfiles), WpsErrorCodeEnum.USER_NOT_EXIST);
List<WpsUsersResponse.WpsUser> allWpsUsers = Lists.newArrayList();
//构建默认用户信息
allWpsUsers.addAll(this.buildDefaultWpsUsers(request.getPersonIds()));
//构建正常用户信息
allWpsUsers.addAll(this.buildNormalWpsUsers(request.getPersonIds()));
return WpsUsersResponse.builder()
.users(personProfiles.stream()
.map(item -> WpsUsersResponse.WpsUser.builder()
.personId(item.getId().toString())
.name(item.getRealName())
.avatarUrl(item.getAvatarUrl()).build()).collect(Collectors.toList()))
.users(allWpsUsers)
.build();
}
/**
* 构建正常用户信息
*/
private List<WpsUsersResponse.WpsUser> buildNormalWpsUsers(List<String> personIds) {
List<Long> normalUserList = personIds.stream().filter(item -> !item.equalsIgnoreCase(Constants.WPS_DEFAULT_USER_ID)).map(Long::parseLong).collect(Collectors.toList());
if (CollectionUtil.isEmpty(normalUserList)) {
return Lists.newArrayList();
}
//查询人员档案
List<PersonProfileDto> personProfiles = this.docUserProfileGateway.personProfileByPersonIds(normalUserList);
WpsAssertUtil.isFalse(CollectionUtil.isEmpty(personProfiles), WpsErrorCodeEnum.USER_NOT_EXIST);
return personProfiles.stream()
.map(item -> WpsUsersResponse.WpsUser.builder()
.personId(item.getId().toString())
.name(item.getRealName())
.avatarUrl(item.getAvatarUrl()).build()).collect(Collectors.toList());
}
/**
* 构建默认用户信息
*/
private List<WpsUsersResponse.WpsUser> buildDefaultWpsUsers(List<String> personIds) {
List<Long> defaultUserList = personIds.stream().filter(item -> item.equalsIgnoreCase(Constants.WPS_DEFAULT_USER_ID)).map(Long::parseLong).collect(Collectors.toList());
if (CollectionUtil.isEmpty(defaultUserList)) {
return Lists.newArrayList();
}
return defaultUserList.stream().map(item ->
WpsUsersResponse.WpsUser.builder()
.personId(item.toString())
.name(StringUtils.EMPTY)
.avatarUrl(StringUtils.EMPTY).build()
).collect(Collectors.toList());
}
/**
* 文件重命名
*/