同步文件元信息
开启 autoUpgrade 后,命中同名文件时将自动将同名文件迭代升级为新版本
| 接口名 | POST: /login-register/open-api/documents/sync-file-meta | |||
| 入参:(body传值) | application/json | |||
| 是否必传 | 默认值 | 描述 | 备注 | |
| fileMd5 | 是 | - | 文件MD5 | 文件MD5 |
| fileSize | 是 | - | 文件大小,单位字节 | |
| originalFilename | 是 | - | 原始文件名(例:'模型.prt') | 页面中展示的文件名 |
| fileName | 是 | - | 真实文件名(例:'uuid.prt') | 实际物理文件的文件名,用于文件存储,不能包含下列任何字符:\ / : * ? " < > | |
| dir | 是 | - | 相对路径 | 获取图文档上传链接接口返回的relativePath值 |
| pfolderId | 否 | "0" | 所属文件夹ID "0"代表根目录 |
所属文件夹ID,需提前创建父文件夹 为空时默认是"0" |
| autoUpgrade | 否 | "n" | 是否开启自动版本升级 | 是->y 否->n |
| fileScope | 是 | - | 文件归属域 | 我的空间->personal 项目空间(企业空间)->project |
| projectCode | 否 | - | 该项目在外部平台的唯一编码,需提前创建项目 | fileScope 为 project 时需要传递 |
| 入参:(Header传值) | ||||
| Authorization | 是 | - | 传递AccessToken | 格式:Bearer {AccessToken} |
| 入参示例:(application/json) | ||||
|
{
"fileId": "",
"fileMd5": "17fc1899dexxx9c24850d308a9",
"fileSize": 72635,
"originalFilename": "test.prt",
"fileName": "test.prt",
"dir": "sviewbusiness%2Ftest%2F20260526%2F105840196370411d9a70af13d98a45ed%2Ftest.prt",
"pfolderCode": "PROJ_001",
"autoUpgrade": "y",
"fileScope":"personal"
}
|
||||
| 回参示例:(application/json) | ||||
|
{
"code": 0,
"msg": null,
"data": {
"bucketName": "sviewngts",
"path": "sviewbusiness%2Ftest%2F20260526%2F105840196370411d9a70af13d98a45ed%2Ftest.prt",
"fileName": "test.prt",
"url": "/personal/space/download/7da327f74exxxx18d4ff661ac3e2830",
"fileId": "7da327f74exxxx18d4ff661ac3e2830",
"upgraded": true,
"revisionNumber": "V2",
"itemId": "7da327f74exxxx18d4fffdfdac3e2830"
},
"ok": true
}
|
||||
package com.hoteam.sview.demo;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.hoteam.sview.ngts.loginRegister.vo.OpenApiSyncFileMetaVO;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
/**
* OpenAPI - 同步文件元信息(自动升版) 调用Demo
* <p>
* 接口地址:POST /login-register/open-api/documents/sync-file-meta
* 鉴权:Header Authorization: Bearer {AccessToken}
* 调用时机:文件通过上传链接PUT上传完成后,同步文件元信息落库;支持同名文件自动迭代升版
* 字段说明:
* fileScope=personal(我的空间)无需传projectId;fileScope=project(项目空间)必须传入projectId
* autoUpgrade=y 开启同名文件自动版本迭代;n关闭,默认n
*/
@Slf4j
public class SyncFileMetaOpenApiDemo {
// 网关域名,部署替换为真实地址
private static final String API_URL = "http://your-gateway-host/login-register/open-api/documents/sync-file-meta";
// 上传状态常量
public static final String UPLOAD_STATUS_SUCCESS = "0";
public static final String UPLOAD_STATUS_FAIL = "1";
// 自动升版标识
public static final String AUTO_UPGRADE_ON = "y";
public static final String AUTO_UPGRADE_OFF = "n";
// 文件归属域
public static final String SCOPE_PERSONAL = "personal";
public static final String SCOPE_PROJECT = "project";
/**
* 同步文件元信息通用方法
*
* @param accessToken OAuth2获取的访问凭证
* @param fileMd5 文件MD5(必填)
* @param fileSize 文件字节大小(必填)
* @param originalFilename 页面展示文件名(必填)
* @param fileName OSS真实存储文件名(必填,禁止包含\/:*?"<>|)
* @param dir 上传链接接口返回的relativePath(必填)
* @param pfolderId 父文件夹ID,不传默认0(根目录)
* @param projectCode 该项目在外部平台的唯一编码,fileScope=project时必传
* @param autoUpgrade 是否自动升版 y/n,默认n
* @param fileScope personal=我的空间 / project=项目空间(必填)
* @param uploadStatus 上传状态 0成功/1失败
* @return 同步结果VO,失败返回null
*/
public static OpenApiSyncFileMetaVO syncFileMeta(String accessToken,
String fileMd5,
long fileSize,
String originalFilename,
String fileName,
String dir,
String pfolderId,
String projectCode,
String autoUpgrade,
String fileScope,
String uploadStatus) {
// 基础入参校验
if (StrUtil.isBlank(accessToken)) {
log.warn("accessToken 不能为空");
return null;
}
if (StrUtil.hasBlank(fileMd5, originalFilename, fileName, dir, fileScope, uploadStatus)) {
log.warn("必填参数缺失:fileMd5/originalFilename/fileName/dir/fileScope/uploadStatus 不能为空");
return null;
}
if (fileSize <= 0) {
log.warn("文件大小必须大于0,当前size:{}", fileSize);
return null;
}
// 校验文件名非法字符
if (StrUtil.containsAny(fileName, "\\", "/", ":", "*", "?", "\"", "<", ">", "|")) {
log.warn("真实文件名包含非法字符 fileName:{}", fileName);
return null;
}
// 项目空间强制校验projectId
if (SCOPE_PROJECT.equals(fileScope) && StrUtil.isBlank(projectCode)) {
log.warn("fileScope为project时,projectCode不能为空");
return null;
}
// 组装请求Body
JSONObject body = new JSONObject();
body.set("fileMd5", fileMd5);
body.set("fileSize", fileSize);
body.set("originalFilename", originalFilename);
body.set("fileName", fileName);
body.set("dir", dir);
body.set("pfolderId", StrUtil.isBlank(pfolderId) ? "0" : pfolderId);
body.set("uploadStatus", uploadStatus);
body.set("fileScope", fileScope);
body.set("autoUpgrade", StrUtil.isBlank(autoUpgrade) ? AUTO_UPGRADE_OFF : autoUpgrade);
// 项目ID仅非空时塞入
if (StrUtil.isNotBlank(projectId)) {
body.set("projectCode", projectCode);
}
// 构建请求
HttpRequest request = HttpRequest.post(API_URL)
.header(Header.AUTHORIZATION, "Bearer " + accessToken)
.header(Header.CONTENT_TYPE, ContentType.JSON.getValue())
.body(body.toString())
.timeout(10_000);
// 注入公共请求头(租户、设备、语言等)
CommonHeaderUtil.withCommonHeaders(request);
try (HttpResponse response = request.execute()) {
int httpCode = response.getStatus();
String respBody = response.body();
log.info("同步文件元信息接口响应 httpCode:{}, body:{}", httpCode, respBody);
// 401鉴权失败
if (httpCode == HttpStatus.HTTP_UNAUTHORIZED) {
log.warn("AccessToken失效或无权限,响应:{}", respBody);
return null;
}
// HTTP非200判定异常
if (!response.isOk() || StrUtil.isBlank(respBody)) {
log.warn("接口请求异常 httpCode:{} body:{}", httpCode, respBody);
return null;
}
JSONObject respJson = JSONUtil.parseObj(respBody);
// 业务码code=0代表成功
Integer code = respJson.getInt("code");
if (code == null || code != 0) {
log.warn("业务处理失败 code:{}, msg:{}, fullBody:{}", code, respJson.getStr("msg"), respBody);
return null;
}
// 解析data为返回VO
JSONObject data = respJson.getJSONObject("data");
if (data == null) {
log.warn("响应data为空 body:{}", respBody);
return null;
}
OpenApiSyncFileMetaVO vo = JSONUtil.toBean(data, OpenApiSyncFileMetaVO.class);
log.info("文件元信息同步成功 fileId:{} 是否升版:{} 版本号:{}",
vo.getFileId(), vo.getUpgraded(), vo.getRevisionNumber());
return vo;
} catch (Exception e) {
log.error("同步文件元信息请求发生异常", e);
return null;
}
}
public static void main(String[] args) {
// 1. 获取登录凭证
String accessToken = OAuth2TokenIntegrationDemo.getAccessTokenByIntegration("18377xxxxxxx69049");
// 2. 本地待上传文件
File localFile = new File("D:/model/test.prt");
String originalFileName = "设备模型.prt";
String realFileName = SecureUtil.md5(localFile) + ".prt";
long fileSize = localFile.length();
String fileMd5 = SecureUtil.md5(localFile);
// 3. 前置:调用获取上传链接接口拿到relativePath
GetUploadUrlDemo.UploadUrlResult uploadUrlResult = GetUploadUrlDemo.getUploadUrl(realFileName, GetUploadUrlDemo.Category.ENT_MY_SPACE);
if (uploadUrlResult == null) {
log.error("获取上传链接失败,终止流程");
return;
}
// 4. 前置:PUT上传文件至OSS
boolean uploadSuccess = LocalUploadDemo.uploadByUploadUrl(uploadUrlResult.getUploadUrl(), localFile);
if (!uploadSuccess) {
log.error("文件OSS上传失败,终止流程");
return;
}
// ====================== 场景1:我的空间(personal,无需projectId,关闭自动升版)======================
OpenApiSyncFileMetaVO personalResult = syncFileMeta(
accessToken,
fileMd5,
fileSize,
originalFileName,
realFileName,
uploadUrlResult.getRelativePath(),
"0", // 根目录
null,
AUTO_UPGRADE_OFF,
SCOPE_PERSONAL,
UPLOAD_STATUS_SUCCESS
);
if (personalResult != null) {
log.info("我的空间文件同步完成 fileId:{} 下载地址:{}", personalResult.getFileId(), personalResult.getUrl());
}
// ====================== 场景2:项目空间(project,传projectId,开启自动升版)======================
String targetProjectId = "proj_00123456789";
OpenApiSyncFileMetaVO projectResult = syncFileMeta(
accessToken,
fileMd5,
fileSize,
originalFileName,
realFileName,
uploadUrlResult.getRelativePath(),
"folder_666",
projectCode,
AUTO_UPGRADE_ON,
SCOPE_PROJECT,
UPLOAD_STATUS_SUCCESS
);
if (projectResult != null) {
log.info("项目空间文件同步完成 fileId:{} 已升版:{} 新版本号:{}",
projectResult.getFileId(), projectResult.getUpgraded(), projectResult.getRevisionNumber());
}
}
}