feat: preview file
This commit is contained in:
parent
fa867dbc27
commit
335b8dfce5
@ -79,6 +79,7 @@ public class AccessLogFilter implements GlobalFilter, Ordered {
|
|||||||
values.put("userType", gatewayLog.getUserType());
|
values.put("userType", gatewayLog.getUserType());
|
||||||
values.put("routeId", gatewayLog.getRoute() != null ? gatewayLog.getRoute().getId() : null);
|
values.put("routeId", gatewayLog.getRoute() != null ? gatewayLog.getRoute().getId() : null);
|
||||||
values.put("schema", gatewayLog.getSchema());
|
values.put("schema", gatewayLog.getSchema());
|
||||||
|
values.put("requestMethod", gatewayLog.getRequestMethod());
|
||||||
values.put("requestUrl", gatewayLog.getRequestUrl());
|
values.put("requestUrl", gatewayLog.getRequestUrl());
|
||||||
values.put("queryParams", gatewayLog.getQueryParams().toSingleValueMap());
|
values.put("queryParams", gatewayLog.getQueryParams().toSingleValueMap());
|
||||||
values.put("requestBody", JsonUtils.isJson(gatewayLog.getRequestBody()) ? // 保证 body 的展示好看
|
values.put("requestBody", JsonUtils.isJson(gatewayLog.getRequestBody()) ? // 保证 body 的展示好看
|
||||||
|
@ -110,4 +110,4 @@ spring:
|
|||||||
|
|
||||||
# 芋道配置项,设置当前项目所有自定义的配置
|
# 芋道配置项,设置当前项目所有自定义的配置
|
||||||
wmyun:
|
wmyun:
|
||||||
demo: true # 开启演示模式
|
demo: false # 开启演示模式
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.wmyun.module.infra.controller.admin.file;
|
||||||
|
|
||||||
|
import com.wmyun.module.infra.controller.admin.file.vo.preview.CheckFileInfoVo;
|
||||||
|
import com.wmyun.module.infra.service.file.FilePreviewService;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.security.PermitAll;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import static com.wmyun.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: 文件预览Wopi
|
||||||
|
* @Date: 2025/2/26 18:18
|
||||||
|
* @Created: by ZZSLL
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Tag(name = "管理后台 - 文件预览")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/infra/file/preview/wopi")
|
||||||
|
public class OfficePreviewController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private FilePreviewService previewService;
|
||||||
|
|
||||||
|
@GetMapping("/files/{fileId}")
|
||||||
|
@PermitAll
|
||||||
|
public ResponseEntity<CheckFileInfoVo> getFileInfo(@PathVariable("fileId") String fileId) {
|
||||||
|
return ResponseEntity.ok().body(previewService.createPreviewInfo(fileId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/files/{fileId}/contents")
|
||||||
|
@PermitAll
|
||||||
|
public void getFileContents(@PathVariable String fileId, HttpServletResponse response) {
|
||||||
|
previewService.getFileContent(fileId, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/files/{fileId}/contents", method = {RequestMethod.POST, RequestMethod.PUT})
|
||||||
|
@PermitAll
|
||||||
|
public ResponseEntity<?> putFileContents(@PathVariable String fileId, InputStream contentStream) {
|
||||||
|
previewService.saveFile(fileId, contentStream);
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package com.wmyun.module.infra.controller.admin.file.vo.preview;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: wopi server文件信息
|
||||||
|
* @link <a href="https://learn.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/checkfileinfo/checkfileinfo-response">https://learn.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/checkfileinfo/checkfileinfo-response<a/>
|
||||||
|
* @link <a href="https://learn.microsoft.com/en-us/openspecs/office_protocols/ms-wopi/71e66fb4-144b-4369-b597-f425f0b700b9?redirectedfrom=MSDN">https://learn.microsoft.com/en-us/openspecs/office_protocols/ms-wopi/71e66fb4-144b-4369-b597-f425f0b700b9?redirectedfrom=MSDN<a/>
|
||||||
|
* @Date: 2025/2/27 9:36
|
||||||
|
* @Created: by ZZSLL
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class CheckFileInfoVo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基本信息
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Schema(description = "文件名称")
|
||||||
|
@JsonProperty("BaseFileName")
|
||||||
|
private String baseFileName;
|
||||||
|
|
||||||
|
@Schema(description = "文件创建认")
|
||||||
|
@JsonProperty("OwnerId")
|
||||||
|
private String ownerId;
|
||||||
|
|
||||||
|
@Schema(description = "文件大小")
|
||||||
|
@JsonProperty("Size")
|
||||||
|
private Long size;
|
||||||
|
|
||||||
|
@Schema(description = "当前用户id")
|
||||||
|
@JsonProperty("UserId")
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
@Schema(description = "用户昵称")
|
||||||
|
@JsonProperty("UserFriendlyName")
|
||||||
|
private String userFriendlyName;
|
||||||
|
|
||||||
|
@Schema(description = "版本号")
|
||||||
|
@JsonProperty("Version")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WOPI host capabilities properties
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Schema(description = "支持删除文档")
|
||||||
|
@JsonProperty("SupportsDeleteFile")
|
||||||
|
private Boolean supportsDeleteFile;
|
||||||
|
|
||||||
|
@Schema(description = "支持文件重命名")
|
||||||
|
@JsonProperty("SupportsRename")
|
||||||
|
private Boolean supportsRename;
|
||||||
|
|
||||||
|
@Schema(description = "支持更新文件")
|
||||||
|
@JsonProperty("SupportsUpdate")
|
||||||
|
private Boolean supportsUpdate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://learn.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/checkfileinfo/checkfileinfo-response#userinfo
|
||||||
|
*/
|
||||||
|
@Schema(description = "支持获取用户信息")
|
||||||
|
@JsonProperty("SupportsUserInfo")
|
||||||
|
private Boolean supportsUserInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User permissions properties
|
||||||
|
*/
|
||||||
|
@Schema(description = "只读")
|
||||||
|
@JsonProperty("ReadOnly")
|
||||||
|
private Boolean readOnly;
|
||||||
|
|
||||||
|
@Schema(description = "重命名")
|
||||||
|
@JsonProperty("UserCanRename")
|
||||||
|
private Boolean userCanRename;
|
||||||
|
|
||||||
|
@Schema(description = "更新文件")
|
||||||
|
@JsonProperty("UserCanWrite")
|
||||||
|
private Boolean userCanWrite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File URL properties
|
||||||
|
*/
|
||||||
|
@Schema(description = "文件下载地址")
|
||||||
|
@JsonProperty("DownloadUrl")
|
||||||
|
private String downloadUrl;
|
||||||
|
|
||||||
|
@Schema(description = "文件下载地址(可代替wopi中的putfile)")
|
||||||
|
@JsonProperty("FileUrl")
|
||||||
|
private String fileUrl;
|
||||||
|
|
||||||
|
@Schema(description = "HOST地址")
|
||||||
|
@JsonProperty("HostViewUrl")
|
||||||
|
private String hostViewUrl;
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.wmyun.module.infra.controller.admin.file.vo.preview;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: TODO
|
||||||
|
* @Date: 2025/2/19 16:56
|
||||||
|
* @Created: by ZZSLL
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
public class WopiFileVo {
|
||||||
|
private String fileId;
|
||||||
|
private String fileName;
|
||||||
|
private long size;
|
||||||
|
private String ownerId;
|
||||||
|
private Path filePath;
|
||||||
|
private boolean userCanWrite;
|
||||||
|
private boolean supportsLocks;
|
||||||
|
private String contentType;
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.wmyun.module.infra.service.file;
|
||||||
|
|
||||||
|
import com.wmyun.module.infra.controller.admin.file.vo.preview.CheckFileInfoVo;
|
||||||
|
import com.wmyun.module.infra.controller.admin.file.vo.preview.WopiFileVo;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname FilePreviceService
|
||||||
|
* @Description TODO
|
||||||
|
* @Date 2025/2/26 18:24
|
||||||
|
* @Created by violet
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface FilePreviewService {
|
||||||
|
|
||||||
|
CheckFileInfoVo createPreviewInfo(String fileId);
|
||||||
|
|
||||||
|
void saveFile(String fileId, InputStream content);
|
||||||
|
|
||||||
|
void getFileContent(String fileId, HttpServletResponse response);
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
package com.wmyun.module.infra.service.file;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import com.wmyun.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import com.wmyun.framework.security.core.LoginUser;
|
||||||
|
import com.wmyun.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
|
import com.wmyun.module.infra.controller.admin.file.vo.preview.CheckFileInfoVo;
|
||||||
|
import com.wmyun.module.infra.dal.dataobject.file.FileDO;
|
||||||
|
import com.wmyun.module.infra.dal.mysql.file.FileMapper;
|
||||||
|
import com.wmyun.module.infra.framework.file.core.client.FileClient;
|
||||||
|
import com.wmyun.module.infra.framework.file.core.utils.FileTypeUtils;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static com.wmyun.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: TODO
|
||||||
|
* @Date: 2025/2/26 18:25
|
||||||
|
* @Created: by ZZSLL
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Service
|
||||||
|
|
||||||
|
public class FilePreviewServiceImpl implements FilePreviewService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private FileMapper fileMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private FileConfigService fileConfigService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CheckFileInfoVo createPreviewInfo(String fileId) {
|
||||||
|
FileDO file = queryFileInfoByFileId(fileId);
|
||||||
|
if (file == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
LoginUser user = SecurityFrameworkUtils.getLoginUser();
|
||||||
|
return CheckFileInfoVo.builder()
|
||||||
|
.baseFileName(file.getName())
|
||||||
|
.ownerId(file.getUpdater())
|
||||||
|
.size(Long.valueOf(file.getSize()))
|
||||||
|
.userId(String.valueOf(Optional.ofNullable(user)
|
||||||
|
.map(LoginUser::getId)
|
||||||
|
.orElse(0L)))
|
||||||
|
.userFriendlyName(Optional.ofNullable(user)
|
||||||
|
.map(LoginUser::getInfo)
|
||||||
|
.map(info -> info.get(LoginUser.INFO_KEY_NICKNAME))
|
||||||
|
.orElse(""))
|
||||||
|
.version("")
|
||||||
|
.supportsDeleteFile(false)
|
||||||
|
.supportsRename(false)
|
||||||
|
.supportsUpdate(true)
|
||||||
|
.supportsUserInfo(true)
|
||||||
|
.readOnly(true)
|
||||||
|
.userCanRename(false)
|
||||||
|
.userCanWrite(false)
|
||||||
|
.downloadUrl(file.getUrl())
|
||||||
|
.fileUrl(file.getUrl())
|
||||||
|
.hostViewUrl("")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询文件信息
|
||||||
|
* @param fileId 文件id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private FileDO queryFileInfoByFileId(String fileId) {
|
||||||
|
LambdaQueryWrapperX<FileDO> queryWrapperX = new LambdaQueryWrapperX<>();
|
||||||
|
queryWrapperX.eq(FileDO::getId, fileId).eq(FileDO::getDeleted, false);
|
||||||
|
List<FileDO> files = fileMapper.selectList(queryWrapperX);
|
||||||
|
return CollectionUtils.isNotEmpty(files) ? files.get(0) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveFile(String fileId, InputStream content) {
|
||||||
|
FileDO existFile = queryFileInfoByFileId(fileId);
|
||||||
|
FileClient client = fileConfigService.getMasterFileClient();
|
||||||
|
if (existFile == null) {
|
||||||
|
throw new RuntimeException("不支持创建文件");
|
||||||
|
}
|
||||||
|
byte[] data = IoUtil.readBytes(content);
|
||||||
|
String type = FileTypeUtils.getMineType(data, existFile.getName());
|
||||||
|
try {
|
||||||
|
String url = client.upload(data, existFile.getPath(), type);
|
||||||
|
existFile.setUrl(url);
|
||||||
|
fileMapper.updateById(existFile);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getFileContent(String fileId, HttpServletResponse response) {
|
||||||
|
FileDO file = queryFileInfoByFileId(fileId);
|
||||||
|
if (file == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FileClient client = fileConfigService.getFileClient(file.getConfigId());
|
||||||
|
try {
|
||||||
|
writeAttachment(response, file.getName(), client.getContent(file.getPath()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -127,4 +127,4 @@ spring:
|
|||||||
|
|
||||||
# 芋道配置项,设置当前项目所有自定义的配置
|
# 芋道配置项,设置当前项目所有自定义的配置
|
||||||
wmyun:
|
wmyun:
|
||||||
demo: true # 开启演示模式
|
demo: false # 开启演示模式
|
||||||
|
@ -166,6 +166,7 @@ wmyun:
|
|||||||
enable: true
|
enable: true
|
||||||
ignore-urls:
|
ignore-urls:
|
||||||
- /admin-api/infra/file/*/get/** # 获取图片,和租户无关
|
- /admin-api/infra/file/*/get/** # 获取图片,和租户无关
|
||||||
|
- /admin-api/infra/file/preview/**
|
||||||
ignore-tables:
|
ignore-tables:
|
||||||
- infra_codegen_column
|
- infra_codegen_column
|
||||||
- infra_codegen_table
|
- infra_codegen_table
|
||||||
|
@ -216,4 +216,6 @@ public interface AdminUserService {
|
|||||||
*/
|
*/
|
||||||
boolean isPasswordMatch(String rawPassword, String encodedPassword);
|
boolean isPasswordMatch(String rawPassword, String encodedPassword);
|
||||||
|
|
||||||
|
String encodePassword(String password);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -520,7 +520,8 @@ public class AdminUserServiceImpl implements AdminUserService {
|
|||||||
* @param password 密码
|
* @param password 密码
|
||||||
* @return 加密后的密码
|
* @return 加密后的密码
|
||||||
*/
|
*/
|
||||||
private String encodePassword(String password) {
|
@Override
|
||||||
|
public String encodePassword(String password) {
|
||||||
return passwordEncoder.encode(password);
|
return passwordEncoder.encode(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user