diff --git a/wmyun-gateway/src/main/java/com/wmyun/gateway/filter/logging/AccessLogFilter.java b/wmyun-gateway/src/main/java/com/wmyun/gateway/filter/logging/AccessLogFilter.java index f09e528..92a5725 100644 --- a/wmyun-gateway/src/main/java/com/wmyun/gateway/filter/logging/AccessLogFilter.java +++ b/wmyun-gateway/src/main/java/com/wmyun/gateway/filter/logging/AccessLogFilter.java @@ -79,6 +79,7 @@ public class AccessLogFilter implements GlobalFilter, Ordered { values.put("userType", gatewayLog.getUserType()); values.put("routeId", gatewayLog.getRoute() != null ? gatewayLog.getRoute().getId() : null); values.put("schema", gatewayLog.getSchema()); + values.put("requestMethod", gatewayLog.getRequestMethod()); values.put("requestUrl", gatewayLog.getRequestUrl()); values.put("queryParams", gatewayLog.getQueryParams().toSingleValueMap()); values.put("requestBody", JsonUtils.isJson(gatewayLog.getRequestBody()) ? // 保证 body 的展示好看 diff --git a/wmyun-module-bpm/wmyun-module-bpm-biz/src/main/resources/application-dev.yaml b/wmyun-module-bpm/wmyun-module-bpm-biz/src/main/resources/application-dev.yaml index 1915b0e..1def925 100644 --- a/wmyun-module-bpm/wmyun-module-bpm-biz/src/main/resources/application-dev.yaml +++ b/wmyun-module-bpm/wmyun-module-bpm-biz/src/main/resources/application-dev.yaml @@ -110,4 +110,4 @@ spring: # 芋道配置项,设置当前项目所有自定义的配置 wmyun: - demo: true # 开启演示模式 + demo: false # 开启演示模式 diff --git a/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/controller/admin/file/OfficePreviewController.java b/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/controller/admin/file/OfficePreviewController.java new file mode 100644 index 0000000..ee40645 --- /dev/null +++ b/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/controller/admin/file/OfficePreviewController.java @@ -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 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(); + } +} diff --git a/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/controller/admin/file/vo/preview/CheckFileInfoVo.java b/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/controller/admin/file/vo/preview/CheckFileInfoVo.java new file mode 100644 index 0000000..cde45a6 --- /dev/null +++ b/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/controller/admin/file/vo/preview/CheckFileInfoVo.java @@ -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 https://learn.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/checkfileinfo/checkfileinfo-response + * @link https://learn.microsoft.com/en-us/openspecs/office_protocols/ms-wopi/71e66fb4-144b-4369-b597-f425f0b700b9?redirectedfrom=MSDN + * @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; +} diff --git a/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/controller/admin/file/vo/preview/WopiFileVo.java b/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/controller/admin/file/vo/preview/WopiFileVo.java new file mode 100644 index 0000000..618ea58 --- /dev/null +++ b/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/controller/admin/file/vo/preview/WopiFileVo.java @@ -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; +} diff --git a/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/service/file/FilePreviewService.java b/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/service/file/FilePreviewService.java new file mode 100644 index 0000000..a250aec --- /dev/null +++ b/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/service/file/FilePreviewService.java @@ -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); +} diff --git a/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/service/file/FilePreviewServiceImpl.java b/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/service/file/FilePreviewServiceImpl.java new file mode 100644 index 0000000..3b95a10 --- /dev/null +++ b/wmyun-module-infra/wmyun-module-infra-biz/src/main/java/com/wmyun/module/infra/service/file/FilePreviewServiceImpl.java @@ -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 queryWrapperX = new LambdaQueryWrapperX<>(); + queryWrapperX.eq(FileDO::getId, fileId).eq(FileDO::getDeleted, false); + List 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); + } + } +} diff --git a/wmyun-module-infra/wmyun-module-infra-biz/src/main/resources/application-dev.yaml b/wmyun-module-infra/wmyun-module-infra-biz/src/main/resources/application-dev.yaml index 4ff842b..4ba9eb4 100644 --- a/wmyun-module-infra/wmyun-module-infra-biz/src/main/resources/application-dev.yaml +++ b/wmyun-module-infra/wmyun-module-infra-biz/src/main/resources/application-dev.yaml @@ -127,4 +127,4 @@ spring: # 芋道配置项,设置当前项目所有自定义的配置 wmyun: - demo: true # 开启演示模式 + demo: false # 开启演示模式 diff --git a/wmyun-module-infra/wmyun-module-infra-biz/src/main/resources/application.yaml b/wmyun-module-infra/wmyun-module-infra-biz/src/main/resources/application.yaml index db686e9..99d0ed7 100644 --- a/wmyun-module-infra/wmyun-module-infra-biz/src/main/resources/application.yaml +++ b/wmyun-module-infra/wmyun-module-infra-biz/src/main/resources/application.yaml @@ -166,6 +166,7 @@ wmyun: enable: true ignore-urls: - /admin-api/infra/file/*/get/** # 获取图片,和租户无关 + - /admin-api/infra/file/preview/** ignore-tables: - infra_codegen_column - infra_codegen_table diff --git a/wmyun-module-system/wmyun-module-system-biz/src/main/java/com/wmyun/module/system/service/user/AdminUserService.java b/wmyun-module-system/wmyun-module-system-biz/src/main/java/com/wmyun/module/system/service/user/AdminUserService.java index 10d2454..a90e259 100644 --- a/wmyun-module-system/wmyun-module-system-biz/src/main/java/com/wmyun/module/system/service/user/AdminUserService.java +++ b/wmyun-module-system/wmyun-module-system-biz/src/main/java/com/wmyun/module/system/service/user/AdminUserService.java @@ -216,4 +216,6 @@ public interface AdminUserService { */ boolean isPasswordMatch(String rawPassword, String encodedPassword); + String encodePassword(String password); + } diff --git a/wmyun-module-system/wmyun-module-system-biz/src/main/java/com/wmyun/module/system/service/user/AdminUserServiceImpl.java b/wmyun-module-system/wmyun-module-system-biz/src/main/java/com/wmyun/module/system/service/user/AdminUserServiceImpl.java index 70a4a96..a255280 100644 --- a/wmyun-module-system/wmyun-module-system-biz/src/main/java/com/wmyun/module/system/service/user/AdminUserServiceImpl.java +++ b/wmyun-module-system/wmyun-module-system-biz/src/main/java/com/wmyun/module/system/service/user/AdminUserServiceImpl.java @@ -520,7 +520,8 @@ public class AdminUserServiceImpl implements AdminUserService { * @param password 密码 * @return 加密后的密码 */ - private String encodePassword(String password) { + @Override + public String encodePassword(String password) { return passwordEncoder.encode(password); }