Skip to content

Commit

Permalink
refactor: 重构原有文件上传接口并优化配置文件配置格式
Browse files Browse the repository at this point in the history
移除 ContiNew Starter 本地存储依赖
  • Loading branch information
Charles7c committed Dec 29, 2023
1 parent 44227ea commit 5e37025
Show file tree
Hide file tree
Showing 18 changed files with 193 additions and 222 deletions.
8 changes: 1 addition & 7 deletions continew-admin-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,6 @@
<artifactId>continew-starter-file-excel</artifactId>
</dependency>

<!-- ContiNew Starter 存储模块 - 本地存储 -->
<dependency>
<groupId>top.charles7c.continew</groupId>
<artifactId>continew-starter-storage-local</artifactId>
</dependency>

<!-- ContiNew Starter API 文档模块 -->
<dependency>
<groupId>top.charles7c.continew</groupId>
Expand All @@ -93,7 +87,7 @@
<groupId>org.dromara.x-file-storage</groupId>
<artifactId>x-file-storage-spring</artifactId>
</dependency>
<!-- Amazon Simple Storage Service亚马逊简单存储服务,通用存储协议 S3,兼容主流云厂商对象存储) -->
<!-- Amazon S3(Amazon Simple Storage Service亚马逊简单存储服务,通用存储协议 S3,兼容主流云厂商对象存储) -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package top.charles7c.continew.admin.system.config;

import java.util.Optional;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

Expand All @@ -25,13 +27,15 @@

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.EscapeUtil;
import cn.hutool.core.util.StrUtil;

import top.charles7c.continew.admin.common.util.helper.LoginHelper;
import top.charles7c.continew.admin.system.enums.FileTypeEnum;
import top.charles7c.continew.admin.system.mapper.FileMapper;
import top.charles7c.continew.admin.system.mapper.StorageMapper;
import top.charles7c.continew.admin.system.model.entity.FileDO;
import top.charles7c.continew.admin.system.model.entity.StorageDO;
import top.charles7c.continew.starter.core.constant.StringConstants;

/**
* 文件记录实现类
Expand All @@ -50,7 +54,9 @@ public class FileRecorderImpl implements FileRecorder {
@Override
public boolean save(FileInfo fileInfo) {
FileDO file = new FileDO();
file.setName(EscapeUtil.unescape(fileInfo.getOriginalFilename()));
String originalFilename = EscapeUtil.unescape(fileInfo.getOriginalFilename());
file.setName(StrUtil.contains(originalFilename, StringConstants.DOT)
? StrUtil.subBefore(originalFilename, StringConstants.DOT, true) : originalFilename);
file.setSize(fileInfo.getSize());
file.setUrl(fileInfo.getUrl());
file.setExtension(fileInfo.getExt());
Expand All @@ -66,17 +72,40 @@ public boolean save(FileInfo fileInfo) {

@Override
public FileInfo getByUrl(String url) {
FileDO file = fileMapper.lambdaQuery().eq(FileDO::getUrl, url).one();
FileDO file = this.getFileByUrl(url);
if (null == file) {
return null;
}
FileInfo fileInfo = new FileInfo();
fileInfo.setOriginalFilename(file.getName());
String extension = file.getExtension();
fileInfo.setOriginalFilename(
StrUtil.isNotBlank(extension) ? file.getName() + StringConstants.DOT + extension : file.getName());
fileInfo.setSize(file.getSize());
fileInfo.setUrl(file.getUrl());
fileInfo.setExt(file.getExtension());
fileInfo.setExt(extension);
fileInfo.setBasePath(StringConstants.EMPTY);
fileInfo.setPath(StringConstants.EMPTY);
fileInfo.setFilename(StrUtil.subAfter(url, StringConstants.SLASH, true));
fileInfo.setPlatform(storageMapper.lambdaQuery().eq(StorageDO::getId, file.getStorageId()).one().getCode());
return fileInfo;
}

@Override
public boolean delete(String url) {
return fileMapper.lambdaUpdate().eq(FileDO::getUrl, url).remove();
FileDO file = this.getFileByUrl(url);
return fileMapper.lambdaUpdate().eq(FileDO::getUrl, file.getUrl()).remove();
}

/**
* 根据 URL 查询文件
*
* @param url
* URL
* @return 文件信息
*/
private FileDO getFileByUrl(String url) {
Optional<FileDO> fileOptional = fileMapper.lambdaQuery().eq(FileDO::getUrl, url).oneOpt();
return fileOptional.orElseGet(() -> fileMapper.lambdaQuery()
.eq(FileDO::getUrl, StrUtil.subAfter(url, StringConstants.SLASH, true)).oneOpt().orElse(null));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
* @since 2023/12/24 22:31
*/
@Slf4j
//@Component
@Component
@RequiredArgsConstructor
public class FileStorageConfigLoader implements ApplicationRunner {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.util.List;

import org.dromara.x.file.storage.core.FileInfo;
import org.springframework.web.multipart.MultipartFile;

import top.charles7c.continew.admin.system.model.query.FileQuery;
Expand All @@ -39,9 +40,10 @@ public interface FileService extends BaseService<FileResp, FileDetailResp, FileQ
*
* @param file
* 文件信息
* @return 文件信息
*/
default void upload(MultipartFile file) {
upload(file, null);
default FileInfo upload(MultipartFile file) {
return upload(file, null);
}

/**
Expand All @@ -51,8 +53,9 @@ default void upload(MultipartFile file) {
* 文件信息
* @param storageCode
* 存储库编码
* @return 文件信息
*/
void upload(MultipartFile file, String storageCode);
FileInfo upload(MultipartFile file, String storageCode);

/**
* 根据存储库 ID 列表查询
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;

import top.charles7c.continew.admin.system.enums.StorageTypeEnum;
import top.charles7c.continew.admin.system.mapper.FileMapper;
import top.charles7c.continew.admin.system.model.entity.FileDO;
import top.charles7c.continew.admin.system.model.entity.StorageDO;
Expand Down Expand Up @@ -62,13 +63,16 @@ public class FileServiceImpl extends BaseServiceImpl<FileMapper, FileDO, FileRes
private final FileStorageService fileStorageService;

@Override
public void upload(MultipartFile file, String storageCode) {
public FileInfo upload(MultipartFile file, String storageCode) {
StorageDO storage;
if (StrUtil.isBlank(storageCode)) {
StorageDO storage = storageService.getDefaultStorage();
storage = storageService.getDefaultStorage();
CheckUtils.throwIfNull(storage, "请先指定默认存储库");
storageCode = storage.getCode();
} else {
storage = storageService.getByCode(storageCode);
CheckUtils.throwIfNotExists(storage, "StorageDO", "Code", storageCode);
}
UploadPretreatment uploadPretreatment = fileStorageService.of(file).setPlatform(storageCode);
UploadPretreatment uploadPretreatment = fileStorageService.of(file).setPlatform(storage.getCode());
uploadPretreatment.setProgressMonitor(new ProgressListener() {
@Override
public void start() {
Expand All @@ -85,7 +89,11 @@ public void finish() {
log.info("上传结束");
}
});
uploadPretreatment.upload();
// 处理本地存储文件 URL
FileInfo fileInfo = uploadPretreatment.upload();
fileInfo.setUrl(StorageTypeEnum.LOCAL.equals(storage.getType())
? URLUtil.normalize(storage.getDomain() + StringConstants.SLASH + fileInfo.getUrl()) : fileInfo.getUrl());
return fileInfo;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ private void registerResource(Map<String, String> registerMapping, boolean isCan
new ResourceHandlerRegistry(applicationContext, servletContext, contentNegotiationManager, urlPathHelper);
// 重新注册相同 Pattern 的静态资源映射
for (Map.Entry<String, String> entry : registerMapping.entrySet()) {
String pathPattern = StrUtil.appendIfMissing(entry.getKey(), "/**");
String pathPattern = StrUtil.appendIfMissing(entry.getKey(), StringConstants.PATH_PATTERN);
String resourceLocations = StrUtil.appendIfMissing(entry.getValue(), StringConstants.SLASH);
// 移除之前注册过的相同 Pattern 映射
handlerMap.remove(pathPattern);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,22 @@

package top.charles7c.continew.admin.system.service.impl;

import java.io.File;
import java.time.LocalDateTime;
import java.util.*;

import jakarta.annotation.Resource;

import lombok.RequiredArgsConstructor;

import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.unit.DataSize;
import org.springframework.web.multipart.MultipartFile;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
Expand All @@ -51,17 +50,12 @@
import top.charles7c.continew.admin.system.model.req.UserRoleUpdateReq;
import top.charles7c.continew.admin.system.model.resp.UserDetailResp;
import top.charles7c.continew.admin.system.model.resp.UserResp;
import top.charles7c.continew.admin.system.service.DeptService;
import top.charles7c.continew.admin.system.service.RoleService;
import top.charles7c.continew.admin.system.service.UserRoleService;
import top.charles7c.continew.admin.system.service.UserService;
import top.charles7c.continew.admin.system.service.*;
import top.charles7c.continew.starter.core.constant.StringConstants;
import top.charles7c.continew.starter.core.util.ExceptionUtils;
import top.charles7c.continew.starter.core.util.FileUploadUtils;
import top.charles7c.continew.starter.core.util.validate.CheckUtils;
import top.charles7c.continew.starter.extension.crud.base.BaseServiceImpl;
import top.charles7c.continew.starter.extension.crud.base.CommonUserService;
import top.charles7c.continew.starter.storage.local.autoconfigure.LocalStorageProperties;

/**
* 用户业务实现
Expand All @@ -75,11 +69,12 @@
public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserResp, UserDetailResp, UserQuery, UserReq>
implements UserService, CommonUserService {

private final UserRoleService userRoleService;
private final RoleService roleService;
private final LocalStorageProperties localStorageProperties;
@Resource
private DeptService deptService;
private final RoleService roleService;
private final UserRoleService userRoleService;
private final FileService fileService;
private final FileStorageService fileStorageService;

@Override
public Long add(UserDO user) {
Expand Down Expand Up @@ -164,26 +159,20 @@ public void fillDetail(Object detailObj) {
@Override
@Transactional(rollbackFor = Exception.class)
public String uploadAvatar(MultipartFile avatarFile, Long id) {
LocalStorageProperties.LocalStorageMapping storageMapping = localStorageProperties.getMapping().get("AVATAR");
DataSize maxFileSize = storageMapping.getMaxFileSize();
CheckUtils.throwIf(avatarFile.getSize() > maxFileSize.toBytes(), "请上传小于 {}MB 的图片", maxFileSize.toMegabytes());
String avatarImageType = FileNameUtil.extName(avatarFile.getOriginalFilename());
String[] avatarSupportImgTypes = FileConstants.AVATAR_SUPPORTED_IMG_TYPES;
CheckUtils.throwIf(!StrUtil.equalsAnyIgnoreCase(avatarImageType, avatarSupportImgTypes), "头像仅支持 {} 格式的图片",
String.join(StringConstants.CHINESE_COMMA, avatarSupportImgTypes));
// 上传新头像
UserDO user = super.getById(id);
String avatarPath = storageMapping.getLocation();
File newAvatarFile = FileUploadUtils.upload(avatarFile, avatarPath, false);
CheckUtils.throwIfNull(newAvatarFile, "上传头像失败");
assert null != newAvatarFile;
FileInfo fileInfo = fileService.upload(avatarFile);
// 更新用户头像
String newAvatar = newAvatarFile.getName();
String newAvatar = fileInfo.getUrl();
baseMapper.lambdaUpdate().set(UserDO::getAvatar, newAvatar).eq(UserDO::getId, id).update();
// 删除原头像
String oldAvatar = user.getAvatar();
if (StrUtil.isNotBlank(oldAvatar)) {
FileUtil.del(avatarPath + oldAvatar);
fileStorageService.delete(oldAvatar);
}
return newAvatar;
}
Expand Down
3 changes: 1 addition & 2 deletions continew-admin-ui/src/components/navbar/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="navbar">
<div class="left-side">
<a-space>
<img alt="logo" :src="getFile(appStore.getLogo)" height="33" />
<img alt="logo" :src="appStore.getLogo" height="33" />
<a-typography-title
:style="{ margin: 0, fontSize: '18px' }"
:heading="5"
Expand Down Expand Up @@ -199,7 +199,6 @@
import useUser from '@/hooks/user';
import Menu from '@/components/menu/index.vue';
import getAvatar from '@/utils/avatar';
import getFile from '@/utils/file';
import { setTimer } from '@/utils/auth';
import MessageBox from '../message-box/index.vue';
Expand Down
8 changes: 0 additions & 8 deletions continew-admin-ui/src/utils/avatar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,6 @@ export default function getAvatar(
gender: number | undefined,
) {
if (avatar) {
const baseUrl = import.meta.env.VITE_API_BASE_URL;
if (
!avatar.startsWith('http:https://') &&
!avatar.startsWith('https://') &&
!avatar.startsWith('blob:')
) {
return `${baseUrl}/avatar/${avatar}`;
}
return avatar;
}

Expand Down
5 changes: 2 additions & 3 deletions continew-admin-ui/src/views/login/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
<div class="root">
<div class="header">
<img
:src="getFile(appStore.getLogo) ?? './logo.svg'"
alt="logo"
:src="appStore.getLogo ?? './logo.svg'"
alt="Logo"
height="33"
/>
<div class="logo-text">{{ appStore.getTitle }}</div>
Expand Down Expand Up @@ -78,7 +78,6 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useAppStore } from '@/store';
import getFile from '@/utils/file';
import useResponsive from '@/hooks/responsive';
import { socialAuth } from '@/api/auth';
import AccountLogin from './components/account-login.vue';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
v-if="faviconFile && faviconFile.url"
class="arco-upload-list-picture custom-upload-avatar favicon"
>
<img :src="getFile(faviconFile.url)" />
<img :src="faviconFile.url" alt="favicon" />
<div
v-if="isEdit"
class="arco-upload-list-picture-mask favicon"
Expand Down Expand Up @@ -77,7 +77,7 @@
v-if="logoFile && logoFile.url"
class="arco-upload-list-picture custom-upload-avatar logo"
>
<img :src="getFile(logoFile.url)" />
<img :src="logoFile.url" alt="Logo" />
<div
v-if="isEdit"
class="arco-upload-list-picture-mask logo"
Expand Down Expand Up @@ -181,7 +181,6 @@
resetValue,
} from '@/api/system/config';
import { upload } from '@/api/common';
import getFile from '@/utils/file';
import { useAppStore } from '@/store';

const { proxy } = getCurrentInstance() as any;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import top.charles7c.continew.starter.core.util.validate.CheckUtils;
import top.charles7c.continew.starter.core.util.validate.ValidationUtils;
import top.charles7c.continew.starter.extension.crud.model.resp.R;
import top.charles7c.continew.starter.log.common.annotation.Log;
import top.charles7c.continew.starter.messaging.mail.util.MailUtils;

/**
Expand All @@ -84,19 +85,22 @@ public class CaptchaController {
private final ProjectProperties projectProperties;
private final GraphicCaptchaProperties graphicCaptchaProperties;

@Log(ignore = true)
@Operation(summary = "获取行为验证码", description = "获取行为验证码(Base64编码)")
@GetMapping("/behavior")
public R<Object> getBehaviorCaptcha(CaptchaVO captchaReq, HttpServletRequest request) {
captchaReq.setBrowserInfo(JakartaServletUtil.getClientIP(request) + request.getHeader(HttpHeaders.USER_AGENT));
return R.ok(captchaService.get(captchaReq).getRepData());
}

@Log(ignore = true)
@Operation(summary = "校验行为验证码", description = "校验行为验证码")
@PostMapping("/behavior")
public R<Object> checkBehaviorCaptcha(@RequestBody CaptchaVO captchaReq) {
return R.ok(captchaService.check(captchaReq));
}

@Log(ignore = true)
@Operation(summary = "获取图片验证码", description = "获取图片验证码(Base64编码,带图片格式:data:image/gif;base64)")
@GetMapping("/img")
public R<CaptchaResp> getImageCaptcha() {
Expand Down
Loading

0 comments on commit 5e37025

Please sign in to comment.