feat: (REQ-3540) wps对接-manager实现

This commit is contained in:
xudawei 2025-03-12 20:50:25 +08:00
parent dd88e4d889
commit 08fa7ccd75
14 changed files with 390 additions and 27 deletions

View File

@ -22,4 +22,19 @@ public class FileAttributes {
*/
private String ossFileKey;
/**
* 版本号
*/
private Integer version;
/**
* 文档创建者 Id
*/
private String creatorId;
/**
* 文档最后修改者 Id
*/
private String modifierId;
}

View File

@ -21,5 +21,10 @@ public class WpsPermissionRequest {
*/
private String docCode;
/**
* 用户Id
*/
private String personId;
}

View File

@ -5,7 +5,7 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import javax.validation.constraints.NotBlank;
/**
* @author xudawei@axzo.cn
@ -21,11 +21,13 @@ public class WpsRenameRequest {
/**
* 文档编码
*/
@NotBlank(message = "文档编码不能为空")
private String docCode;
/**
* 新文档名称
*/
@NotBlank(message = "新文档名称不能为空")
private String name;

View File

@ -5,6 +5,8 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.util.List;
/**
@ -21,7 +23,9 @@ public class WpsUsersRequest {
/**
* 用户Id集合
*/
private List<String> userIds;
@NotEmpty(message = "personIds not empty")
@Size(max = 1000, message = "personIds max length:1000")
private List<String> personIds;
}

View File

@ -5,6 +5,8 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @author xudawei@axzo.cn
* @date 2025/3/11
@ -40,12 +42,12 @@ public class WpsFetchFileResponse {
/**
* 文档创建时间戳单位纪元秒
*/
private Long createAt;
private Date createAt;
/**
* 文档最后修改时间戳单位纪元秒
*/
private Long updateAt;
private Date updateAt;
/**
* 文档创建者 Id

View File

@ -16,5 +16,6 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
public class WpsRenameResponse {
private boolean updateFlag;
}

View File

@ -5,10 +5,12 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author xudawei@axzo.cn
* @date 2025/3/11
* @description 文档用户权限
* @date 2025/3/12
* @description 文档用户
*/
@Builder
@Data
@ -16,19 +18,27 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
public class WpsUsersResponse {
/**
* 当前用户 ID
*/
private String personId;
private List<WpsUser> users;
/**
* 用户昵称
*/
private String name;
@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class WpsUser {
/**
* 当前用户 ID
*/
private String personId;
/**
* 用户头像 URL需要是https链接
*/
private String avatarUrl;
/**
* 用户昵称
*/
private String name;
/**
* 用户头像 URL需要是https链接
*/
private String avatarUrl;
}
}

View File

@ -93,6 +93,11 @@
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.axzo.basics</groupId>
<artifactId>basics-profiles-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,62 @@
package cn.axzo.nanopart.doc.rpc;
import cn.axzo.nanopart.doc.integration.OssClient;
import cn.axzo.oss.http.api.ServerFileServiceApi;
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.azxo.framework.common.model.CommonResponse;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* OSS文件访问
*
* @author xudawei@axzo.cn
* @date 2025/03/12
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class DocOssGateway {
private final ServerFileServiceApi serverFileServiceApi;
/**
* 获取下载地址
*/
public List<ApiSignUrlDownloadResponse> signUrlFetchDownload(ApiSignUrlDownloadRequest request) {
try {
log.info("DocOssGateway-signUrlFetchDownload request:{}", JSON.toJSONString(request));
CommonResponse<List<ApiSignUrlDownloadResponse>> response = serverFileServiceApi.signUrlFetchDownload(request);
log.info("DocOssGateway-signUrlFetchDownload result:{}", JSON.toJSONString(response));
return response.getData();
} catch (Exception e) {
log.warn("DocOssGateway-signUrlFetchDownload exception", e);
throw e;
}
}
/**
* 更新文件
*/
public UpdateFileInfoResponse updateFileInfo(UpdateFileInfoRequest request) {
try {
log.info("DocOssGateway-updateFileInfo request:{}", JSON.toJSONString(request));
CommonResponse<UpdateFileInfoResponse> response = serverFileServiceApi.updateFileInfo(request);
log.info("DocOssGateway-updateFileInfo result:{}", JSON.toJSONString(response));
return response.getData();
} catch (Exception e) {
log.warn("DocOssGateway-updateFileInfo exception", e);
throw e;
}
}
}

View File

@ -0,0 +1,62 @@
package cn.axzo.nanopart.doc.rpc;
import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.basics.profiles.api.UserProfileServiceApi;
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
import cn.axzo.basics.profiles.dto.request.QueryPersonProfileByIdOrPhoneDto;
import cn.axzo.oss.http.api.ServerFileServiceApi;
import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest;
import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse;
import cn.azxo.framework.common.model.CommonResponse;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
/**
* 人员档案
*
* @author xudawei@axzo.cn
* @date 2025/03/12
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class DocUserProfileGateway {
private final UserProfileServiceApi userProfileService;
/**
* 获取用户信息
*/
public List<PersonProfileDto> findPersonProfileListByIdOrPhone(QueryPersonProfileByIdOrPhoneDto request) {
AssertUtil.isFalse(Objects.isNull(request) || (CollectionUtil.isEmpty(request.getPhones()) && CollectionUtil.isEmpty(request.getPersonIds()))
, "personIds and phones is empty");
try {
log.info("DocUserProfileGateway-findPersonProfileListByIdOrPhone request:{}", JSON.toJSONString(request));
CommonResponse<List<PersonProfileDto>> response = userProfileService.findPersonProfileListByIdOrPhone(request);
log.info("DocUserProfileGateway-findPersonProfileListByIdOrPhone result:{}", JSON.toJSONString(response));
return response.getData();
} catch (Exception e) {
log.warn("DocUserProfileGateway-findPersonProfileListByIdOrPhone exception", e);
throw e;
}
}
/**
* 查询人员档案
* @param personIds
* @return
*/
public List<PersonProfileDto> personProfileByPersonIds(List<Long> personIds) {
AssertUtil.isFalse(CollectionUtil.isEmpty(personIds), "personIds is empty");
//查询人员档案集合
return this.findPersonProfileListByIdOrPhone(QueryPersonProfileByIdOrPhoneDto.builder()
.personIds(personIds).build());
}
}

View File

@ -1,4 +1,4 @@
package cn.axzo.nanopart.doc.wps;
package cn.axzo.nanopart.doc.wps.wpsbase;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.nanopart.doc.api.wps.WpsBaseApi;
@ -28,6 +28,8 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
public class WpsBaseController implements WpsBaseApi {
private final WpsBaseManager wpsBaseManager;
/**
* 获取文件信息
* <p> 公有云wps回调接口
@ -35,8 +37,7 @@ public class WpsBaseController implements WpsBaseApi {
*/
@Override
public ApiResult<WpsFetchFileResponse> fetchFile(@Validated @RequestBody WpsFetchFileRequest request) {
return ApiResult.ok();
return ApiResult.ok(wpsBaseManager.fetchFileBase(request.getDocCode()));
}
/**
@ -46,7 +47,7 @@ public class WpsBaseController implements WpsBaseApi {
*/
@Override
public ApiResult<WpsFetchDownloadResponse> fetchDownload(@Validated @RequestBody WpsFetchDownloadRequest request) {
return ApiResult.ok();
return ApiResult.ok(wpsBaseManager.fetchDownload(request.getDocCode()));
}
/**
@ -57,7 +58,7 @@ public class WpsBaseController implements WpsBaseApi {
*/
@Override
public ApiResult<WpsPermissionResponse> permission(@Validated @RequestBody WpsPermissionRequest request) {
return ApiResult.ok();
return ApiResult.ok(wpsBaseManager.permission(request));
}
/**
@ -67,7 +68,7 @@ public class WpsBaseController implements WpsBaseApi {
*/
@Override
public ApiResult<WpsUsersResponse> users(@Validated @RequestBody WpsUsersRequest request) {
return ApiResult.ok();
return ApiResult.ok(wpsBaseManager.users(request));
}
/**
@ -77,7 +78,7 @@ public class WpsBaseController implements WpsBaseApi {
*/
@Override
public ApiResult<WpsRenameResponse> rename(@Validated @RequestBody WpsRenameRequest request) {
return ApiResult.ok();
return ApiResult.ok(wpsBaseManager.rename(request));
}
}

View File

@ -0,0 +1,148 @@
package cn.axzo.nanopart.doc.wps.wpsbase;
import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
import cn.axzo.nanopart.doc.api.wps.request.WpsPermissionRequest;
import cn.axzo.nanopart.doc.api.wps.request.WpsRenameRequest;
import cn.axzo.nanopart.doc.api.wps.request.WpsUsersRequest;
import cn.axzo.nanopart.doc.api.wps.response.WpsFetchDownloadResponse;
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 cn.axzo.nanopart.doc.dao.IndexNodeDao;
import cn.axzo.nanopart.doc.entity.IndexNode;
import cn.axzo.nanopart.doc.rpc.DocOssGateway;
import cn.axzo.nanopart.doc.rpc.DocUserProfileGateway;
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对接基础信息
* @author xudawei@axzo.cn
* @date 2025/03/12
*/
@Component
@RequiredArgsConstructor
public class WpsBaseManager {
private final IndexNodeDao indexNodeDao;
private final DocOssGateway docOssGateway;
private final DocUserProfileGateway docUserProfileGateway;
/**
* 获取文件基础信息
* @param docCode 文件编码
*/
public WpsFetchFileResponse fetchFileBase(String docCode) {
IndexNode node = indexNodeDao.getNodeOrThrow(docCode);
return WpsFetchFileResponse.builder()
.docCode(docCode)
.name(node.getName())
.version(node.getAttributes().getFileAttributes().getVersion())
.size(node.getSize())
.createAt(node.getCreateAt())
.updateAt(node.getUpdateAt())
.creatorId(node.getAttributes().getFileAttributes().getCreatorId())
.modifierId(node.getAttributes().getFileAttributes().getModifierId())
.build();
}
/**
* 获取文档下载信息
* @param docCode 文件编码
*/
public WpsFetchDownloadResponse fetchDownload(String docCode) {
IndexNode node = indexNodeDao.getNodeOrThrow(docCode);
return WpsFetchDownloadResponse.builder()
.url(this.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> apiSignUrlDownloadResponses = docOssGateway.signUrlFetchDownload(request);
return apiSignUrlDownloadResponses.get(0).getSignUrl();
}
/**
* 文档权限
* 暂时全部开放权限REQ-35401期只是OMS没有文件权限功能待REQ-3540的2期建立权限后再对接
*/
public WpsPermissionResponse permission(WpsPermissionRequest request) {
return WpsPermissionResponse.builder()
.personId(request.getPersonId())
.read(1)
.update(1)
.download(1)
.rename(1)
.history(1)
.copy(1)
.print(1)
.saveas(1)
.comment(1)
.build();
}
/**
* 用户信息
*/
public WpsUsersResponse users(WpsUsersRequest request) {
AssertUtil.isFalse(Objects.isNull(request) || CollectionUtil.isEmpty(request.getPersonIds()), "入参错误");
//查询人员档案
List<PersonProfileDto> personProfiles = this.docUserProfileGateway.personProfileByPersonIds(request.getPersonIds().stream().map(Long::parseLong).collect(Collectors.toList()));
if (CollectionUtil.isEmpty(personProfiles)) {
return WpsUsersResponse.builder().build();
}
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()))
.build();
}
/**
* 文件重命名
*/
public WpsRenameResponse rename(WpsRenameRequest request) {
AssertUtil.isFalse(Objects.isNull(request) || StringUtils.isEmpty(request.getDocCode()) || StringUtils.isEmpty(request.getName()), "参数错误");
IndexNode node = indexNodeDao.getNodeOrThrow(request.getDocCode());
if (Objects.isNull(node)
|| Objects.isNull(node.getAttributes())
|| Objects.isNull(node.getAttributes().getFileAttributes())
|| StringUtils.isBlank(node.getAttributes().getFileAttributes().getOssFileKey())) {
return WpsRenameResponse.builder().updateFlag(false).build();
}
indexNodeDao.rename(request.getDocCode(), request.getName());
UpdateFileInfoResponse response = this.docOssGateway.updateFileInfo(UpdateFileInfoRequest.builder().fileKey(node.getAttributes().getFileAttributes().getOssFileKey()).build());
return WpsRenameResponse.builder().updateFlag(response.isUpdateFlag()).build();
}
}

View File

@ -1,4 +1,4 @@
package cn.axzo.nanopart.doc.wps;
package cn.axzo.nanopart.doc.wps.wpsedit;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.nanopart.doc.api.wps.WpsEditApi;
@ -27,6 +27,8 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
public class WpsEditController implements WpsEditApi {
private final WpsEditManager wpsEditManager;
/**
* 文档编辑
* 1 准备上传阶段
@ -35,7 +37,7 @@ public class WpsEditController implements WpsEditApi {
*/
@Override
public ApiResult<WpsEditUploadPrepareResponse> uploadPrepare(@Validated @RequestBody WpsEditUploadPrepareRequest request) {
return ApiResult.ok();
return ApiResult.ok(wpsEditManager.uploadPrepare(request));
}
/**

View File

@ -0,0 +1,44 @@
package cn.axzo.nanopart.doc.wps.wpsedit;
import cn.axzo.nanopart.doc.api.wps.request.WpsEditUploadAddressRequest;
import cn.axzo.nanopart.doc.api.wps.request.WpsEditUploadPrepareRequest;
import cn.axzo.nanopart.doc.api.wps.response.WpsEditUploadAddressResponse;
import cn.axzo.nanopart.doc.api.wps.response.WpsEditUploadPrepareResponse;
import cn.axzo.nanopart.doc.dao.TemplateDatabaseDao;
import cn.axzo.nanopart.doc.file.index.IndexManager;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
* @author yanglin
*/
@Component
@RequiredArgsConstructor
public class WpsEditManager {
private final IndexManager indexManager;
private final TemplateDatabaseDao templateDatabaseDao;
/**
* 文档编辑
* 1 准备上传阶段
* 说明三阶段保存的第一步主要用于 WebOffice 与接入方进行参数协商目前主要协商摘要算法
*
*/
public WpsEditUploadPrepareResponse uploadPrepare(WpsEditUploadPrepareRequest request) {
return WpsEditUploadPrepareResponse.builder().digestTypes(new String[]{"sha1"}).build();
}
/**
* 文档编辑
* 2 获取上传地址
* 说明三阶段保存第二步主要用于获取上传地址WebOffice 将上传保存后的文档到该地址
* 此外回调中也会带上本次保存的一些额外信息如文档大小手动/自动保存等
*/
public WpsEditUploadAddressResponse uploadAddress(WpsEditUploadAddressRequest request) {
return WpsEditUploadAddressResponse.builder().build();
}
}